Search code examples
pythonuser-interfacewxpythonpanel

wxPython : Update the label on Panel with GridBagSizer and Timer


I want to update the panel "label", but I think I am wrong with Refresh/Update/Remove method .

I write 2 python file, the "WriteData.py" would auto-update a txt file, and the "Main.py" want to show the txt value on wx.panel.

I run the 2 python file at the same time, use Timer to auto update data every 3 sec .

And I use the GridBagSizer hope to arrange these panel position.

But I don't know how to arrange the new updating panel position, Also don't know how to remove previous panel .

Hope you give me some advice, or even point out my mistake. I also appreciate for some example code about this !

Here is the "Main.py"

import wx
import time

def ReadData():
    with open('RealTime.txt') as f:
        for line in f:
            data = line.split()
    results = map(float, data)
    return results

class BlockWindow(wx.Panel):
    # code on book "wxPython in action" Listing 11.1 
    def __init__(self, parent, ID=-1, label="",
                 pos = wx.DefaultPosition, size = (100, 25)):
        wx.Panel.__init__(self, parent, ID, pos, size, 
                          wx.RAISED_BORDER, label)
        self.label = label

        self.SetMinSize(size)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
    def OnPaint(self, evt):
        sz = self.GetClientSize()
        dc = wx.PaintDC(self)
        w,h = dc.GetTextExtent(self.label)
        dc.SetFont(self.GetFont())
        dc.DrawText(self.label, (sz.width-w)/2, (sz.height-h)/2)


class MyPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, size=(0,0))

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
        self.timer.Start(3000)

    def OnTimer(self, evt):
        Data = ReadData()
        sizer = wx.GridBagSizer(hgap=5, vgap=-1)

        bw = BlockWindow(self, label="Item 1" )
        sizer.Add(bw, pos=(4, 2))
        #bw.Refresh()

        bw = BlockWindow(self, label="Updated : %.3f" % Data[0])
        sizer.Add(bw, pos=(5, 2))
        bw.Refresh()           
        #bw.Update(self, label ="Updated : %.3f" % Data[0] )

        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(sizer, 0, wx.EXPAND|wx.ALL, 10)

        self.SetSizer(mainSizer)
        self.Fit()

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title=' Frame Title')
        mypanel = MyPanel(self)
        self.SetSize(wx.Size(800,600))
        self.Centre()

app = wx.App(False)
MyFrame().Show()
app.MainLoop()

Here is the 'WriteData.py',

import sched, time
from datetime import datetime as dt

data = ['5.564', '3.4', '2.176', '7.3',  '4.4', '5.5', '2.3', '4.4', '5.1']

index = 0

while True:
    start = dt.now().hour
    stop = dt.now().hour + 1
    if index >7 : index=1
    if dt.now().hour in range(start, stop):  # start, stop are integers (eg: 6, 9)
        # call to your scheduled task goes here
        f2 = open('RealTime.txt', 'w')
        f2.write("%s " % data[index])
        index = index + 1
        f2.close()

        time.sleep(3)
    else:
        time.sleep(3)

When I run the 2 .py file , I got this situation Running example

Hope you help me solve this . I use python2.7 on win10. Best regards, Kuo-Ting Tang


Solution

  • You don't need to recreate everything from scratch each time an update is needed. Just move the initialization code (where you create BlockWindows and sizers to the constructor of MyPanel. It seems that all you want to do is update the label of the second panel, to achieve this you could write a method in BlockWindow that will update the label and call Refresh so that OnPaint will be triggered and will take care of the rest.

    class BlockWindow(wx.Panel):
        # code on book "wxPython in action" Listing 11.1 
        def __init__(self, parent, ID=-1, label="",
                     pos = wx.DefaultPosition, size = (100, 25)):
            wx.Panel.__init__(self, parent, ID, pos, size, 
                              wx.RAISED_BORDER, label)
            self.label = label
    
            self.SetMinSize(size)
            self.Bind(wx.EVT_PAINT, self.OnPaint)
        def OnPaint(self, evt):
            sz = self.GetClientSize()
            dc = wx.PaintDC(self)
            w,h = dc.GetTextExtent(self.label)
            dc.SetFont(self.GetFont())
            dc.DrawText(self.label, (sz.width-w)/2, (sz.height-h)/2)
    
        def UpdateLabel(self, label):
            self.label = label
            self.Refresh()
    
    class MyPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent, size=(0,0))
    
            sizer = wx.GridBagSizer(hgap=5, vgap=-1)
            bw = BlockWindow(self, label="Item 1" )
            sizer.Add(bw, pos=(4, 2))
    
            self.block = BlockWindow(self, label="")
            sizer.Add(self.block, pos=(5, 2))
    
            mainSizer = wx.BoxSizer(wx.VERTICAL)
            mainSizer.Add(sizer, 0, wx.EXPAND|wx.ALL, 10)
    
            self.SetSizer(mainSizer)
            self.Fit()
    
            self.timer = wx.Timer(self)
            self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
            self.timer.Start(3000)
    
        def OnTimer(self, evt):
            Data = ReadData()
            self.block.UpdateLabel("Updated : %.3f" % Data[0])