4

我打算围绕数值模拟编写一个小型 GUI,这就是我现在使用 Tkinter 的原因。模拟应该在单独的过程中从 GUI 启动。为了稍微玩一下,我定义了一个函数 random_process 来生成一对 randn 数(这应该稍后是一个真正的模拟过程)。由于该函数打算在单独的进程中启动,因此将两个 mp.Event 对象和一个 mp.Pipe 对象作为参数传递。主应用程序可以使用一个事件向进程请求累积数据,另一个事件用作“毒丸”杀死“模拟”进程。然后使用管道传递数据。在主应用程序中,我使用 Tkinter 的后功能定期检查是否有新数据到达,然后绘制它。启动和停止“模拟过程”

至少这是想法,在实践中该程序并不能很好地发挥作用。当我点击“开始!” 用于启动模拟过程的按钮,将出现第二个 Tkinter 窗口,与主窗口相同。我一点也不知道为什么会这样。与进程的通信也不起作用,似乎没有发送数据。在谷歌搜索解决方案时,我发现了一个 Tkinter 程序启动进程并与它们交谈的工作示例,但我没有发现是什么导致它在我的情况下不起作用。有人有线索吗?

顺便说一句,操作系统是 Windows-7。

干杯,简

import matplotlib
matplotlib.use('TkAgg')
import time
import multiprocessing as mp
import Tkinter as Tk
import numpy.random as npr
import matplotlib.figure
import matplotlib.backends.backend_tkagg as tkagg

def random_process(delay, data_request, data_in, poison):
    while not poison.is_set():
        time.sleep(delay)
        print("Generating pair of random numbers...")
        x,y = npr.randn(), npr.randn()
        try:
            random_process.l.append((x,y))
        except:
            random_process.l = [(x,y)]
        if data_request.is_set():
            data_request.clear()
            try:
                ll = len(random_process.l)
                if ll > 0:
                    print("Sending %d pairs to main program.." % ll)
                    data_in.send(random_process.l)
                random_process.l = []
            except:
                print("data requested, but none there.")
    # when poison event is set, clear it:
    poison.clear()

class GuiInterfaceApp:
    def __init__(self, parent):
        self.myParent = parent

        self.previewplot_container = Tk.Frame(self.myParent)
        self.f = matplotlib.figure.Figure()
        self.ax = self.f.add_subplot(111)
        self.preview_canvas = tkagg.FigureCanvasTkAgg(self.f, master=self.previewplot_container)
        self.preview_canvas.show()

        self.button_container = Tk.Frame(self.myParent)
        self.hellobutton = Tk.Button(self.button_container, text="hello!")
        self.hellobutton.config(command = self.printhello)
        self.startbutton = Tk.Button(self.button_container, text="go!")
        self.startbutton.config(command=self.run_simulation)
        self.plotbutton = Tk.Button(self.button_container, text="show!")
        self.plotbutton.config(command=self.request_data)
        self.stopbutton = Tk.Button(self.button_container, text="stop.")
        self.stopbutton.config(command=self.stop_simulation)
        self.quitbutton = Tk.Button(self.button_container, text="get me outta here!")
        self.quitbutton.config(command=self.quit_program)

        self.previewplot_container.pack(side = Tk.TOP)
        self.preview_canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
        self.button_container.pack(side = Tk.BOTTOM)
        self.hellobutton.pack(side = Tk.LEFT)
        self.startbutton.pack(side = Tk.LEFT)
        self.plotbutton.pack(side = Tk.LEFT)
        self.stopbutton.pack(side = Tk.LEFT)
        self.quitbutton.pack(side = Tk.LEFT)

        self.simulation_running = False

        self.datarequest = mp.Event()
        self.DataIn, self.DataOut = mp.Pipe()
        self.PoisonEvent = mp.Event()
        self.p = mp.Process(target = random_process, args=(1.0, self.datarequest,     self.DataIn, self.PoisonEvent))

        self.l = [] # list of received pairs to plot

        self.mytask_time = 100 # delay in ms between calls to self.mytask

    def printhello(self):
        print("hello!")

    def run_simulation(self):
        print("startbutton pressed.")
        if not self.simulation_running:
            print("starting simulation...")
            self.p.start()
            self.simulation_running = True  # attention: no error checking

    def stop_simulation(self):
        print("stop button pressed.")
        if self.simulation_running:
            print("Sending poison pill to simulation process..")
            self.PoisonEvent.set()
            self.simulation_running = False
            # todo: wait a short amount of time and check if simu stopped.

    def request_data(self):
        print("plotbutton pressed.")
        if self.simulation_running:
            print("requesting data from simulation process")
            self.datarequest.set()

    def update_plot(self):
        print("update_plot called.")
        if len(self.l) > 0:
            print("there is data to plot.")
            while len(self.l) > 0:
                x,y = self.l.pop()
                print("plotting point (%.2f, %.2f)" % (x,y))
                self.ax.plot([x], [y], '.', color='blue')
            print("drawing the hole thing..")
            self.ax.draw()
        else:
            print("nothing to draw")

    def quit_program(self):
        print("quitbutton pressed.")
        if self.simulation_running:
            print("sending poison pill to simulation process..")
            self.PoisonEvent.set()
        print("quitting mainloop..")
        self.myParent.quit()
        print("destroying root window..")
        self.myParent.destroy()

    def receive_data(self):
        if self.DataOut.poll():
            print("receiving data..")
            data =  self.DataOut.recv()
            self.l.append(data)
            self.update_plot()

    def my_tasks(self):
        self.receive_data()
        self.myParent.after(self.mytask_time, self.my_tasks)
        return

root = Tk.Tk()
myGuiInterfaceApp = GuiInterfaceApp(root)
root.after(100, myGuiInterfaceApp.my_tasks)
root.mainloop()
4

1 回答 1

5

尝试将您的主要逻辑隐藏在代码是否正在运行或导入的测试中。

if __name__ == "__main__":
    root = Tk.Tk()
    ...
于 2012-09-06T12:42:55.990 回答