【问题标题】:accessing threads continually in tkinter loop在 tkinter 循环中不断访问线程
【发布时间】:2013-01-22 22:37:54
【问题描述】:

我正在尝试制作一个不断绘制从微处理器接收到的信号的 GUI。我试图通过仅使用类来实现这一点,但是由于只有 GUI 类是开放的,所以失败了。现在我已经实现了线程(或者至少我认为我有!?)但是每个线程只运行一次。这让我相信我不明白 tkinter 中的 mainloop 是如何工作的,所以我可以重新制作我的代码以使线程变得活跃吗?

import Tkinter
import tkMessageBox as messagebox
from serial import *
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np
import time
import threading

go=0

x=[0.0001,0.0002,0.0003]
y=[3600,1000,2000]
stid=time.time()

root = Tkinter.Tk()
root.title("Serial gui")

class SensorThread(threading.Thread):
    def run(self):
        global run
        global x
        global y
        global stid
        print "run er ok"
        if go==1:
            print "go er ok"
            ser = Serial(5, 9600, timeout=1)
            f=ser.read(4)
            ser.close()
            x.append(time.time()-stid)
            y.append(f)


class Foo:
    def __init__(self, master):
        print "foo ok"

        frame = Tkinter.Frame(root)

        self.button_left = Tkinter.Button(frame,text="Start",
                                command=self.start)
        self.button_left.pack(side="left")

        self.button_right = Tkinter.Button(frame,text="Stop",
                                command=self.stop)
        self.button_right.pack(side="right")

        self.button_midt = Tkinter.Button(frame, text='Quit', command=self.terminate)
        self.button_midt.pack(side="bottom")

        fig = Figure()
        ax = fig.add_subplot(111, axisbg='black')

        canvas = FigureCanvasTkAgg(fig,master=master)
        canvas.show()
        canvas.get_tk_widget().pack(side='top', fill='both', expand=1)
        frame.pack()

        line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma
        line1.set_ydata(y)
        fig.canvas.draw()


    def start(self):
        global go
        go=1
        print go

    def stop(self):
        global go
        go=0
        print go

    def terminate(self):
        root.quit()     # stops mainloop
        root.destroy()  # this is necessary on Windows to prevent
                        # Fatal Python Error: PyEval_RestoreThread: NULL tstate

if __name__ == "__main__":
    SensorThread().run()
    Foo(root)
    root.mainloop() 

我希望你们中的一些人可以帮助我把这段代码变成一个实时更新情节的程序。

超级我在程序里改了以下,

class SensorThread(threading.Thread):
def run(self):
    global run
    global x
    global y
    global stid
    #print "run er ok"
    if go==1:
        print "go er ok"
        ser = Serial(17, 9600, timeout=1)
        f=ser.read(4)
        ser.close()
        x.append(time.time()-stid)
        y.append(f)
        SensorThread().start()
    else:
        SensorThread().start()

class Foo:
....

if __name__ == "__main__":
SensorThread().start()
Foo(root)
root.mainloop() 

但它仍然没有更新 plottet 的图形,它不应该在 Foo 类中执行此操作吗?现在,当我退出或完全退出 python 脚本时,它仍然使用 50% 的 CPU 功率,可能是因为传感器线程现在永远运行!?

【问题讨论】:

  • 您误用了threading 模块;你不应该打电话给.run(),而是.start()。请参阅docs.python.org/2/library/threading.html 了解更多信息。
  • 谢谢mmgp 我已经尝试实现我编辑过的东西,但我的图保持初始化状态。但我仍然有一些问题可以在我编辑的问题中看到。
  • 现在你在run 方法中也调用了start:/ 这里有一些误解。例如,您在__init__ 中只调用一次plot;为什么仅仅因为您更改了列表/之后/情节已经执行,并且再也没有更新过,您为什么期望情节会自动更新?
  • 如果您可以在几百毫秒内读取传感器,那么线程是完全没有必要的,并且会增加不必要的复杂性。在 stackoverflow 中搜索与使用 after 相关的无数问题。

标签: tkinter serial-port updating


【解决方案1】:

【讨论】:

  • 这真的不相关,这里的另一个线程没有与 Tk GUI 元素交互。 sys.exit(1) 真的不需要,只需为其他创建的线程设置 daemon = True 即可。这是一个使用队列在线程之间进行通信的简化答案(它只是更长,因为它有一堆用于执行其他操作的其他代码):stackoverflow.com/questions/14379106/…。如果一切都是用线程构建的,也可以使用event_generate 并为这一特定任务使用队列无效。
  • 这可能有点扭曲,但对我来说是一个起点。当然,您必须在 GuiPart.processIncoming 中添加实际工作部分,示例中有“print msg”。 "thread1.daemon = True" 确实是一个很好的提示。
  • 我并不是说它应该包含实际工作部分的代码。我的意思是那里显示的代码,就像你说的那样,“扭曲”,而另一个链接的答案更直接,并提供相同的通信方法。此外,为了强调,目前的问题与这些刚刚链接的答案所提供的内容无关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-26
  • 1970-01-01
  • 2022-07-07
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
  • 2013-12-04
相关资源
最近更新 更多