在这里读了很多关于多个流程,管道等的内容之后,我还没有找到答案,但是如果它已经存在我会道歉。
我有一块外围硬件,我试图创建一个GUI。我希望GUI能够不断更新来自外围设备的数据,同时仍然保持用户的交互性。例如,我有一个我用来驱动条形图的增益参数,虽然这个参数不断更新,但我希望用户能够点击一个按钮来执行某些操作。这是一些示例代码。尽管我确信这里有一些严重的错误,但这实际上几乎可以解决,但是“退出”了。按钮仍无响应:
#!/usr/bin/env python`
# -*- coding: utf-8 -*-
# 2014-07-24 S. Petit
import matplotlib.pyplot as plt
from serial import Serial
import serial, socket, time, datetime, sys, struct
from datetime import datetime
import numpy as np
import shutil
import os
from random import randint
from Tkinter import *
from multiprocessing import *
dcbSerialPort = 'COM10'
def getGainLNA(pipeToParent):
try:
S_dcb = Serial(dcbSerialPort, 115200, timeout=.1)
print 'Opened DCB at', dcbSerialPort
except:
print '\r\n'
print '*************************************************'
print 'ERROR: Unable to open', dcbSerialPort, 'serial connection.'
print '*************************************************'
print '\r\n'
raw_input()
exit()
while True:
promptFound = False
PICreturn = ''
S_dcb.write('gain\r')
while not promptFound:
PICreturn += S_dcb.read(S_dcb.inWaiting())
if 'DCB>' in PICreturn:
promptFound = True
gainLNA = float(PICreturn[20:28].strip())
gainLNA_scaled = int(100*(gainLNA/33))
pipeToParent.send(gainLNA_scaled)
return()
if __name__ == '__main__':
gainUpdaterPipe, gainUpdaterPipeChild = Pipe()
lnaGainUpdater = Process(target=getGainLNA, args=(gainUpdaterPipeChild,))
lnaGainUpdater.start()
root=Tk()
root.title = 'AGC'
while True:
if gainUpdaterPipe.poll():
gainLNA = gainUpdaterPipe.recv()
print gainLNA
quitButton = Button(text='Quit', command=quit)
quitButton.grid(row=1, column=0)
areaAGC = Canvas(width=120, height=100, bg='blue')
objectAGC = areaAGC.create_polygon(20,20, gainLNA,20, gainLNA,50, 20,50, outline='green', fill='yellow')
areaAGC.grid(row=0, column=0)
root.update_idletasks()
感谢您的帮助...... 史蒂夫P
编辑:好的,在尝试使用@ ebarr的例子之后,这就是我所拥有的。标签小部件随计数更新,但条形图不会:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 2014-07-24 S. Petit
import matplotlib.pyplot as plt
from serial import Serial
import serial, socket, time, datetime, sys, struct
from datetime import datetime
import numpy as np
import shutil
import os
from random import randint
import Tkinter as tk
from multiprocessing import *
dcbSerialPort = 'COM10'
# count from 0 to infinity, writing the value to a pipe
def count(pipe,stop):
ii = 0
while not stop.is_set():
ii+=1
pipe.send(ii)
time.sleep(1)
class UpdatingGUI(tk.Frame):
def __init__(self,parent):
tk.Frame.__init__(self,parent)
self.parent = parent
self.parent_pipe, self.child_pipe = Pipe()
self.stop_event = Event()
# label to show count value
self.updating_int = tk.IntVar()
self.updating_int.set(0)
self.updating_lbl = tk.Label(self,textvariable=self.updating_int)
self.updating_lbl.pack()
# bargraph to show count value
self.area_barGraph = tk.Canvas(width=120, height=100, bg='blue')
self.bargraph = self.area_barGraph.create_polygon(10,10, (10+self.updating_int.get()),10, (10+self.updating_int.get()),20, 10,20, outline='green', fill='yellow')
self.area_barGraph.pack()
# button that will stay responsive to requests while count is on going
self.quit_btn = tk.Button(self,text="Quit",command=self.quit)
self.quit_btn.pack()
# launch count as a process
self.counter = Process(target=count,args=(self.child_pipe,self.stop_event))
self.counter.start()
# call an update method to check the pipe and update the label
self.update()
def quit(self):
self.stop_event.set()
self.parent.destroy()
def update(self):
# While the pipe has data, read and update the StringVar
while self.parent_pipe.poll():
self.updating_int.set(self.parent_pipe.recv())
# set the update method to run again in 1 seconds time
self.parent.after(1000,self.update)
def main():
root = tk.Tk()
gui = UpdatingGUI(root)
gui.pack()
root.mainloop()
# print __name__
if __name__ == "__main__":
main()
答案 0 :(得分:2)
你非常接近一个有效的解决方案。正如上面其中一条评论中所述,使用tkinter after
将解决您的大部分问题。
下面是一个单独进程(运行一个简单的计数器)的最小示例,它传递了一个可用于更新GUI的状态:
import Tkinter as tk
from multiprocessing import Event,Process,Pipe
from time import sleep
# count from 0 to infinity, writing the value to a pipe
def count(pipe,stop):
ii = 0
while not stop.is_set():
ii+=1
pipe.send(ii)
sleep(1)
class UpdatingGUI(tk.Frame):
def __init__(self,parent):
tk.Frame.__init__(self,parent)
self.parent = parent
self.parent_pipe, self.child_pipe = Pipe()
self.stop_event = Event()
# label to show count value
self.updating_txt = tk.StringVar()
self.updating_txt.set("Waiting...")
self.updating_lbl = tk.Label(self,textvariable=self.updating_txt)
self.updating_lbl.pack()
# button that will stay responsive to requests while count is on going
self.quit_btn = tk.Button(self,text="Quit",command=self.quit)
self.quit_btn.pack()
# launch count as a process
self.counter = Process(target=count,args=(self.child_pipe,self.stop_event))
self.counter.start()
# call an update method to check the pipe and update the label
self.update()
def quit(self):
self.stop_event.set()
self.parent.destroy()
def update(self):
# While the pipe has data, read and update the StringVar
while self.parent_pipe.poll():
self.updating_txt.set(self.parent_pipe.recv())
# set the update method to run again in 1 seconds time
self.parent.after(1000,self.update)
def main():
root = tk.Tk()
gui = UpdatingGUI(root)
gui.pack()
root.mainloop()
if __name__ == "__main__":
main()
<强>更新强>
响应更新后的代码:您已经完成了,唯一的问题是您只需要调用bargraph创建器一次,而需要将其添加到update
函数中,如:
def update(self):
# While the pipe has data, read and update the StringVar
while self.parent_pipe.poll():
self.updating_int.set(self.parent_pipe.recv())
dx = self.updating_int.get()
self.area_barGraph.create_polygon(10,10, (10+dx),10, (10+dx),20, 10,20, outline='green', fill='yellow')
# set the update method to run again in 1 seconds time
self.parent.after(1000,self.update)
这将确保每次更新intVar时,图表也会相应更新。