Откройте индикатор выполнения, пока не закончится функциональное задание - PullRequest
1 голос
/ 21 мая 2019

У меня есть прослушиватель событий по двойному левому щелчку внутри 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() 

Спасибо,

1 Ответ

1 голос
/ 21 мая 2019

Вы можете использовать модуль _thread для создания нового потока и pubsub для управления связью между потоками.Один из способов сделать это показан ниже.Я добавил несколько комментариев к коду.

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.Dialog, custom_dialog.ShowModal()

...