Starting method after screen has loaded wxpython - python

I'm getting familiar with python / wxpython.
I've created a class for the panel / grid.
But I want to "paint" the grid and only after all is loaded / shown, I want to start to run a method / function to count running processes in Windows. Code snippet:
self.sb.SetStatusText('Initialising application...')
self.SetTitle('Computer Check v0.1')
self.Centre()
self.Show()
self.onStart()
def onStart(self):
self.sb.SetStatusText('Counting processes')
count = 0
for process in c.Win32_Process():
count +=1
self.sb.SetStatusText('Found '+str(count)+' running processes')
but it looks like things are following eachother to fast, meaning that the application is being painted and the "onstart()" is already running...
Another thing is that the application "hangs" during the onstart(), it seems quite heavy to use the WMI...or maybe the code is just crap from my side ;-)
Can't find an event to use to initiate the onstart after the application has loaded.
How to do this in a proper way?
thank you!

You can use wx.CallAfter to run a callable when the wx event loop "has free time", or wx.CallLater to run something after some period of time.
wx.CallAfter(self.onStart)
I do not know if Win32_Process takes a long time, if so, it will certainly block the UI. The best thing would be to start a new thread to perform the computation (Win32_Process), and then for example wx.CallAfter to update the UI. Remember, you may not update the UI from other threads.
When your thread calculates the value, you can for example
def thread_run_function(self):
# perform the calculation...
wx.CallAfter(self.update_ui, calculated_value)
def update_ui(self, calculated_value):
self.some_widget.SetLabel("Value: %s" % calculated_value)
Or:
def thread_run_function(self):
# perform the calculation...
self.calculated_value = calculated_value
wx.CallAfter(self.update_ui)
def update_ui(self):
self.some_widget.SetLabel("Value: %s" % self.calculated_value)

Related

Implementing threading in a Python GTK application (PyGObject) to prevent UI freezing

Simply put, I want to properly implement threading in a Python GTK application. This is in order to prevent UI freezing due to functions/code taking a long time to finish running. Hence, my approach was to move all code which took a long time to run into separate functions, and run them in their separate threads as needed. This however posed a problem when trying to run the functions in sequence.
For example, take a look at the following code:
class Main(Gtk.Window):
def __init__(self):
super().__init__()
self.button = Gtk.Button(label='button')
self.add(self.button)
self.button.connect('clicked', self.main_function)
def threaded_function(self):
time.sleep(20)
print('this is a threaded function')
def first_normal_function(self):
print('this is a normal function')
def second_normal_function(self):
print('this is a normal function')
def main_function(self, widget):
self.first_normal_function()
self.threaded_function()
self.second_normal_function()
Pressing the button starts main_function which then starts 3 functions in sequence. threaded_function represents a function which would take a long time to complete. Running this as is will freeze the UI. Hence it should be threaded as such:
...
...
def main_function(self, widget):
self.first_normal_function()
thread = threading.Thread(target=self.threaded_function)
thread.daemon = True
thread.start()
self.second_normal_function()
What should happen is that the following first_normal_function should run, then threaded_function in a background thread - the UI should remain responsive as the background thread is working. Finally, second_normal_function should run, but only when threaded_function is finished.
The issue with this is that the functions will not run in sequence. The behaviour I am looking for could be achieved by using thread.join() however this freezes the UI.
So I ask, what's the proper way of doing this? This is a general case, however it concerns the general issue of having code which takes a long time to complete in a graphical application, while needing code to run sequentially. Qt deals with this by using signals, and having a QThread emit a finished signal. Does GTK have an equivalent?
I'm aware that this could be partially solved using Queue , with a put() and get() in relevant functions, however I don't understand how to get this to work if the main thread is calling anything other than functions.
EDIT: Given that it's possible to have threaded_function call second_normal_function using GLib.idle_add, let's take an example where in main_function, the second_normal_function call is replaced with a print statement, such that:
def main_function(self, widget):
self.first_normal_function()
thread = threading.Thread(target=self.threaded_function)
thread.daemon = True
thread.start()
print('this comes after the thread is finished')
...
...
...
#some more code here
With GLib.idle_add, the print statement and all the code afterwards would need to be moved into a separate function. Is it possible to avoid moving the print statement into its own function while maintaining sequentiality, such that the print statement remains where it is and still gets called after threaded_function is finished?
Your suggestion on how to do this was very close to the actual solution, but it's indeed not going to work.
In essence, what you'll indeed want to do, is to run the long-running function in a different thread. That'll mean you get 2 threads: one which is running the main event loop that (amongs other things) updates your UI, and another thread which does the long-running logic.
Of course, that bears the question: how do I notify the main thread that some work is done and I want it to react to that? For example, you might want to update the UI while (or after) some complex calculation is going on. For this, you can use GLib.idle_add() from within the other thread. That function takes a single callback as an argument, which it will run as soon as it can ("on idle").
So a possibility to use here, would be something like this:
class Main(Gtk.Window):
def __init__(self):
super().__init__()
self.button = Gtk.Button(label='button')
self.add(self.button)
self.button.connect('clicked', self.main_function)
thread = threading.Thread(target=self.threaded_function)
thread.daemon = True
thread.start()
def threaded_function(self):
# Really intensive stuff going on here
sleep(20)
# We're done, schedule "on_idle" to be called in the main thread
GLib.idle_add(self.on_idle)
# Note, this function will be run in the main loop thread, *not* in this one
def on_idle(self):
second_normal_function()
return GLib.SOURCE_REMOVE # we only want to run once
# ...
For more context, you might want to read the pygobject documentation on threading and concurrency

