Question

Level: Beginner

I am using python v2.7 and wxPython v3.0 and the OS is 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. Then each of these panels will represent the values in form of a staticText. For eg: If I receive from the server 1,2,3 values, then I create 3 panels each displaying 1, 2 and 3 respectively. This works fine till here.

Problem: I want to check the server every 5 seconds to fetch the values and accordingly update my GUI ie. I have to update the staticText on the panels to display the updated values. I don't want to add new panels I just want to update the values in the old panels.

For eg: If I check the server and if the server returns 1, 2, 3 as values then I want to create 3 panels displaying 1, 2, 3 values respectively. Then after 5 seconds when I check the server again then if server gives 4, 5, 6 as values then I just want to update these values on the old panels. Which means now the panels will display 4, 5, 6 instead of 1, 2, 3 respectively. I read some tutorials & posts on SC regarding using threads, I understood some basic facts too. Unfortunately I don't understand how to apply this concept to my problem. 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 labelsA and the getLabels() in the class labelsB mimics the server by just generating some random values and returning them in a list. Then the list of values returned by getLabels() of the class labelA and the list of values returned by getLabels() of the class labelsB are used by createPanels()A and createPanelsB() respectively to create panels and to display these values. The panel in white background is panelA and the panel with yellow background is the panelB. It would be really great if some one can teach me how to use threading to update the values of these two panels without freezing/blocking my GUI.

Download: The sample code is provided below and can be downloaded from here too to avoid identation problems.

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

Thank you very much for your time. Any help will be appreciated.

Was it helpful?

Solution

Here is a demonstration of creating a thread to get info from somewhere every 5 seconds, and also showing how to create StaticTexts as you need them, and how to update them.

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

OTHER TIPS

For the record, I know this question was answered a long time ago, the same result can be achieved with a simple wx.Timer.
Using the code supplied above:

#!/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()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top