Python 线程在Tkinter回调块中启动,以阻止整个接口

Python 线程在Tkinter回调块中启动,以阻止整个接口,python,multithreading,tkinter,trace,Python,Multithreading,Tkinter,Trace,(在找到新信息后,我删除了旧描述,我认为不再需要它) 所以,我有一个Tkinter界面,实际上有三个按钮:Run,Stop,Step “运行”按钮启动运行各种函数的线程,但需要在“步骤”按钮上输入以继续执行。这是通过等待一个Python事件来完成的,该事件是在按下Step按钮时设置的 但是,尽管在等待我的事件时有time.sleep,我的代码仍不会返回Tkinter接口,整个程序被阻止。如果我删除等待条件,线程将一直运行到停止,那么我就可以访问我的接口 我相信回调函数RunButton()在线程

(在找到新信息后,我删除了旧描述,我认为不再需要它)

所以,我有一个Tkinter界面,实际上有三个按钮:Run,Stop,Step

“运行”按钮启动运行各种函数的线程,但需要在“步骤”按钮上输入以继续执行。这是通过等待一个Python事件来完成的,该事件是在按下Step按钮时设置的

但是,尽管在等待我的事件时有
time.sleep
,我的代码仍不会返回Tkinter接口,整个程序被阻止。如果我删除等待条件,线程将一直运行到停止,那么我就可以访问我的接口

我相信回调函数
RunButton()
在线程结束之前不会返回,这就是我的接口被锁定的原因。有没有办法通过这个问题

这是我目前的代码:

import sys
import signal
import inspect
import threading
import multiprocessing 
import Queue
import time
import Tkinter

class tk_interface(Tkinter.Tk):
    def __init__(self,parent):
        Tkinter.Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()

    def initialize(self):
        self.grid()

        self.button1 = Tkinter.Button(self,text=u"Run",command=self.RunButton)
        self.button1.grid(column=0,row=0)

        self.button2 = Tkinter.Button(self,text=u"Stop",command=self.StopButton)
        self.button2.grid(column=1,row=0)

        self.button3 = Tkinter.Button(self,text=u"Step",command=self.StepButton)
        self.button3.grid(column=2,row=0)

        self.cmd_box = Tkinter.Text(self, wrap='word', height=20)
        self.cmd_box.grid(column=0,row=1,columnspan=3)

        self.resizable(False,False)
        self.update()
        self.ReadReportQueue()

    def RunButton(self):
        thr1.run()

    def StopButton(self):
        self.destroy()

    def StepButton(self):
        cmd_step.set()

    def ReadReportQueue(self):
        sys.stdout=sys.__stdout__
        if not reportQueue.empty():
            catch_message(self.cmd_box,reportQueue)
        self.after(200, self.ReadReportQueue)


class debug_thread(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def trace_calls(self, frame, event, arg):
        if event != 'call':
            return

        co = frame.f_code
        func_name = co.co_name
        file_name = co.co_filename

        if func_name in ['loop_func']:
            return self.trace_lines

    def trace_lines(self, frame, event, arg):
        if event != 'line' and event != 'return':
            return

        co = frame.f_code
        func_name = co.co_name
        file_name = co.co_filename
        source = inspect.getsourcelines(co)[0]

        #cmd_step.wait()

        while not cmd_step.is_set():
            time.sleep(0.2)

        cmd_step.clear()
        print('Call to %s on line %s of %s' % (func_name, frame.f_lineno, co.co_filename))

    def loop_func(self):
        for i in range(0,3):
            print("Loop number %d\n" %i)

    def run(self):
        print "Started thread"
        sys.stdout = reportQueue
        sys.settrace(self.trace_calls)
        self.loop_func()
        print "Exiting " + self.name


class StdoutQueue(Queue.Queue):
    def __init__(self, *args, **kwargs):
        Queue.Queue.__init__(self, *args, **kwargs)

    def write(self, msg):
        self.put(msg)

    def flush(self):
        sys.__stdout__.flush()


def catch_message(text_widget, queue):
    text_widget.insert(Tkinter.INSERT,queue.get())


if __name__ == "__main__":
    cmd_step = threading.Event()
    cmd_step.clear()

    reportQueue = StdoutQueue()

    thr1 = debug_thread('Thread 1')

    app = simpleapp_tk(None)
    app.title('Debug App')

    while True:
        app.update_idletasks()
        app.update()
        print "updating..."

通过继承
threading.thread
创建线程时,通过重写
thread.run
提供应在线程中运行的代码。但是,
debug\u thread.run
仍然是一种正常的方法。调用
thr1.run()
时,您只执行
debug\u thread.run
中声明的代码,该代码不会启动单独的线程。要启动一个单独的线程,需要使用
thr1.start()
,它将创建一个新线程,并在新线程中调用
run
方法

继承
threading.Thread
的另一种方法是将要在新线程中调用的函数作为参数传递给
threading.Thread
构造函数

def run_in_thread(step_event, stop_event):
    local_data = 1
    while not stop_event.is_set():
        local_data = do_step(local_data)
        step_event.wait()
        step_event.clear()

step_event = threading.Event()
stop_event = threading.Event()

thread = threading.Thread(target=run_in_thread, args=(step_event, stop_event))
thread.start()
要单步执行线程函数,只需设置
step\u event
,要停止它并让线程终止,请设置
stop\u event
使循环中断,然后设置
step\u event
,使线程再次检查循环条件

这两个
事件
作为线程参数传递,因此它们不需要是全局变量。

您直接调用
thr1.run()
,而不是
thr1.start()
,因此您永远不会真正启动第二个线程。