【问题标题】:Python TKinter Threading Help Required需要 Python TKinter 线程帮助
【发布时间】:2012-08-27 19:01:38
【问题描述】:

我正在尝试创建一个与 RS232 串行对象通信的 GUI。我将针对我面临的问题提出一个类似的场景。我想创建一个带有 2 个按钮的框架,开始和停止。开始按钮调用'foo'函数:

status = True

def foo():
   n = 0
   while(getStatus()):
       print n
       n += 1
       sleep(0)

这个 foo 函数一直运行,直到我按下停止。

def getStatus():
   return status

def stop():
   status = False

我知道 Tkinter 是单线程的,一旦我按下“开始”,GUI 就会冻结。我知道 after 函数可以做到这一点,但我非常想使用 threading。这可能与线程?如果可以,请您提供示例代码吗?谢谢你。

【问题讨论】:

  • 我不太明白您的问题,只需启动一个线程 (thread.threading) 并让它检查状态。通过锁/信号量保护状态,你会没事的。我不知道python中的原子集是否适用于您的情况。因为您不想更新 gui,所以从控制台启动线程没有区别。
  • @ted:我不确定这意味着什么。我对 GUI 编码很陌生。如果不是示例代码,您能否指出一些有用的链接/文档?
  • 如果我有时间的话,我今晚会尝试把一些东西放在一起,如果在那之前没有人做。抱歉我不能早点做,不过我得看看它,因为我还没有用 python 做太多线程
  • 谢谢。我真的很感激。

标签: python multithreading user-interface tkinter


【解决方案1】:

这里有一些(还不完善的)代码:

什么是丢失/损坏,但你没有要求这个,我添加了链接:

  • 它不使用锁 => 调用 set 可能会停止,因为它们可以同时发生。 read the docs(这很简单)
  • 它从另一个线程更新 gui。见12
  • 可能更多(不是线程专家)

也用于停止线程查看here

import time
import tkinter
from tkinter import ttk
import threading  

#gui
root = tkinter.Tk()
root.title("Threading demo")

status = tkinter.StringVar()
elapsed = tkinter.StringVar()
error = tkinter.StringVar()

#thread
class timer(threading.Thread):
    def __init__(self):
        super().__init__()
        self.stopped = False
        #your code here, don't need init if you have no code



    def run(self):
        status.set('running')

        while not self.isStopped():
            time.sleep(1)

            try:
                oldtime = int(elapsed.get())
            except ValueError:
                oldtime = 0

            elapsed.set(oldtime+1)

        status.set('stopped')
        time.sleep(2)

    def isStopped(self):
        return self.stopped



    def stop(self):
        self.stopped = True



#starts/stops thread (manages it)
class threadedOp(object):
    def __init__(self):
        self.thread = None


    def run(self):
        if self.thread == None:
            self.thread = timer()
            status.set('starting')
            self.thread.start()
        else:
            error.set('Thread already running')


    def stop(self):
        if self.thread != None:
            status.set('stopping')
            self.thread.stop()
            self.thread.join()
            error.set('Join complete')
            self.thread = None
        else:
            error.set('No thread to stop')

op = threadedOp()

#remaining gui
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(tkinter.N, tkinter.W, tkinter.E, tkinter.S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)

ttk.Label(mainframe, textvariable=elapsed).grid(column=1, row=1, sticky=(tkinter.W, tkinter.E))
ttk.Label(mainframe, textvariable=status).grid(column=2, row=1, sticky=(tkinter.W, tkinter.E))
ttk.Label(mainframe, textvariable=error).grid(column=1, row=3, sticky=(tkinter.W, tkinter.E))
ttk.Button(mainframe, text="Start", command=op.run).grid(column=1, row=2, sticky=tkinter.W)
ttk.Button(mainframe, text="Stop", command=op.stop).grid(column=2, row=2, sticky=tkinter.W)

root.mainloop()

【讨论】:

  • 谢谢。在某些版本之后,我能够运行您的代码。但是,当我点击开始按钮时,它会打印一条消息,说明 super() 方法需要一个参数并且没有给出任何参数。在计时器类中 super 应该有什么参数?
  • 你在运行 python 2.x 吗?这是为 python 3 编写的。例如 tkinter 模块曾经在 2.x 中有一个大写 T 我相信。如果是这种情况,super(see the docs) 实际上除了在此处使用的两个参数,我们想要超级的类名和绑定超级对象的实例。因此该行将显示为:super(timer, self).__init__()。这样super的优势就没有了,你也可以写threading.Thread.__init__(self),不过我喜欢super(py3熟悉它)
  • 是的,我正在运行 2.x,所以不得不更改一些语法。再次感谢
猜你喜欢
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多