0

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.

swanux
  • 67
  • 7

1 Answers1

0

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

Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60
  • Thank you for your answer! The keep_going variable isn't required because g.th is the name of the other thread. If it ends this will end too. But with keep_going it goes forever. Also the modifications didn't help, the window still doesn't even appear on the screen on button press. I can only see in the terminal that the 'HEEYY' thing works good. – swanux Jul 16 '19 at 19:26
  • It was an example, given that you have posted only enough code for us to guess! https://stackoverflow.com/help/minimal-reproducible-example – Rolf of Saxony Jul 17 '19 at 08:49
  • Edited the question to contain (I thin) all of the necessary code. – swanux Jul 17 '19 at 09:57
  • Edited again with a fully working code (only need proper common.py in the same directory), and added code to my_thread2 to show a test dialog, and it shows up correctly along with the text in terminal. – swanux Jul 17 '19 at 15:39
  • Excuse my ignorance but what/where is `common.py` – Rolf of Saxony Jul 17 '19 at 16:24
  • It contains some important configuration and functions for the program, but this is irrelevant for this problem. For this part of the code, common.py only needs to contain **th = 'common**' – swanux Jul 17 '19 at 17:14
  • Thank you for your help! Now it works as it's expected and it's a lot shorter! Thank you! – swanux Jul 17 '19 at 18:26
  • @swanux Given that `apt update` gives a running commentary on its progress, if you used `subprocess.Popen` rather than `os.system` you could provide an actual progress bar rather than just a pulse bar. – Rolf of Saxony Jul 18 '19 at 08:23
  • How could I do that? I mean the progress bar gets the required information from where? Can you show me an example please? – swanux Jul 18 '19 at 08:38
  • See https://stackoverflow.com/questions/89228/calling-an-external-command-in-python/92395#92395 check the 3rd answer and its first comment. You can parse the output looking for known progress markers and update the progress bar appropriately. – Rolf of Saxony Jul 18 '19 at 08:44
  • Good idea! Thank you! One question according to this. How does a "real" progress bar looks like in wxpython? (What is its Syntax?) – swanux Jul 18 '19 at 08:53
  • Use `wx.Gauge` or what you have currently with `dlg.Update(value, newmsg="")` – Rolf of Saxony Jul 18 '19 at 09:28
  • The output from subprocess looks like this: `b'Hit:13 http://us.archive.ubuntu.com/ubuntu disco-backports InRelease\n' b'Fetched 3,674 B in 1s (2,715 B/s)\n' b'Reading package lists...\n' b'Building dependency tree...\n' b'Reading state information...\n' b"69 packages can be upgraded. Run 'apt list --upgradable' to see them.\n" b'' Exiting Thread-1` (Just the and of the output) So what can I assign to `value` from there? – swanux Jul 18 '19 at 11:45
  • Yes, sorry about that! The progress information when "working", "reading the package lists" and "Building dependency tree" which you see flicking on the screen, simply isn't caught by checking stdout or stderr. So, 1 I don't know how to capture it, 2 I don't know where that info is coming from, perhaps another thread. It was a nice idea but unless someone else spots this and knows the answer, as to how to capture it, it isn't going to work. Sorry! – Rolf of Saxony Jul 18 '19 at 18:13
  • Well, no problem. The idea is good, and maybe I'll find a solution later. But thanks for the help! – swanux Jul 19 '19 at 09:26
  • Do you have any idea regarding to this question? https://stackoverflow.com/questions/57119935/command-not-works-in-subprocess-or-os-popen-but-works-in-terminal# – swanux Jul 19 '19 at 22:22