使用wxPython中的线程将面板添加到GUI

时间:2014-03-03 11:43:16

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

等级:初学者

我已经和wxPython合作了一个月了。我几乎完全是我的GUI应用程序,但是当涉及到线程时,我被卡住了。我使用的是python v2.7和wxPython v3.0,操作系统是Windows 7。

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

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

代码:我为此特定问题创建了一个简短的示例代码。 getLabels()中的class labels通过生成一些随机值并将其返回到列表中来模仿服务器。然后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()

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

感谢您的时间。

2 个答案:

答案 0 :(得分:1)

希望此代码包含一些答案。基本上:将接口放在线程中的服务器上,并使用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()

答案 1 :(得分:0)

跟进:为清晰起见,这里是SeverInterface不是图形元素的版本。

#!/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():
    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)
        time.sleep(5)


class ServerInterface():

    def __init__(self):
        interface_thread = threading.Thread(target = InterfaceThread, args = ()) 
        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()
    app.MainLoop()

正如我在另一个答案中提到的 - 如果你想更新StaticTexts,然后在创建它们时将它们放在一个数组中,并在OnNewLabels中迭代数组,用SetLabel()更新它们。