显示 wx.panel 时如何执行 while 循环?

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

我是 wxPython 的新手,我想在显示特定面板 (Panel1) 时执行一个 while 循环,并在面板隐藏时停止它。

我对循环很感兴趣,因为我想更改 Panel1 中的标签值。

我试着按字面意思输入代码 while True: ...,但没有成功,

有什么建议吗?

正如其他人所提到的,您可以使用线程或 wx.Timer 来完成您要查找的内容。我从我的旧面板切换 tutorial 中抓取了一些代码并对其进行了修改以展示如何使用计时器方法。您所要做的就是运行以下代码并通过菜单切换面板:

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()

就我个人而言,我认为为此使用线程有点矫枉过正。然而,将上面的代码修改为使用线程是一种有趣的做法。所以这也是那个版本:

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()

请注意,您需要通过 EVT_CLOSE 捕获关闭事件,以确保线程在退出应用程序时停止,否则您的应用程序可能会挂起或出现异常。