473,378 Members | 1,571 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,378 software developers and data experts.

Showing a message dialog from a thread using GTK

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 13445
ilikepython
844 Expert 512MB
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 Expert 4TB
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
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 Expert 4TB
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
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
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
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
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
by: John | last post by:
Hi How can I show a dialog from within the main form? frmdialog.show? Thanks Regards
3
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
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
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
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
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
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 ...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 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 former...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

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.