Running two QThreads simultaneously

My goal for a task is to allow one button press to start two processes, both running simultaneously on different QThreads.
My code is structured like this (simplified)
class Main_Window():
# My UI stuff goes here
class worker1(QtCore.QObject):
def __init__(self):
...
def run1():
...
class worker2(QtCore.QObject):
def __init__(self):
...
def run2():
...
app = QtGui.QApplication(sys.argv)
myapp = Main_Window()
thr1 = QtCore.QThread()
thr2 = QtCore.QThread()
work1 = worker1()
work2 = worker2()
work1.moveToThread(thr1)
work2.moveToThread(thr2)
# I have a signal coming in from main thread
app.connect(myapp, QtCore.SIGNAL('start1'), work1.run1())
app.connect(myapp, QtCore.SIGNAL('start1'), work2.run2())
thr1.start()
thr2.start()
Is this kind of QThread coding incorrect if I want to setup two Qthreads?
I am getting a "Segmentation fault" when I try to start the program, but as soon as I take the second app.connect away, it runs fine.
I was wondering if anyone can tell me where I've gone wrong.
Thanks!
When you connect your signals with:
app.connect(myapp, QtCore.SIGNAL('start1'), work1.run1())
You are actually executing the run function, not just connecting it. You want to leave out the "()" or else python executes the function and tries to connect whatever it returns.
EDIT:
Two more suggestions in response to your comment saying you took out the "()".
First, I've never seen someone rename the run function when using the QtThread class and you may want to try the same code where both run1 and run2 are actually just named "run". Check out this thread for some good example:
How to use QThread correctly in pyqt with moveToThread()?
Second, can you post the actual error? Does it like anything like the one in this thread:
Is this PyQt 4 python bug or wrongly behaving code?

Threading in Python, control taken by the other thread

