Skip to main content
 首页 » 编程设计

python之在 wxPython 中使用线程将面板添加到 GUI

2025年05月04日26kevingrace

级别:初级

我使用 wxPython 已经一个月了。我几乎完成了我的 GUI 应用程序,但是当涉及到线程时,我陷入了困境。我正在使用 python v2.7 和 wxPython v3.0,操作系统是 windows 7。

我的 GUI 应用程序:在我的 GUI 应用程序中,我从服务器读取一些值,然后根据这些值的数量在我的 GUI 中创建面板。然后,这些面板中的每一个都将以 staticText 的形式表示值。例如:如果我从服务器接收到 1,2,3 值,那么我会创建 3 面板,每个面板显示 123 分别。到这里一切正常。

问题:我想每 5 秒检查一次服务器以获取值并相应地更新我的 GUI,即。我必须添加新面板来显示新值。我在 SC 上阅读了一些关于使用线程的教程和帖子,我也了解了一些基本事实。不幸的是,我不明白如何将这个概念应用到我的问题中。我想我必须将检查服务器值的代码放在线程循环中。但我不明白还能做什么。我想我可能必须更改我的代码逻辑(创建面板部分)以使用线程。 如果我能为我的这个特定问题找到一个工作示例,那么我就可以将它应用到我的应用程序的其余部分,那就太好了。

代码:我为这个特定问题创建了一个简短的示例代码。 class labels 中的 getLabels() 通过生成一些随机值并将它们返回到列表中来模拟服务器。然后,createPanels() 使用这些值来创建面板并显示这些值。如果有人能教我如何使用线程将新面板添加到我的 GUI 而不会卡住/阻塞我的 GUI,那就太好了。

下载:整个代码可以在下面找到,也可以downloaded from here以避免任何识别问题。

#!/usr/bin/env python 
 
from random import randrange 
import wx 
import wx.lib.scrolledpanel 
 
class GUI(wx.Frame): 
 
    def __init__(self, parent, id, title): 
        screenWidth = 800 
        screenHeight = 450 
        screenSize = (screenWidth, screenHeight) 
        wx.Frame.__init__(self, None, id, title, size=screenSize) 
        self.locationFont = locationFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD) 
        mainSizer = wx.BoxSizer(wx.VERTICAL) 
        self.sizer = sizer = wx.BoxSizer(wx.VERTICAL) 
        self.panel = panel = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER) 
        panel.SetupScrolling() 
        panel.SetBackgroundColour('#FFFFFF') 
        self.createPanels() 
        panel.SetSizer(sizer) 
        mainSizer.Add(panel, 15, wx.EXPAND|wx.ALL) 
        self.SetSizer(mainSizer) 
 
    def createPanels(self): 
        k = 0 
        labelObj = labels() 
        locations = labelObj.getLabel() 
        print locations 
        for i in locations: 
            sPanels = 'sPanel'+str(k) 
            sPanels = wx.Panel(self.panel) 
            label = str(k+1) 
            text = wx.StaticText(sPanels, -1, label) 
            text.SetFont(self.locationFont) 
            text.SetForegroundColour('#0101DF') 
            self.sizer.Add(sPanels, 0, wx.ALL, 5) 
            self.sizer.Add(wx.StaticLine(self.panel), 0, wx.ALL|wx.EXPAND, 0) 
            k += 1 
 
################################################ 
class labels(): 
    def getLabel(self): 
    mylist =[] 
    i = randrange(10) 
    for k in range(1,i+1): 
        list.append(k) 
    return mylist 
############################################### 
 
if __name__=='__main__': 
app = wx.App() 
frame = GUI(parent=None, id=-1, title="Test") 
frame.Show() 
app.MainLoop() 

如果执行代码后没有看到任何面板,请重新执行代码。

感谢您的宝贵时间。

请您参考如下方法:

希望这段代码能包含一些答案。基本上:将服务器接口(interface)放在线程中,并使用 wx.CallAfter 与 wx 中的组件对话。使用 pubsub 在 GUI 中的元素之间进行对话。该代码创建了一个线程,该线程每 5 秒执行一次操作,并且它通过直接方法调用与您拥有句柄的 wx 元素进行通信,并通过 pubsub 与您没有句柄的元素进行通信。

#!/usr/bin/env python 
 
from random import randrange 
import wx 
import wx.lib.scrolledpanel 
 
# imports added by GreenAsJade 
import time 
import threading 
from wx.lib.pubsub import setupkwargs 
from wx.lib.pubsub import pub 
 
class GUI(wx.Frame): 
 
    def __init__(self, parent, id, title): 
        screenWidth = 800 
        screenHeight = 450 
        screenSize = (screenWidth, screenHeight) 
        wx.Frame.__init__(self, None, id, title, size=screenSize) 
        self.locationFont = locationFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD) 
        mainSizer = wx.BoxSizer(wx.VERTICAL) 
        self.sizer = sizer = wx.BoxSizer(wx.VERTICAL) 
        self.panel = panel = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER) 
        panel.SetupScrolling() 
        panel.SetBackgroundColour('#FFFFFF') 
        panel.SetSizer(sizer) 
        mainSizer.Add(panel, 15, wx.EXPAND|wx.ALL) 
        self.SetSizer(mainSizer) 
 
        pub.subscribe(self.OnNewLabels, "NEW_LABELS") 
 
 
    def OnNewLabels(self, labels): 
        k = 0 
        locations = labels 
        print locations 
        for i in locations: 
            sPanels = 'sPanel'+str(k) 
            sPanels = wx.Panel(self.panel) 
            label = str(k+1) 
            print "doing", label 
            text = wx.StaticText(sPanels, -1, label) 
            text.SetFont(self.locationFont) 
            text.SetForegroundColour('#0101DF') 
            self.sizer.Add(sPanels, 0, wx.ALL, 5) 
            self.sizer.Add(wx.StaticLine(self.panel), 0, wx.ALL|wx.EXPAND, 0) 
            k += 1 
        self.sizer.Layout() 
 
 
############################### 
# 
# 
 
def InterfaceThread(id, log): 
    label_generator = Labels() 
    while True: 
        labels = label_generator.getLabel()   # get the info from the server 
        # Tell the GUI about them 
        wx.CallAfter(pub.sendMessage, "NEW_LABELS", labels = labels) 
        # Tell the logger about them 
        wx.CallAfter(log.AppendText, "Sent %s \n" % str(labels)) 
        time.sleep(5) 
 
 
class ServerInterface(wx.Frame): 
 
    def __init__(self, parent, id, title): 
        wx.Frame.__init__(self, None, id, title) 
        self.log = wx.TextCtrl(self, style = wx.TE_MULTILINE) 
        interface_thread = threading.Thread(target = InterfaceThread, args = (1, self.log))  
        interface_thread.start() 
 
 
 
################################################ 
class Labels(): 
    def getLabel(self): 
        mylist =[] 
        i = 4 #randrange(10) 
        for k in range(1,i+1): 
            mylist.append(k) 
        return mylist 
############################################### 
 
if __name__=='__main__': 
    app = wx.App() 
    frame = GUI(parent=None, id=-1, title="Test") 
    frame.Show() 
    server_interface = ServerInterface(parent = None, id=-1, title="Server Log") 
    server_interface.Show() 
    app.MainLoop()