wxPython线程不阻止GUI?

时间:2014-04-10 16:30:03

标签: multithreading user-interface wxpython blocking

我是wxPython和线程的新手。我试图将一些代码移动到一个线程中,以便它在执行时不再阻止我的GUI,我可以按下另一个按钮来杀死该线程。但是,完成此操作后,代码仍会阻止我的GUI。如何编写此代码以便我的线程不会阻止GUI?

import wx, sys
import threading
import time


class mywxframe(wx.Frame):

    global sizer2, WorkerThread

    def __init__(self):
        wx.Frame.__init__(self, None)
        pnl = wx.Panel(self)
        szr = wx.BoxSizer(wx.VERTICAL)
        pnl.SetSizer(szr)
        szr2 = sizer2(self, pnl)
        szr.Add(szr2, 1, wx.ALL | wx.EXPAND, 10)
        log = wx.TextCtrl(pnl, -1,style=wx.TE_MULTILINE, size=(300,-1))
        szr.Add(log, 1, wx.ALL, 10)
        btn3 = wx.Button(pnl, -1, "Stop")
        btn3.Bind(wx.EVT_BUTTON, self.OnStop)

        szr.Add(btn3, 0, wx.ALL, 10)

        redir = RedirectText(log)
        sys.stdout=redir

        szr.Fit(self)
        self.Show()


    def sizer2(self, panel):
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        btn2 = wx.Button(panel, -1, "OK",)
        self.Bind(wx.EVT_BUTTON, self.OnStart, btn2)
        sizer.Add(btn2, 0, wx.ALL, 10)
        return sizer


    def WorkerThread(self):    
        self.dead = False
        while (not self.dead):
            for i in range(0,10):
                print "printing", i
                time.sleep(3)

    def OnStart(self, event):
         our_thread = threading.Thread(target=WorkerThread(self))
         our_thread.start()

    def OnStop(self, event):
        self.dead = True


class RedirectText(object):
    def __init__(self, aWxTextCtrl):
        self.out=aWxTextCtrl

    def write(self, string):
        self.out.WriteText(string)




app = wx.PySimpleApp()
frm = mywxframe()
app.MainLoop()

1 个答案:

答案 0 :(得分:1)

那里有几个问题。

首先,如果您要将sizer2WorkerThread定义为方法,则应将它们用作方法,而不是全局变量。

接下来,当您创建线程时,您正在调用WorkerThread并将其返回值(None)传递给线程。这是您阻止GUI的地方。

    def OnStart(self, event):
        our_thread = threading.Thread(target=WorkerThread(self))
        our_thread.start()

相反,你应该将一个可调用的对象(WorkerThread没有())传递给线程,这样它就可以在新线程的上下文中调用它。

最后,由于self.out.WriteText操纵UI对象,因此必须在GUI线程的上下文中调用它。使用wx.CallAfter是一种简单的方法。

以下是使用这些更改更新的示例:

import wx, sys
import threading
import time

print wx.version()

class mywxframe(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None)
        pnl = wx.Panel(self)
        szr = wx.BoxSizer(wx.VERTICAL)
        pnl.SetSizer(szr)
        szr2 = self.sizer2(pnl)
        szr.Add(szr2, 1, wx.ALL | wx.EXPAND, 10)
        log = wx.TextCtrl(pnl, -1,style=wx.TE_MULTILINE, size=(300,-1))
        szr.Add(log, 1, wx.ALL, 10)
        btn3 = wx.Button(pnl, -1, "Stop")
        btn3.Bind(wx.EVT_BUTTON, self.OnStop)

        szr.Add(btn3, 0, wx.ALL, 10)

        redir = RedirectText(log)
        sys.stdout=redir

        szr.Fit(self)
        self.Show()


    def sizer2(self, panel):
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        btn2 = wx.Button(panel, -1, "OK",)
        self.Bind(wx.EVT_BUTTON, self.OnStart, btn2)
        sizer.Add(btn2, 0, wx.ALL, 10)
        return sizer


    def WorkerThread(self):    
        self.dead = False
        while (not self.dead):
            for i in range(0,10):
                print "printing", i
                if self.dead:
                    break
                time.sleep(3)
        print 'thread exiting'

    def OnStart(self, event):
        our_thread = threading.Thread(target=self.WorkerThread)
        our_thread.start()

    def OnStop(self, event):
        self.dead = True


class RedirectText(object):
    def __init__(self, aWxTextCtrl):
        self.out=aWxTextCtrl

    def write(self, string):
        wx.CallAfter(self.out.WriteText, string)


app = wx.App()
frm = mywxframe()
app.MainLoop()