Search code examples
python-3.xprogress-barprogressdialogwxpython

How to make pulsing progress bar in wxpython when running command?


I'd like to indicate that my program is running and didn't freeze with a pulsing progress bar. The command that would run in the background is this:

os.system('apt install program etc...')

It'll start on button press and I'd like to show a popup progress dialog during the process.

Here's the code of the releated part:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import wx
import threading
import common as g


class myThread (threading.Thread):
    def __init__(self, threadID, name):
       threading.Thread.__init__(self)
       self.threadID = threadID
       self.name = name
    def run(self):
       print ("Starting " + self.name)
       my_thread()
       print ("Exiting " + self.name)

class myThread2 (threading.Thread):
    def __init__(self, threadID, name):
       threading.Thread.__init__(self)
       self.threadID = threadID
       self.name = name
    def run(self):
       print ("Starting " + self.name)
       my_thread2()
       print ("Exiting " + self.name)

def my_thread():
     os.system('apt update')

def my_thread2():
    dlg = wx.ProgressDialog('Test', 'Please wait..', style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_CAN_ABORT | wx.STAY_ON_TOP)
    test = OtherFrame(title='progres')
    counter = 1
    while g.th.isAlive():
        print('HEEYY')
        wx.MilliSleep(300)
        dlg.Pulse("Doing computation %d"%counter)
        test.Show()
        counter += 1
class OtherFrame(wx.Frame):

    def __init__(self, title, parent=None):
        wx.Frame.__init__(self, parent=parent, title=title, size=(700, 400))
        self.Centre()
        self.InitUI()
        self.Show()

    def InitUI(self):

        gs = wx.GridSizer(1, 1, 7, 7)
        update = wx.Button(self,label = 'Check for  system Updates')

        gs.Add(update,28,wx.EXPAND)

        update.Bind(wx.EVT_BUTTON, self.OnUpdate)

        self.SetSizer(gs)

    def OnUpdate(self, e):

        g.th = myThread(1, "Thread-1")
        thread2 = myThread2(2, "Thread-2")
        thread2.start()
        g.th.start()
        g.th.join()
        thread2.join()

def main():

    app = wx.App()
    f1 = OtherFrame(title='frame')
    f1.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

The text 'HEEYY' appears in the right time on the right place, but the dialog doesn't show up.


Solution

  • You appear to be trying to use 1 thread to determine if the other one is still running.
    There is a simpler way, see below:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import os
    import wx
    import threading
    #import common as g
    
    class myThread (threading.Thread):
        def __init__(self, threadID, name):
           threading.Thread.__init__(self)
           self.threadID = threadID
           self.name = name
        def run(self):
           print ("Starting " + self.name)
           os.system('apt update')
           print ("Exiting " + self.name)
    
    class OtherFrame(wx.Frame):
    
        def __init__(self, title, parent=None):
            wx.Frame.__init__(self, parent=parent, title=title, size=(700, 400))
            self.Centre()
            self.InitUI()
            self.Show()
    
        def InitUI(self):
            gs = wx.GridSizer(1, 1, 7, 7)
            update = wx.Button(self,label = 'Check for  system Updates')
            gs.Add(update,28,wx.EXPAND)
            update.Bind(wx.EVT_BUTTON, self.OnUpdate)
            self.SetSizer(gs)
    
        def OnUpdate(self, e):
            t1 = myThread(1, "Thread-1")
            t1.start()
            counter = 0
            dlg = wx.ProgressDialog('Test', 'Please wait..', style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_CAN_ABORT | wx.STAY_ON_TOP)
            while t1.isAlive():
                print('HEEYY')
                wx.MilliSleep(300)
                dlg.Pulse("Doing computation %d"%counter)
                wx.GetApp().Yield()
                counter += 1
            del dlg
            t1.join()
    
    def main():
        app = wx.App()
        f1 = OtherFrame(title='frame')
        f1.Show()
        app.MainLoop()
    
    if __name__ == '__main__':
        main()
    

    enter image description here