【问题标题】:Open a progress bar until function task ends打开进度条直到函数任务结束
【发布时间】:2019-05-21 02:21:49
【问题描述】:

我在 wx.Grid 内双击左键有一个事件监听器,它打开一个对话框来确认更改。如果用户单击“是”,我会调用一个大约需要 6 秒才能执行的函数,同时窗口会冻结。我想要做的是打开一个进度条,以便用户可以等到函数完成其任务,或者更好的是,在对话框中有进度条。

我不知道从哪里开始,因为直到现在我才需要进度条。

我看过的很多解决方案都建议使用线程,但我对 Python 中的线程非常缺乏经验。

我希望有人能够帮助我显示使用 wxPython 正在运行的任务的进度。

到目前为止,这是我的代码:

def OnCellLeftDClick(self, evt):
    if evt.GetCol() == 17:
        dlg = wx.MessageDialog(None, "Do you want to change " + self.GetCellValue(evt.GetRow(), 1) + " bid?",'Updater',wx.YES_NO | wx.ICON_QUESTION)
        result = dlg.ShowModal()
        if result == wx.ID_YES:
            from chanbeBid import changeBidTb
            changeBidTb(self.GetCellValue(evt.GetRow(), 1), self.GetCellValue(evt.GetRow(), 16))

    evt.Skip() 

谢谢,

【问题讨论】:

    标签: python wxpython progress-bar


    【解决方案1】:

    您可以使用 _thread 模块来创建新线程,并使用 pubsub 来处理线程之间的通信。一种方法如下所示。我在代码中添加了一些 cmets。

    import wx
    import time
    import _thread
    from pubsub import pub
    
    seconds = 10
    
    class MyFrame(wx.Frame):
        def __init__(self):
            """
            Just a button to start counting
            """
            super().__init__(None, title='Counting until...')
            self.panel  = wx.Panel(self)
            self.button = wx.Button(self.panel, label='Count', pos=(50, 50))
            self.button.Bind(wx.EVT_BUTTON, self.OnCount)
    
            ## This will subscribe the window to the message 'Finish counting'.
            ## Thus, everytime the message is broadcast the self.Pass method
            ## will be executed.
            pub.subscribe(self.Pass, 'Finish counting')
    
        def OnCount(self, event):
            dlg = wx.MessageDialog(None, "Do you want to count?", 
                                  style=wx.YES_NO|wx.ICON_QUESTION)
            if dlg.ShowModal() == wx.ID_YES:
                self.count()
            else:
                pass
    
        def count(self):
            ## Creates and starts a new thread that will execute the self.wait
            ## method. Notice that the thread is started before the ProgressDialog
            ## because the ProgressDialog will keep the main thread busy
            _thread.start_new_thread(self.wait, (seconds,))
    
            ## ProgressDialog that will keep running until maxV is reached or
            ## until self.keepGoing is set to False
            maxV = 100
            dlg = wx.ProgressDialog("Progress dialog example",
                                         "An informative message",
                                         maximum = maxV,
                                         parent=self,
                                         style = 0
                                         | wx.PD_APP_MODAL
                                        #| wx.PD_CAN_ABORT
                                        #| wx.PD_CAN_SKIP
                                         | wx.PD_ELAPSED_TIME
                                        #| wx.PD_ESTIMATED_TIME
                                        #| wx.PD_REMAINING_TIME
                                        #| wx.PD_AUTO_HIDE
                                         )
            self.keepGoing = True
            count = 0
            while self.keepGoing and count < maxV:
                count += 1
                wx.MilliSleep(250)
                wx.SafeYield()
                (keepGoing, skip) = dlg.Update(count)
            dlg.Destroy() 
    
        def wait(self, secs):
            ## This is the function that is executed by the new thread
            ## when it finishs the wx.CallAfter method broadcast the message
            ## 'Finish counting' that triggers self.Pass as mentioned above.
            time.sleep(secs)
            wx.CallAfter(pub.sendMessage, 'Finish counting')
    
        def Pass(self):
            ## Changes self.keepGoing to false so the ProgressDialog is destroyed. 
            self.keepGoing = False
    
    if __name__ == "__main__":
        app = wx.App()
        frame = MyFrame()
        frame.Show()
        app.MainLoop()
    

    关于对话框窗口中的进度条要求继续。这可以完成,但您需要构建自定义对话窗口,并且可能使用wx.Gauge 而不是wx.ProgressDialog。您也很可能希望这个自定义窗口是模态的(冻结程序中的所有其他窗口,以便用户必须等待线程中运行的函数完成)。为此,将以下方法添加到自定义对话框类中,

    def ShowModal(self):
        """
        wx.Dialog behavior
        """
        self._disabler = wx.WindowDisabler(self)
        self.Show()
        self.eventLoop = wx.GUIEventLoop()
        self.eventLoop.Run()
    

    并以与正常wx.Dialogcustom_dialog.ShowModal() 相同的方式显示自定义对话框

    【讨论】:

    • 谢谢您的回答,但正如我所说,我从未使用过 Thread。该代码在作为独立运行时有效,但不幸的是我无法将它集成到我现有的脚本中。我的第一行有错误:/
    • 你能给你的应用程序的 MWE 吗?您收到的错误是什么意思?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-19
    • 1970-01-01
    • 2015-04-04
    • 1970-01-01
    • 2023-01-08
    • 2016-12-10
    • 1970-01-01
    相关资源
    最近更新 更多