WxPython - GUI 冻结

WxPython - GUI frozen

我的 python 程序由一个服务器套接字和一个 GUI 组成。 如果新客户端连接到服务器,则应将新滑块添加到 GUI。 客户端接收到的数据应该改变滑块的位置。

我的问题是,方法 "addSlider" 的调用使 GUI 冻结。 我注意到只要调用该方法的服务器线程停止,它就会冻结。

为了简单起见,我创建了一个测试线程而不是服务器线程

您对我如何正确添加滑块有什么建议吗?

主线程:

g = GUI()
t = Test(g.addSlider)
g.start()
t.start()

测试Class:

class Test(threading.Thread):
    def __init__(self, addFunction):
            threading.Thread.__init__(self)
            self.add = True
            self.addFunction = addFunction

    def run(self):
            while True:
                    if self.add:
                            self.addFunction(10)
                            self.add = False

图形界面 Class:

class GUI(threading.Thread):
    def __init__(self, title='New Window'):
        threading.Thread.__init__(self)
        self.ex = wx.App(False)
        self.title = title
        self.window = Window(None, self.title)

    def loop(self):
        self.ex.MainLoop()

    def addSlider(self, newId):
        self.window.addSlider(newId)

class Window(wx.Frame):

class Window(wx.Frame):
    def __init__(self, parent, title):
        super(Window, self).__init__(parent, title = title, style= wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.SetSize(wx.Size(300, 500))
        self.SetMinSize(wx.Size(300, 500))
        self.SetBackgroundColour('RED')

        self.rootPanel = wx.Panel(self)
        self.rootPanel.Fit()
        self.rootPanel.SetBackgroundColour('YELLOW')

        self.panelList = []
        self.panelIdList = []

        self.vbox = wx.BoxSizer(wx.HORIZONTAL)
        self.vbox.Fit(self)

        self.rootPanel.SetSizer(self.vbox)

        self.Centre()
        self.Show(True)

    def addSlider(self, sldId):
        minSize = 130 * (len(self.panelList)+1)

        if minSize < 300:
            minSize = 300

        self.SetSize(wx.Size(minSize, 500))
        self.SetMinSize(wx.Size(minSize, 500))

        cpnl = ControlPanel(self.rootPanel, 500, sldId)

        self.panelIdList.append(sldId)
        self.panelList.append(cpnl)

        self.vbox.Add(self.panelList[len(self.panelList)-1], 1, wx.ALL|wx.ALIGN_CENTER)
        self.vbox.Layout()
        self.vbox.Fit(self)

        self.rootPanel.Layout()
        self.Layout()

控制面板Class:

class ControlPanel(wx.Panel):
    def __init__(self, parent, newHeight, newId):
        wx.Panel.__init__(self, parent, -1, size=wx.Size(100, newHeight), style=wx.ALIGN_CENTER)
        self.id = newId

        self.lbl = wx.StaticText(self, label = ("ID = " + str(newId)), name = ("ID = " + str(newId)), style = wx.ALIGN_CENTRE_HORIZONTAL)

        self.sld = wx.Slider(self, value = 10, size = wx.Size(100, newHeight-100), minValue = 0, maxValue = 255, style = wx.SL_VERTICAL|wx.SL_MIN_MAX_LABELS|wx.SL_INVERSE)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.lbl, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM | wx.TOP, 20)
        self.sizer.Add(self.sld, 1, wx.ALIGN_CENTER | wx.LEFT, 30)

        self.sizer.Fit(parent)
        self.SetSizer(self.sizer)

        self.sizer.Layout()
        self.Layout()

问题几乎可以肯定是您从 Python 线程中启动 wx.App。这是落后的。 App 对象应该是主线程,并根据需要产生所有其他线程。改为创建 wx.App 的子 class,然后在需要时创建不同的线程。

注意当使用线程时,你必须使用wxPython的线程安全方法从线程返回到wxPython。以下方法是线程安全的:

  • wx.CallAfter
  • wx.CallLater
  • wx.PostEvent

以下是包含更多信息的几个链接: