Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Tkinter:对每秒发生的事件进行多处理_Python_Tkinter_Modbus_Minimalmodbus - Fatal编程技术网

Python Tkinter:对每秒发生的事件进行多处理

Python Tkinter:对每秒发生的事件进行多处理,python,tkinter,modbus,minimalmodbus,Python,Tkinter,Modbus,Minimalmodbus,我制作了一个Tkinter程序,从modbus从设备读取数据。它每秒读取设备并将输出显示在标签上。但是,我有多个选项卡,它们为每个连接的设备运行相同的代码。当一个设备被读取时,整个GUI会冻结,因此在读取完成之前,您无法移动程序或按下按钮。多重处理有助于冷冻吗?如果是,我该如何实施 这是我的密码: import tkinter as tk from tkinter import * from tkinter import ttk from time import time import mini

我制作了一个Tkinter程序,从modbus从设备读取数据。它每秒读取设备并将输出显示在标签上。但是,我有多个选项卡,它们为每个连接的设备运行相同的代码。当一个设备被读取时,整个GUI会冻结,因此在读取完成之前,您无法移动程序或按下按钮。多重处理有助于冷冻吗?如果是,我该如何实施

这是我的密码:

import tkinter as tk
from tkinter import *
from tkinter import ttk
from time import time
import minimalmodbus
import serial
minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL = True

class Page(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
    def show(self):
        self.lift()

class Page1(Page):
    def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)

       self.gas = minimalmodbus.Instrument('COM3', 1)
       self.gas.serial.baudrate = 9600
       self.gas.serial.bytesize = 8
       self.gas.serial.parity = serial.PARITY_NONE
       self.gas.serial.stopbits = 1
       self.gas.serial.timeout = 0.25
       self.gas.mode = minimalmodbus.MODE_RTU

       self.value_display = tk.Label(self, text='value', width=10)
       self.value_display.pack(side="top")

       self.unit_display = tk.Label(self, text='unit', width=10)
       self.unit_display.pack(side="top")

       self.gas_display = tk.Label(self, text='temp', width=10)
       self.gas_display.pack(side="top")

       self.status_display = tk.Label(self, text='status', width=10)
       self.status_display.pack(side="top")

       self.command_display = tk.Label(self, text='command', width=10)
       self.command_display.pack(side="top")

       self.pressure_display = tk.Label(self, text='pressure', width=10)
       self.pressure_display.pack(side="top")

       self.timer_button = tk.Button(self, text='Start', command=self.toggle)
       self.timer_display = tk.Label(self, text='00:00', width=10)
       self.timer_button.pack(side="top")
       self.timer_display.pack(side="top")
       self.paused = True

    def gas_meth(self):
        try:
            gas_value = self.gas.read_registers(0,42)

            self.value_display.config(text=gas_value[0])
            self.unit_display.config(text=gas_value[1])
            self.gas_display.config(text=gas_value[2])
            self.status_display.config(text=gas_value[3])
            self.command_display.config(text=gas_value[4])
            self.pressure_display.config(text=gas_value[5])

        except IOError:
            self.gas_display.config(text="Lost con.")
        except ValueError:
            self.gas_display.config(text="RTU error")
        self.gas_display.after(1000, self.gas_meth)

    def toggle(self):
        if self.paused:
            self.paused = False
            self.timer_button.config(text='Stop')
            self.oldtime = time()
            self.run_timer()
            self.gas_meth()
        else:
            self.paused = True
            self.oldtime = time()
            self.timer_button.config(text='Start')

    def run_timer(self):
        if self.paused:
            return
        delta = int(time() - self.oldtime)
        timestr = '{:02}:{:02}'.format(*divmod(delta, 60))
        self.timer_display.config(text=timestr)
        self.timer_display.after(500, self.run_timer)

class MainView(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        p1 = Page1(self)

        buttonframe = tk.Frame(self)
        container = tk.Frame(self)
        buttonframe.pack(side="top", fill="x", expand=False)
        container.pack(side="top", fill="both", expand=True)

        p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        b1 = tk.Button(buttonframe, text="Page 1", command=p1.lift)
        b1.pack(side="left")
        p1.show()

if __name__ == "__main__":
    root = tk.Tk()
    main = MainView(root)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("1000x600")
    root.mainloop()

一般的想法是将从传感器读取的代码放在一个线程中,并让该代码通过队列与GUI线程通信

这里有一个真正快速的技巧来演示这项技术:

import tkinter as tk
import threading
import queue
import random
import time

class Example(object):
    def __init__(self):
        self.root = tk.Tk()
        self.sensor_vars = []

        self.root.grid_columnconfigure(1, weight=1)
        for row, i in enumerate(range(3)):
            var = tk.StringVar()
            self.sensor_vars.append(var)
            label = tk.Label(self.root, text="Sensor %d:" % i)
            value = tk.Label(self.root, textvariable=var, width=4)
            label.grid(row=row, column=0, sticky="e")
            value.grid(row=row, column=1, sticky="w")

        # create a queue for communication
        self.queue = queue.Queue()

        # create some sensors
        self.sensors = []
        for i in range(3):
            sensor = Sensor(self.queue, i)
            self.sensors.append(sensor)
            sensor.setName("Sensor %d" % i)

        # start polling the queue
        self.poll_queue()

    def start(self):
        # start the sensors
        for sensor in self.sensors:
            sensor.start()

        # start the GUI loop
        self.root.mainloop()

        # wait for the threads to finish
        for sensor in self.sensors:
            sensor.stop()
            sensor.join()

    def poll_queue(self):
        if not self.queue.empty():
            message = self.queue.get()
            index = message["index"]
            self.sensor_vars[index].set(message["value"])

        self.root.after(100, self.poll_queue)

class Sensor(threading.Thread):
    def __init__(self, queue, index):
        threading.Thread.__init__(self)
        self.queue = queue
        self.index = index
        self.stop_requested = False

    def stop(self):
        self.stop_requested = True

    def run(self):
        for i in range(10):
            if self.stop_requested:
                break
            value = random.randint(10, 100)
            self.queue.put({"index": self.index, "value": value})
            time.sleep(1)



if __name__ == "__main__":
    app = Example()
    app.start()

哇,回答得太好了。我还得多读一些关于多重处理的书,但我明白你在回答中的意思。多重处理会减少程序的开销吗?@Evan:多重处理会增加开销。不多,但有一点。我遇到的问题是,每次传感器读取时,我的程序都会冻结一小部分秒。如果每秒读取6个传感器的数据超过半秒,我的程序将被冻结。多处理会有帮助吗?@Evan:是的,多处理会有帮助,就像我例子中的线程一样。在我的示例中,模拟传感器的代码将休眠一秒钟,并且不会导致程序挂起。