2017-06-14 9 views
0

私はModbusスレーブデバイスから読み込むTkinterプログラムを作成しました。毎秒デバイスを読み取り、出力をラベルに表示します。しかし、私は、接続された各デバイスに対して同じコードを実行する複数のタブを持っています。デバイスが読み込まれている間は、GUI全体がフリーズし、プログラムの移動やボタンの押下が完了するまで実行できません。マルチプロセッシングはフリーズに役立つでしょうか?もしそうなら、私はそれをどのように実装できますか?ここでTkinter:毎秒発生するイベントでのマルチプロセッシング

が私のコードです:

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() 

答えて

1

一般的な考え方は、スレッド内のセンサから読み取ったコードを置くことで、コードはキューを経由して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() 
+0

うわー、素晴らしい答え:

は、ここで技術を実証するための本当の迅速なハックです。私は、マルチプロセッシングに関するいくつかの読書をしなければならないでしょうが、私はあなたの答えに何を意味するのかを見ています。マルチプロセッシングはプログラムのオーバーヘッドを削減しますか? – GreenSaber

+0

@Evan:マルチプロセッシング_adds_オーバーヘッド。それほど多くはありませんが、少しです。 –

+0

私が抱えている問題は、センサーが読み取るたびに、私のプログラムが数分の1秒間フリーズすることです。 1秒間に6個のセンサーが毎秒読み取る場合、私のプログラムはフリーズされます。マルチプロセッシングはそれを助けますか? – GreenSaber

関連する問題