我正計劃圍繞數值模擬編寫一個小GUI,這就是爲什麼我現在正在玩弄Tkinter。模擬應該在獨立進程中從GUI啓動。爲了玩一下,我定義了一個函數random_process,它生成一對randn數字(這應該是一個真正的模擬過程)。由於該函數旨在在單獨的進程中啓動,因此將兩個mp.Event對象和一個mp.Pipe對象作爲參數傳遞。 主應用程序可以使用一個事件來請求過程中的累積數據,另一個事件被用作「毒丸」來殺死「模擬」過程。然後使用管道傳遞數據。 在主應用程序中,我使用Tkinter的函數後定期檢查新數據是否已到達,然後繪製它。啓動和停止「模擬過程」是通過主應用程序中的按鈕完成的,從數據中請求數據也是如此。Tkinter:通過多處理啓動過程創建了不想要的新窗口
至少這是這個想法,在實踐中,該程序不會很好。當我點擊「去!」按鈕是爲了啓動仿真過程,第二個Tkinter窗口出現,與主窗口相同。我絲毫不知道爲什麼會發生這種情況。與流程的溝通也不起作用,似乎沒有數據發送。當搜索一個解決方案時,我發現了一個Tkinter程序的工作示例,啓動過程並與他們交談,但我沒有發現是什麼讓我無法正常工作。有人有線索嗎?
順便說一下,OS是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()
請注意,從'object'繼承你的類。在Python 2.x中不要只做「class name:」 – jsbueno