简体   繁体   English

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

[英]Adding panels to GUI using threading in wxPython

Level: Beginner 级别:初学者

I have been working with wxPython for a month now. 我已经使用wxPython工作了一个月了。 I almost completely my GUI application, but when it came to threading I got stuck. 我几乎完全完成了我的GUI应用程序,但是当涉及到线程时,我陷入了困境。 I am using python v2.7 and wxPython v3.0 and the OS is windows 7. 我正在使用python v2.7和wxPython v3.0,并且操作系统是Windows 7。

My GUI app : Well in my GUI app I am reading some values from a server and then based upon number of these values I create panels in my GUI. 我的GUI应用程序 :在我的GUI应用程序中,我正在从服务器读取一些值,然后根据这些值的数量在GUI中创建面板。 Then each of these panels will represent the values in form of a staticText . 然后,每个面板将以staticText形式表示值。 For eg: If I receive from server 1,2,3 values, then I create 3 panels each displaying 1 , 2 and 3 respectively. 为例如:如果我从服务器1,2,3值接收,然后创建各自分别显示1,23 3层的面板。 Till here everything works fine. 到这里为止一切正常。

Problem: I want to check the server every 5 seconds to fetch the values and accordingly update my GUI ie. 问题:我想每5秒检查一次服务器以获取值并相应地更新我的GUI。 I have to add new panels to display the new values. 我必须添加新面板以显示新值。 I read some tutorials & posts on SC regarding using threads, I understood some basic facts too. 我阅读了一些有关使用线程的SC教程和帖子,我也了解一些基本事实。 Unfortunately I don't understand how to apply this concept to my problem. 不幸的是,我不明白如何将这个概念应用于我的问题。 I think I have to put the code that checks the values from the server in threading loop. 我想我必须将检查来自服务器的值的代码放入线程循环中。 But I don't understand what else to do. 但是我不知道该怎么办。 I think I may have to change the logic of my code (creating panels part) for using threads. 我认为我可能不得不更改使用线程的代码逻辑(创建面板部分)。 It would be really great if I could get a working example for my this particular problem so that I could apply the same to my rest of the application. 如果我能为这个特殊的问题找到一个可行的例子,那真是太好了,这样我就可以将其应用于其余的应用程序中。

Code : I have created a short sample code for this particular problem. 代码 :我为这个特定问题创建了一个简短的示例代码。 The getLabels() in the class labels mimics the server by just generating some random values and returning them in a list. class labelsgetLabels()通过仅生成一些随机值并将其返回到列表中来模拟服务器。 Then these values are used by createPanels() to create panels and to display these values. 然后, createPanels()使用这些值来创建面板并显示这些值。 It would be really great if some one can teach me how to use threading to add new panels to my GUI without freezing/blocking my GUI. 如果有人可以教我如何使用线程添加新面板到我的GUI而不冻结/阻止我的GUI,那将是非常不错的。

Download: The entire code can be found below and can also be downloaded from here to avoid any identation problem. 下载:完整代码可在下面找到,也可以从此处下载,以避免任何标识问题。

#!/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()

If you don't see any panels after executing the code then please re execute the code. 如果执行代码后没有看到任何面板,请重新执行代码。

Thank you for your time. 感谢您的时间。

Hopefully this code will contain some answers. 希望这段代码将包含一些答案。 Basically: put the interface to the server in a thread, and use wx.CallAfter to talk to components in wx. 基本上:将服务器的接口放入线程中,并使用wx.CallAfter与wx中的组件进行通信。 Use pubsub to talk between elements in the GUI. 使用pubsub在GUI中的元素之间进行交谈。 The code has creation of a thread that does something every 5 seconds, and it has communication by direct method call for a wx element that you have a handle for, and communication by pubsub for one that you don't. 该代码创建了一个线程,该线程每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()

Followup: here is a version where the SeverInterface is not a graphical element, for clarity. 后续:为了清晰起见,这是一个版本,其中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()

As I mentioned in the other answer - if you want to update the StaticTexts, then put them in an array when you create them, and iterate through the array in OnNewLabels updating them with SetLabel(). 正如我在另一个答案中提到的那样-如果要更新StaticText,则在创建它们时将它们放在数组中,并在OnNewLabels中遍历该数组,并使用SetLabel()更新它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM