gpt4 book ai didi

Python:如何在保持 GUI 交互性的同时使用来自单独进程的变量更新 GUI

转载 作者:太空宇宙 更新时间:2023-11-04 03:43:38 28 4
gpt4 key购买 nike

在这里阅读了很多关于多进程、管道等的内容后,我还没有找到答案,但如果它已经存在,我深表歉意。

我有一个外围硬件,我正在尝试为其创建一个 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()

最佳答案

您非常接近可行的解决方案。正如上面的评论之一所述,使用 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()

更新

响应更新后的代码:您已经完成了很多工作,唯一的问题是您只调用了条形图创建器一次,而它需要添加到您的 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 时,图形也会相应地更新。

关于Python:如何在保持 GUI 交互性的同时使用来自单独进程的变量更新 GUI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24945357/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com