在wxPython中使用线程更新GUI面板标签
级别:初学者
我正在使用 Python 2.7 和 wxPython 3.0,操作系统是 Windows 7。
我的 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。我看了一些关于使用线程的教程和帖子,也理解了一些基本概念。不幸的是,我不太明白如何将这个概念应用到我的问题上。如果能给我一个适用于我这个特定问题的示例,那就太好了,这样我可以将其应用到我的其他部分。
代码:我为这个特定问题创建了一个简短的示例代码。在 class labelsA
中的 getLabels()
和 class labelsB
中的 getLabels()
模拟了服务器,只是生成一些随机值并将它们以列表的形式返回。然后,class labelA
中的 getLabels()
返回的值列表和 class labelsB
中的 getLabels()
返回的值列表分别被 createPanels()A
和 createPanelsB()
用来创建面板并显示这些值。白色背景的面板是 panelA
,黄色背景的面板是 panelB
。如果有人能教我如何使用线程来更新这两个面板的值,而不让我的 GUI 冻结或阻塞,那就太好了。
下载:下面提供了示例代码,也可以通过 这里下载,以避免缩进问题。
#!/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.HORIZONTAL)
panelSizer = wx.BoxSizer(wx.HORIZONTAL)
self.sizerA = sizerA = wx.BoxSizer(wx.VERTICAL)
self.panelA = panelA = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER)
panelA.SetupScrolling()
panelA.SetBackgroundColour('#FFFFFF')
self.sizerB = sizerB = wx.BoxSizer(wx.VERTICAL)
self.panelB = panelB = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER)
panelB.SetupScrolling()
panelB.SetBackgroundColour('#FFF000')
panelA.SetSizer(sizerA)
panelB.SetSizer(sizerB)
mainSizer.Add(panelA, 15, wx.EXPAND|wx.ALL)
mainSizer.Add(panelB, 15, wx.EXPAND|wx.ALL)
self.SetSizer(mainSizer)
self.createPanelsA()
self.createPanelsB()
def createPanelsA(self):
k = 0
labelObj = labelsA()
locations = labelObj.getLabel()
print locations
for i in locations:
sPanels = 'sPanel'+str(k)
sPanels = wx.Panel(self.panelA)
label = str(k+1)
text = wx.StaticText(sPanels, -1, label)
text.SetFont(self.locationFont)
text.SetForegroundColour('#0101DF')
self.sizerA.Add(sPanels, 0, wx.ALL, 5)
self.sizerA.Add(wx.StaticLine(self.panelA), 0, wx.ALL|wx.EXPAND, 0)
k += 1
def createPanelsB(self):
k = 0
labelObj = labelsB()
locations = labelObj.getLabel()
print locations
for i in locations:
sPanels = 'sPanel'+str(k)
sPanels = wx.Panel(self.panelB)
label = str(k+1)
text = wx.StaticText(sPanels, -1, label)
text.SetFont(self.locationFont)
text.SetForegroundColour('#0101DF')
self.sizerB.Add(sPanels, 0, wx.ALL, 5)
self.sizerB.Add(wx.StaticLine(self.panelB), 0, wx.ALL|wx.EXPAND, 0)
k += 1
################################################
class labelsA():
def getLabel(self):
mylist =[]
i = randrange(10)
for k in range(1,i+1):
mylist.append(k)
return mylist
###############################################
class labelsB():
def getLabel(self):
mylist =[]
i = 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()
app.MainLoop()
非常感谢您的时间。任何帮助都将不胜感激。
2 个回答
为了说明,我知道这个问题早就有人回答过了,其实用一个简单的 wx.Timer 也能达到同样的效果。
使用上面提供的代码:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import wx
import wx.lib.scrolledpanel
from random import randrange
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
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
self.timer.Start(5000)
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
if len(self.text_labels) > len(labels):
labels_not_needed = len(self.text_labels) - len(labels)
for i in range(labels_not_needed):
self.text_labels[k].SetLabel("-")
k+=1
def OnTimer(self, evt):
# get the info from the server
mylist =[]
i = randrange(10)
for k in range(1,i+1):
mylist.append(randrange(10))
self.OnNewLabels(mylist)
if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()
这里演示了如何创建一个线程,每隔5秒从某个地方获取信息。同时也展示了如何根据需要创建静态文本,以及如何更新这些文本。
#!/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()