How do I multi-thread properly in Python?
I am trying to change the simple fork mechanism into a solution using the threading library (I think that forks causes some problems so I'm trying to replace them)
class CustomConsole(cmd.Cmd):
db = DatabaseControl()
bot = Bot(db)
addPoints = AddPointsToActiveUsers(db)
def do_startbot(self, args):
botThread = threading.Thread(target=self.bot.mainLoop(),
name='BotThread')
botThread.daemon = True
botThread.start()
def do_startpoints(self, args):
pointsThread = threading.Thread(target=self.addPoints.addPoints(),
name='PointsThread')
pointsThread.daemon = True
pointsThread.start()
if __name__ == '__main__':
CustomConsole().cmdloop()
Both objects have infinite loops inside, but when i am starting one of them and i can't start the other one as it seems that the the thread is taking control of the terminal.
I think there could be problem with the custom console but I have no idea how to not give control over terminal to the thread but to leave it to the main thread and just run it in background.
In addition I have no idea why, but even if I delete the objects.start() lines, the threads are starting and I have no control over terminal again.
The code formatting is good, I just can't format it here properly

Is it still not enough to simply use threads to update GUI?

For example:
class DemoFrame(wx.Frame):
def __init__(self):
Initializing
...
self.TextA = wx.StaticText(MainPanel, id = -1, label = "TextAOrWhatever")
self.TextB = wx.StaticText(MainPanel, id = -1, label = "TextBOrWhatever")
...
def StaticTextUpdating(self, ObjectName, Message):
ObjectName.SetLabel(Message)
def WorkerA(self):
while True:
Work on something
UpdatingThread = threading.Thread(target = self.StaticTextUpdating, args = (self.TextA, "Something for TextA", ))
UpdatingThread.start()
time.sleep(randomSecs)
def WorkerB(self):
while True:
Work on something
UpdatingThread = threading.Thread(target = self.StaticTextUpdating, args = (self.TextB, "Something for TextB", ))
UpdatingThread.start()
time.sleep(randomSecs)
...
def StartWorking(self):
Spawn WorkerA thread
Spawn WorkerB thread
...
As you can see, I always update StaticText in new threads, and I'm 100% sure at a whatever certain time point there's only one thread updating a specific object, but the problem is, every now and then after running for a while, some objects just disappear. Why is this happening? Does it mean GUI updating is not thread safe? Maybe only one object can be updated at a certain time point?
Added:
OK, wx.CallAfter should be a good solution for above codes. But I got another question, what if a button event and SetLabel happens at the same time? Wouldn't things like this cause troubles although I don't see any?
Most wx methods are not thread-safe. Use wx.CallAfter if you want to invoke a wx method from another thread; replace
ObjectName.SetLabel(Message)
with:
wx.CallAfter(ObjectName.SetLabel, Message)
Edit: Some Background Information
In wx (And in most other UI platforms) all the UI updates get executed in a single thread called main thread (Or UI Thread). This is to make the UI work faster by avoiding the performance hit of thread synchronization.
But the down side of this is that If we write code to update the UI from a different thread the results are undefined. Sometimes it may work, sometimes it may crash, sometimes some other thing may happen. So we should always go to UI thread to do the UI updates. So we use CallAfter function to make UI update function execute in the UI thread.
UI thread in java
UI thread in C#
The main thing to remember is that you shouldn't update anything in wxPython without using a threadsafe method, such as wx.CallAfter, wx.CallLater or wx.PostEvent. See http://wiki.wxpython.org/LongRunningTasks or http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/ for more information.

separate threads in pygtk application

I'm having some problems threading my pyGTK application. I give the thread some time to complete its task, if there is a problem I just continue anyway but warn the user. However once I continue, this thread stops until gtk.main_quit is called. This is confusing me.
The relevant code:
class MTP_Connection(threading.Thread):
def __init__(self, HOME_DIR, username):
self.filename = HOME_DIR + "mtp-dump_" + username
threading.Thread.__init__(self)
def run(self):
#test run
for i in range(1, 10):
time.sleep(1)
print i
..........................
start_time = time.time()
conn = MTP_Connection(self.HOME_DIR, self.username)
conn.start()
progress_bar = ProgressBar(self.tree.get_widget("progressbar"),
update_speed=100, pulse_mode=True)
while conn.isAlive():
while gtk.events_pending():
gtk.main_iteration()
if time.time() - start_time > 5:
self.write_info("problems closing connection.")
break
#after this the program continues normally, but my conn thread stops
Firstly, don't subclass threading.Thread, use Thread(target=callable).start().
Secondly, and probably the cause of your apparent block is that gtk.main_iteration takes a parameter block, which defaults to True, so your call to gtk.main_iteration will actually block when there are no events to iterate on. Which can be solved with:
gtk.main_iteration(block=False)
However, there is no real explanation why you would use this hacked up loop rather than the actual gtk main loop. If you are already running this inside a main loop, then I would suggest that you are doing the wrong thing. I can expand on your options if you give us a bit more detail and/or the complete example.
Thirdly, and this only came up later: Always always always always make sure you have called gtk.gdk.threads_init in any pygtk application with threads. GTK+ has different code paths when running threaded, and it needs to know to use these.
I wrote a small article about pygtk and threads that offers you a small abstraction so you never have to worry about these things. That post also includes a progress bar example.

Categories