473,498 Members | 1,992 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Showing a message dialog from a thread using GTK

6 New Member
I have a worker thread, and when the worker is done I want it to show a popup dialog. The sample application below demonstrates this. There are two buttons: a "Show dialog" button which immediately displays a dialog, and a "Do work" button which launches a worker thread. The worker thread simulates some work by sleeping a moment, and then attempts to display a dialog.

The problem is that when the worker thread attempts to display the popup the program freezes. What is the difference between showing a dialog from the event handler thread in the "connected" button2_click method, and showing a dialog in the run method of a custom thread?

Expand|Select|Wrap|Line Numbers
  1. import gobject
  2. import gtk
  3. import threading
  4. import time
  5.  
  6. class MessageBox(gtk.MessageDialog):
  7.     def __init__(self, parent, message):
  8.         gtk.MessageDialog.__init__(self, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  9.                                 gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message)
  10.         self.set_default_response(gtk.RESPONSE_OK)
  11.         self.connect('response', self._handle_clicked)
  12.  
  13.     def _handle_clicked(self, *args):
  14.         self.destroy()
  15.  
  16. class TestThread(threading.Thread):
  17.     def __init__(self, mainview):
  18.         threading.Thread.__init__(self)
  19.         self.mainview = mainview
  20.  
  21.     def run(self):
  22.         print "Some work is done here..."
  23.         time.sleep(3)
  24.         dialog = MessageBox(self.mainview, "Work completed")
  25.         dialog.show_all()
  26.         print "Work complete"
  27.  
  28. class MainView(gtk.Window):
  29.     def __init__(self):
  30.         gtk.Window.__init__(self)
  31.         self.connect('delete_event', self.handle_window_delete_event)
  32.         self.connect('destroy', self.quit)
  33.  
  34.         button1 = gtk.Button("Do work")
  35.         button1.connect('clicked', self.button1_click)
  36.         button2 = gtk.Button("Show dialog")
  37.         button2.connect('clicked', self.button2_click)
  38.         box = gtk.VBox()
  39.         box.pack_start(button1)
  40.         box.pack_start(button2)
  41.         self.add(box)
  42.  
  43.     def quit(self, *args):
  44.         gtk.main_quit()
  45.  
  46.     def handle_window_delete_event(self, *args):
  47.         return False
  48.  
  49.     def button1_click(self, *args):
  50.         worker = TestThread(self)
  51.         worker.start()
  52.  
  53.     def button2_click(self, *args):
  54.         dialog = MessageBox(self, "Just a message!")
  55.         dialog.show_all()
  56.  
  57. if __name__ == "__main__":
  58.     gobject.threads_init()
  59.     main = MainView()
  60.     main.show_all()
  61.     gtk.main()
  62.  
Oct 3 '07 #1
6 13463
ilikepython
844 Recognized Expert Contributor
I have a worker thread, and when the worker is done I want it to show a popup dialog. The sample application below demonstrates this. There are two buttons: a "Show dialog" button which immediately displays a dialog, and a "Do work" button which launches a worker thread. The worker thread simulates some work by sleeping a moment, and then attempts to display a dialog.

The problem is that when the worker thread attempts to display the popup the program freezes. What is the difference between showing a dialog from the event handler thread in the "connected" button2_click method, and showing a dialog in the run method of a custom thread?

Expand|Select|Wrap|Line Numbers
  1. import gobject
  2. import gtk
  3. import threading
  4. import time
  5.  
  6. class MessageBox(gtk.MessageDialog):
  7.     def __init__(self, parent, message):
  8.         gtk.MessageDialog.__init__(self, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  9.                                 gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message)
  10.         self.set_default_response(gtk.RESPONSE_OK)
  11.         self.connect('response', self._handle_clicked)
  12.  
  13.     def _handle_clicked(self, *args):
  14.         self.destroy()
  15.  
  16. class TestThread(threading.Thread):
  17.     def __init__(self, mainview):
  18.         threading.Thread.__init__(self)
  19.         self.mainview = mainview
  20.  
  21.     def run(self):
  22.         print "Some work is done here..."
  23.         time.sleep(3)
  24.         dialog = MessageBox(self.mainview, "Work completed")
  25.         dialog.show_all()
  26.         print "Work complete"
  27.  
  28. class MainView(gtk.Window):
  29.     def __init__(self):
  30.         gtk.Window.__init__(self)
  31.         self.connect('delete_event', self.handle_window_delete_event)
  32.         self.connect('destroy', self.quit)
  33.  
  34.         button1 = gtk.Button("Do work")
  35.         button1.connect('clicked', self.button1_click)
  36.         button2 = gtk.Button("Show dialog")
  37.         button2.connect('clicked', self.button2_click)
  38.         box = gtk.VBox()
  39.         box.pack_start(button1)
  40.         box.pack_start(button2)
  41.         self.add(box)
  42.  
  43.     def quit(self, *args):
  44.         gtk.main_quit()
  45.  
  46.     def handle_window_delete_event(self, *args):
  47.         return False
  48.  
  49.     def button1_click(self, *args):
  50.         worker = TestThread(self)
  51.         worker.start()
  52.  
  53.     def button2_click(self, *args):
  54.         dialog = MessageBox(self, "Just a message!")
  55.         dialog.show_all()
  56.  
  57. if __name__ == "__main__":
  58.     gobject.threads_init()
  59.     main = MainView()
  60.     main.show_all()
  61.     gtk.main()
  62.  
