Tkinter:通过多处理启动进程创建了不想要的新窗口

时间:2012-09-06 10:20:08

标签: python matplotlib tkinter multiprocessing

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

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

BTW,操作系统是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()

1 个答案:

答案 0 :(得分:3)

尝试将主要逻辑隐藏在测试后面,以确定代码是在运行还是导入。

if __name__ == "__main__":
    root = Tk.Tk()
    ...