Kevin Quinzel
Kevin Quinzel

Reputation: 1428

How to execute a while loop when wx.panel is shown?

I'm new using wxPython and I want to execute a while loop just when certain panel (Panel1) is shown and stop it when the panel gets hidden.

I'm interested in the loop because I want to change a label's value which is in the Panel1.

I tried to literally put the code while True: ..., but didn't work,

Any suggestions?

Upvotes: 0

Views: 1045

Answers (1)

Mike Driscoll
Mike Driscoll

Reputation: 33071

As the others have mentioned, you can use a thread or a wx.Timer to accomplish what you're looking for. I grabbed some code from my old panel switching tutorial and modified it to show how to use the timer approach. All you have to do is run the following code and switch the panels via the menu:

import wx
import wx.grid as gridlib

########################################################################
class PanelOne(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)

        grid = gridlib.Grid(self)
        grid.CreateGrid(25,12)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(grid, 0, wx.EXPAND)
        self.SetSizer(sizer)

########################################################################
class PanelTwo(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)
        self.count = 0
        self.lbl = wx.StaticText(self,
                                 label='Counter: {}'.format(self.count))

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.update, self.timer)

    #----------------------------------------------------------------------
    def start_timer(self):
        self.timer.Start(1000)

    #----------------------------------------------------------------------
    def stop_timer(self):
        self.timer.Stop()

    #----------------------------------------------------------------------
    def update(self, event):
        self.count += 1
        self.lbl.SetLabel('Counter: {}'.format(self.count))

########################################################################
class MyForm(wx.Frame):

    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY,
                          "Panel Switcher Tutorial")

        self.panel_one = PanelOne(self)
        self.panel_two = PanelTwo(self)
        self.panel_two.Hide()

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.panel_one, 1, wx.EXPAND)
        self.sizer.Add(self.panel_two, 1, wx.EXPAND)
        self.SetSizer(self.sizer)


        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        switch_panels_menu_item = fileMenu.Append(wx.ID_ANY,
                                                  "Switch Panels",
                                                  "Some text")
        self.Bind(wx.EVT_MENU, self.onSwitchPanels,
                  switch_panels_menu_item)
        menubar.Append(fileMenu, '&File')
        self.SetMenuBar(menubar)

    #----------------------------------------------------------------------
    def onSwitchPanels(self, event):
        """"""
        if self.panel_one.IsShown():
            self.SetTitle("Panel Two Showing")
            self.panel_one.Hide()
            self.panel_two.Show()
            self.panel_two.start_timer()
        else:
            self.SetTitle("Panel One Showing")
            self.panel_one.Show()
            self.panel_two.stop_timer()
            self.panel_two.Hide()
        self.Layout()


# Run the program
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm()
    frame.Show()
    app.MainLoop()

Personally, I think using a thread for this is overkill. However it was kind of fun to modify the code above to use a thread instead. So here's that version too:

import time
import wx
import wx.grid as gridlib

from threading import Thread


########################################################################
class TestThread(Thread):
    """Test Worker Thread Class."""

    #----------------------------------------------------------------------
    def __init__(self, panel):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self.panel = panel
        self.sentinel = True
        self.start()    # start the thread

    #----------------------------------------------------------------------
    def run(self):
        """Run Worker Thread."""
        # This is the code executing in the new thread.
        while self.sentinel:
            time.sleep(1)
            wx.CallAfter(self.panel.update)
        print 'Thread finished!'

########################################################################
class PanelOne(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)

        grid = gridlib.Grid(self)
        grid.CreateGrid(25,12)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(grid, 0, wx.EXPAND)
        self.SetSizer(sizer)

########################################################################
class PanelTwo(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)
        self.count = 0
        self.lbl = wx.StaticText(self,
                                 label='Counter: {}'.format(self.count))
        self.thread = None

    #----------------------------------------------------------------------
    def start_timer(self):
        self.thread = TestThread(self)

    #----------------------------------------------------------------------
    def stop_timer(self):
        self.thread.sentinel = False

    #----------------------------------------------------------------------
    def update(self):
        self.count += 1
        self.lbl.SetLabel('Counter: {}'.format(self.count))

########################################################################
class MyForm(wx.Frame):

    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY,
                          "Panel Switcher Tutorial")

        self.panel_one = PanelOne(self)
        self.panel_two = PanelTwo(self)
        self.panel_two.Hide()

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.panel_one, 1, wx.EXPAND)
        self.sizer.Add(self.panel_two, 1, wx.EXPAND)
        self.SetSizer(self.sizer)

        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        switch_panels_menu_item = fileMenu.Append(wx.ID_ANY,
                                                  "Switch Panels",
                                                  "Some text")

        self.Bind(wx.EVT_MENU, self.onSwitchPanels,
                  switch_panels_menu_item)
        self.Bind(wx.EVT_CLOSE, self.on_close)

        menubar.Append(fileMenu, '&File')
        self.SetMenuBar(menubar)

    #----------------------------------------------------------------------
    def onSwitchPanels(self, event):
        """"""
        if self.panel_one.IsShown():
            self.SetTitle("Panel Two Showing")
            self.panel_one.Hide()
            self.panel_two.Show()
            self.panel_two.start_timer()
        else:
            self.SetTitle("Panel One Showing")
            self.panel_one.Show()
            self.panel_two.stop_timer()
            self.panel_two.Hide()
        self.Layout()

    #----------------------------------------------------------------------
    def on_close(self, event):
        self.panel_two.stop_timer()
        self.panel_two.thread.join()
        self.Destroy()


# Run the program
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm()
    frame.Show()
    app.MainLoop()

Note that you will want to catch the close event via EVT_CLOSE to make sure the thread is stopped when exiting your application or you may have your application hang or misbehave.

Upvotes: 1

Related Questions