I'm not sure if this is the problem, but usually, child threads shouldn't do anything with the GUI in the maiin thread. Threads usually use the queue module to communicate between threads. What you need is a callback to listen from events from the queue in the main thread and the child thread to put some data on the queue.
Oct 3 '07 #2
bartonc
6,596 Recognized Expert Expert
In some frameworks, threads are allowed to post events to the event queue.
Using this technique, your main thread (which is usually the only thread allow to use GUI elements) can pop up the dialog. I'm not sure if this is also true of GTK, though.
Oct 3 '07 #3
kdikert
6 New Member
Thanks for the hints.I was expecting something like this, and it seems somewhat reasonable that the toolkit allows certain operatinons only from the main thread. I tested the callback approach, but i couldn't get it to work either. Here is some sample code for activating callbacks:

Expand|Select|Wrap|Line Numbers
  1. ...
  2. class TestThread(threading.Thread):
  3.     def __init__(self, mainview):
  4.         threading.Thread.__init__(self)
  5.         self.mainview = mainview
  6.  
  7.     def run(self):
  8.         print "Some work is done here..."
  9.         time.sleep(3)
  10.         print "worker " + str(threading.currentThread())
  11.         # Perform some action that will cause a 'notify' signal to be emitted
  12.         mainview.show_dialog = True
  13.         self.mainview.set_title("x")
  14.  
  15. ...
  16.  
  17. class MainView(gtk.Window):
  18.     def __init__(self):
  19.         gtk.Window.__init__(self)
  20.         self.connect('notify', self.do_notify)
  21.         self.show_dialog = False
  22. ...        
  23.     def do_notify(self, *args):
  24.         if self.show_dialog:
  25.             print "notify " + str(threading.currentThread())
  26.             dialog = MessageBox(self.mainview, "Work completed")
  27.             dialog.show_all()
  28. ...
  29.  
This did not work because the 'notify' signal is called in the same thread that performs the action that triggers the signal. The application will still freeze. Do you have any ideas for emitting a singnal in a way that will make it to be called in the main thread (running the gtk.main() loop)?
Oct 4 '07 #4
bartonc
6,596 Recognized Expert Expert
Thanks for the hints.I was expecting something like this, and it seems somewhat reasonable that the toolkit allows certain operatinons only from the main thread. I tested the callback approach, but i couldn't get it to work either. Here is some sample code for activating callbacks:

Expand|Select|Wrap|Line Numbers
  1. ...
  2. class TestThread(threading.Thread):
  3.     def __init__(self, mainview):
  4.         threading.Thread.__init__(self)
  5.         self.mainview = mainview
  6.  
  7.     def run(self):
  8.         print "Some work is done here..."
  9.         time.sleep(3)
  10.         print "worker " + str(threading.currentThread())
  11.         # Perform some action that will cause a 'notify' signal to be emitted
  12.         mainview.show_dialog = True
  13.         self.mainview.set_title("x")
  14.  
  15. ...
  16.  
  17. class MainView(gtk.Window):
  18.     def __init__(self):
  19.         gtk.Window.__init__(self)
  20.         self.connect('notify', self.do_notify)
  21.         self.show_dialog = False
  22. ...        
  23.     def do_notify(self, *args):
  24.         if self.show_dialog:
  25.             print "notify " + str(threading.currentThread())
  26.             dialog = MessageBox(self.mainview, "Work completed")
  27.             dialog.show_all()
  28. ...
  29.  
