Tkinter:分离过程

2024-06-02 12:56:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试构建一个支持多处理的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在进程运行的同时运行?在


Tags: textfromimportselfreaddefserialgui
1条回答
网友
1楼 · 发布于 2024-06-02 12:56:42

最简单的解决方案是把这些都放在一个单独的线程上。GUI冻结的原因是process方法已经占用了主线程,在它完成之前,Tkinter不会更新任何内容。在

下面是一个简单的例子:

self.timer_button = tk.Button(self, text='Start', command=lambda: threading.Thread(target=self.process).start())

但是,这并不能阻止用户单击按钮两次。你可以创建一个新的方法来控制它。示例:

^{pr2}$

Lock是为了确保没有两个线程同时运行。我还禁用了该按钮,这样用户在完成之前无法单击。通过使用root.after方法,可以创建在运行之前等待一段时间的回调。在

就多处理而言,您是在一个单独的进程上运行这些进程,但一次只能运行一个进程。如果您希望一次运行多个,则需要将join调用移到其他地方。我不知道一次有多少进程在运行,但您可以这样做:

processes = []
for sen in self.gas_list:
    proc = Process(target=self.reader, args=(sen,))
    processes.append(proc)
    proc.start()
[x.join() for x in processes]

在这个实现中,我删除了将proc作为类变量的赋值。在

我没有库或数据来正确测试所有这些,但它应该工作。。。在

编辑

这将启动一个由6个进程组成的池,循环通过self.gas_list,并将该项传递给self.reader。当这些操作完成后,它将检查以确保已经过了一秒钟(如果没有,则等待),然后重新启动上述进程。这将永远运行或直到引发异常。您需要从多处理模块导入Pool。在

def process(self):
    with THREAD_LOCK:
        pool = Pool(6)
        while 1:
            start_time = time.time()
            pool.map(self.reader, self.gas_list)
            execution_time = time.time() - start_time
            if execution_time < 1:
                time.sleep(1-execution_time)

相关问题 更多 >