使用wxPython中的线程更新GUI中面板的标签

时间:2014-03-04 16:01:19

标签: python multithreading python-2.7 user-interface wxpython

等级:初学者

我使用的是python v2.7和wxPython v3.0,操作系统是Windows 7。

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

问题:我想每隔5秒检查一次服务器以获取值并相应地更新我的GUI即。我必须更新面板上的staticText以显示更新的值。我不想添加新面板,我只想更新旧面板中的值。

例如:如果我检查服务器以及服务器是否返回 1 2 3 为然后我想创建 3 面板,分别显示 1 2 3 值。然后在我再次检查服务器5秒后,如果服务器提供 4 5 6 作为值,那么我只想更新这些值在旧面板上。这意味着现在面板将显示 4 5 6 而不是 1 2 3 。我读了一些教程& SC关于使用线程的帖子,我也理解了一些基本事实。不幸的是,我不明白如何将这个概念应用于我的问题。 如果我可以为我的这个特定问题找到一个有效的例子,那将是非常好的,这样我就可以将它应用到我的应用程序的其余部分。

代码:我为此特定问题创建了一个简短的示例代码。 getLabels()中的class labelsA和类getLabels()中的labelsB通过生成一些随机值并将其返回到列表中来模仿服务器。然后getLabels()的{​​{1}}返回的值列表以及class labelA的{​​{1}}返回的值列表由getLabels()和{{1}使用分别创建面板并显示这些值。白色背景中的面板为class labelsB,黄色背景的面板为createPanels()A。如果有人可以教我如何使用线程来更新这两个面板的值而不冻结/阻止我的GUI,那将是非常好的。

下载:示例代码如下所示,也可以是downloaded from here,以避免出现身份问题。

createPanelsB()

非常感谢你的时间。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

以下是创建一个每5秒从某个地方获取信息的线程的演示,还展示了如何根据需要创建StaticTexts,以及如何更新它们。

#!/usr/bin/env python

from random import randrange
import wx
import wx.lib.scrolledpanel

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)

        self.text_labels = []  # Stores the labels where server data is displayed

        pub.subscribe(self.OnNewLabels, "NEW_LABELS")


    def OnNewLabels(self, labels):
        locations = labels
        print locations
        if len(self.text_labels) < len(labels):
            new_labels_needed = len(labels) - len(self.text_labels) 
            label = "(no data)"
            for i in range(new_labels_needed):
                sPanels = wx.Panel(self.panel)
                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)
                self.text_labels.append(text)
            self.sizer.Layout()            
        k = 0
        for label in locations:
            self.text_labels[k].SetLabel(str(label))
            k=k+1


###############################
#
#

def InterfaceThread():
    while True:
        # get the info from the server
        mylist =[]
        i = randrange(10)
        for k in range(1,i+1):
            mylist.append(randrange(10))

        # Tell the GUI about them
        wx.CallAfter(pub.sendMessage, "NEW_LABELS", labels = mylist)
        time.sleep(5)


class ServerInterface():

    def __init__(self):
        interface_thread = threading.Thread(target = InterfaceThread, args = ()) 
        interface_thread.start()



#############
#

if __name__=='__main__':
    app = wx.App()
    frame = GUI(parent=None, id=-1, title="Test")
    frame.Show()
    server_interface = ServerInterface()
    app.MainLoop()

答案 1 :(得分:1)

为了记录,我知道很久以前这个问题得到了解答,用简单的wx.Timer可以达到同样的效果。
使用上面提供的代码:

3