This did not work because the 'notify' signal is called in the same thread that performs the action that triggers the signal. The application will still freeze. Do you have any ideas for emitting a singnal in a way that will make it to be called in the main thread (running the gtk.main() loop)?
There is probably an event mechanism for this but in the mean time you could:
Use one of the "thread-safe" mechanisms provided by the threading module (like Event()) or a Queue.Queue() and poll the state of the thread from your main loop using a timer. That's what I do in wxPython, anyway. For that matter, you could just poll t.isAlive() where t is a reference to your thread.
Oct 4 '07 #5
kdikert
6 New Member
There is probably an event mechanism for this but in the mean time you could:
Use one of the "thread-safe" mechanisms provided by the threading module (like Event()) or a Queue.Queue() and poll the state of the thread from your main loop using a timer. That's what I do in wxPython, anyway. For that matter, you could just poll t.isAlive() where t is a reference to your thread.
As I see it, the Queue would not provide any help here, as it is intended for exchanging data between threads. The problem is rather that the thing I want to do can not be done in the worker thread, and so far I did not find the correct way of scheduling my own events to be executed in the main loop. It's the Widget.show_all() call that jams the system if it is not called in the GTK main loop.

However, now I found a solution to the problem. A recent post in the GTK mailing list relates to the same problem: http://mail.gnome.org/archives/gtk-a.../msg00034.html There is no specific example in the message, but here is mine:

Expand|Select|Wrap|Line Numbers
  1. class MessageBox(gtk.MessageDialog):
  2.     def __init__(self, parent, message):
  3.         gtk.MessageDialog.__init__(self, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message)
  4.         self.set_default_response(gtk.RESPONSE_OK)
  5.         self.connect('response', self._handle_clicked)
  6.  
  7.     def _handle_clicked(self, *args):
  8.         self.destroy()
  9.  
  10.     def show_dialog(self):
  11.         gobject.timeout_add(0, self._do_show_dialog)
  12.  
  13.     def _do_show_dialog(self):
  14.         self.show_all()
  15.         return False
  16.  
  17. ...
  18.  
  19. class TestThread(threading.Thread):
  20.     def __init__(self, mainview):
  21.         threading.Thread.__init__(self)
  22.         self.mainview = mainview
  23.  
  24.     def run(self):
  25.         time.sleep(3)
  26.         dialog = MessageBox(self.mainview, "Work completed")
  27.         dialog.show_dialog()
  28. ...
  29.  
The MessageBox.show_dialog() is now made thread safe from GTK point of view. The gobject.timeout_add() schedules a function to be called from the GTK main loop. The GTK main loop will call MessageBox._do_show_dialog() which will make the dialog visible. The False return value must be included, as GTK would otherwise call the function repeatedly. Now I can call dialog.show_dialog() directly from the worker thread.
Oct 4 '07 #6
chipselect
1 New Member
With C, I use "g_idle_add()", passing a function pointer and parameters, because I hear that GTK is thread aware, not thread safe.

GLib is thread safe (with "if (!g_thread_supported ()) g_thread_init (NULL);" in init) and solve this problem for me.
May 28 '09 #7

Sign in to post your reply or Sign up for a free account.

Similar topics

3
2829
by: Andrew Baker | last post by:
OK this has me perplexed, puzzled and bamboozled! I have a remoting service which I displayed a message box in. I then wondered what would happen if a client made a call to the service while the...
8
3259
by: Raed Sawalha | last post by:
I have form with progress bar ,when application begin processing and progress bar moving if I minimized the form and try to restore it ,it is not showing until the processing completed ,how can I...
5
1865
by: John | last post by:
Hi How can I show a dialog from within the main form? frmdialog.show? Thanks Regards
3
2226
by: mccoyn | last post by:
When I have a long process to run I can create a new thread to run it and create a modal dialog on my GUI thread. The modal dialog prevents any messages (like button clicks) from working on my...
2
2052
by: Lars Netzel | last post by:
Hi I have a Form that on Form_Load() does some heavy database reading and I want to show that as a progressbar ontop of the main window.. I want to create a smaller Form with a progressbar.....
0
1147
by: Chukkalove | last post by:
I have a thread that sits polling a smart card status for the lifetime of an application using WinSCard API. It also performs asynchronous read and writes to the card as required and uses...
1
1629
by: Claire | last post by:
Hi I need to set my main form as the owner of an error dialog box shown when there's an exception in a background thread. This is to make sure that the error form is closed down if the user pulls...
1
3092
by: Roland | last post by:
Hello, I am writing modal dialog box to display progress of downloading file. I am starting download of a file in constructor of dialog using some asynchronous method call which returns me an...
2
3419
by: pandehrushikesh | last post by:
I am doing setup project in VS 2008. I used custom action to select file from local drives. On the button click of custom action form, I am launching Open file dialog as ...
0
7125
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
7002
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7203
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
6885
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
5462
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
4908
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4588
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3081
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
290
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.