我正在尝试构建一个支持多处理的Tkinter程序。我需要从多个Modbus设备读取并在GUI上显示输出。在
我已经通过使用进程成功地用命令行完成了这项工作,但是在Tkinter中,每当我试图读取时,我的GUI就会冻结。在
这是我的代码:
import os
from multiprocessing import Process
import threading
import queue
import tkinter as tk
from tkinter import *
from tkinter import ttk
import time
import time as ttt
import minimalmodbus
import serial
minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL = True
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.gas = minimalmodbus.Instrument('COM3', 1)
self.gas.serial.baudrate = 9600
self.gas.serial.parity = serial.PARITY_NONE
self.gas.serial.bytesize = 8
self.gas.serial.stopbits = 1
self.gas.serial.timeout = 0.25
self.gas.mode = minimalmodbus.MODE_RTU
self.pack()
self.create_widgets()
def create_widgets(self):
self.first_gas_labelframe = LabelFrame(self, text="Gas 1", width=100)
self.first_gas_labelframe.pack()
self.value_label = Label(self.first_gas_labelframe, text="Value")
self.value_label.pack()
self.unit_label = Label(self.first_gas_labelframe, text="Unit")
self.unit_label.pack()
self.temp_label = Label(self.first_gas_labelframe, text="Temp")
self.temp_label.pack()
self.timer_button = tk.Button(self, text='Start', command=self.process)
self.quit = tk.Button(self, text="QUIT", fg="red", command=root.destroy)
self.quit.pack()
self.gas_list = [self.gas]
def reader():
self.read = gas_num.read_registers(0,42)
self.value_label.config(text=self.read[0])
self.unit_label.config(text=self.read[1])
self.temp_label.config(text=self.read[2])
def process(self):
for sen in self.gas_list:
self.proc = Process(target=self.reader, args=(sen,))
self.proc.start()
self.proc.join()
if __name__ == '__main__':
root = tk.Tk()
app = Application()
app.mainloop()
当我按下开始按钮,程序将冻结,直到过程完成。如何正确地设置一个系统,使GUI在进程运行的同时运行?在
最简单的解决方案是把这些都放在一个单独的线程上。GUI冻结的原因是
process
方法已经占用了主线程,在它完成之前,Tkinter不会更新任何内容。在下面是一个简单的例子:
但是,这并不能阻止用户单击按钮两次。你可以创建一个新的方法来控制它。示例:
^{pr2}$Lock
是为了确保没有两个线程同时运行。我还禁用了该按钮,这样用户在完成之前无法单击。通过使用root.after
方法,可以创建在运行之前等待一段时间的回调。在就多处理而言,您是在一个单独的进程上运行这些进程,但一次只能运行一个进程。如果您希望一次运行多个,则需要将
join
调用移到其他地方。我不知道一次有多少进程在运行,但您可以这样做:在这个实现中,我删除了将
proc
作为类变量的赋值。在我没有库或数据来正确测试所有这些,但它应该工作。。。在
编辑
这将启动一个由6个进程组成的池,循环通过
self.gas_list
,并将该项传递给self.reader
。当这些操作完成后,它将检查以确保已经过了一秒钟(如果没有,则等待),然后重新启动上述进程。这将永远运行或直到引发异常。您需要从多处理模块导入Pool
。在相关问题 更多 >
编程相关推荐