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? -
import gobject
-
import gtk
-
import threading
-
import time
-
-
class MessageBox(gtk.MessageDialog):
-
def __init__(self, parent, message):
-
gtk.MessageDialog.__init__(self, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
-
gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message)
-
self.set_default_response(gtk.RESPONSE_OK)
-
self.connect('response', self._handle_clicked)
-
-
def _handle_clicked(self, *args):
-
self.destroy()
-
-
class TestThread(threading.Thread):
-
def __init__(self, mainview):
-
threading.Thread.__init__(self)
-
self.mainview = mainview
-
-
def run(self):
-
print "Some work is done here..."
-
time.sleep(3)
-
dialog = MessageBox(self.mainview, "Work completed")
-
dialog.show_all()
-
print "Work complete"
-
-
class MainView(gtk.Window):
-
def __init__(self):
-
gtk.Window.__init__(self)
-
self.connect('delete_event', self.handle_window_delete_event)
-
self.connect('destroy', self.quit)
-
-
button1 = gtk.Button("Do work")
-
button1.connect('clicked', self.button1_click)
-
button2 = gtk.Button("Show dialog")
-
button2.connect('clicked', self.button2_click)
-
box = gtk.VBox()
-
box.pack_start(button1)
-
box.pack_start(button2)
-
self.add(box)
-
-
def quit(self, *args):
-
gtk.main_quit()
-
-
def handle_window_delete_event(self, *args):
-
return False
-
-
def button1_click(self, *args):
-
worker = TestThread(self)
-
worker.start()
-
-
def button2_click(self, *args):
-
dialog = MessageBox(self, "Just a message!")
-
dialog.show_all()
-
-
if __name__ == "__main__":
-
gobject.threads_init()
-
main = MainView()
-
main.show_all()
-
gtk.main()
-
6 13449
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? -
import gobject
-
import gtk
-
import threading
-
import time
-
-
class MessageBox(gtk.MessageDialog):
-
def __init__(self, parent, message):
-
gtk.MessageDialog.__init__(self, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
-
gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message)
-
self.set_default_response(gtk.RESPONSE_OK)
-
self.connect('response', self._handle_clicked)
-
-
def _handle_clicked(self, *args):
-
self.destroy()
-
-
class TestThread(threading.Thread):
-
def __init__(self, mainview):
-
threading.Thread.__init__(self)
-
self.mainview = mainview
-
-
def run(self):
-
print "Some work is done here..."
-
time.sleep(3)
-
dialog = MessageBox(self.mainview, "Work completed")
-
dialog.show_all()
-
print "Work complete"
-
-
class MainView(gtk.Window):
-
def __init__(self):
-
gtk.Window.__init__(self)
-
self.connect('delete_event', self.handle_window_delete_event)
-
self.connect('destroy', self.quit)
-
-
button1 = gtk.Button("Do work")
-
button1.connect('clicked', self.button1_click)
-
button2 = gtk.Button("Show dialog")
-
button2.connect('clicked', self.button2_click)
-
box = gtk.VBox()
-
box.pack_start(button1)
-
box.pack_start(button2)
-
self.add(box)
-
-
def quit(self, *args):
-
gtk.main_quit()
-
-
def handle_window_delete_event(self, *args):
-
return False
-
-
def button1_click(self, *args):
-
worker = TestThread(self)
-
worker.start()
-
-
def button2_click(self, *args):
-
dialog = MessageBox(self, "Just a message!")
-
dialog.show_all()
-
-
if __name__ == "__main__":
-
gobject.threads_init()
-
main = MainView()
-
main.show_all()
-
gtk.main()
-
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.
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.
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: -
...
-
class TestThread(threading.Thread):
-
def __init__(self, mainview):
-
threading.Thread.__init__(self)
-
self.mainview = mainview
-
-
def run(self):
-
print "Some work is done here..."
-
time.sleep(3)
-
print "worker " + str(threading.currentThread())
-
# Perform some action that will cause a 'notify' signal to be emitted
-
mainview.show_dialog = True
-
self.mainview.set_title("x")
-
-
...
-
-
class MainView(gtk.Window):
-
def __init__(self):
-
gtk.Window.__init__(self)
-
self.connect('notify', self.do_notify)
-
self.show_dialog = False
-
...
-
def do_notify(self, *args):
-
if self.show_dialog:
-
print "notify " + str(threading.currentThread())
-
dialog = MessageBox(self.mainview, "Work completed")
-
dialog.show_all()
-
...
-
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)?
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: -
...
-
class TestThread(threading.Thread):
-
def __init__(self, mainview):
-
threading.Thread.__init__(self)
-
self.mainview = mainview
-
-
def run(self):
-
print "Some work is done here..."
-
time.sleep(3)
-
print "worker " + str(threading.currentThread())
-
# Perform some action that will cause a 'notify' signal to be emitted
-
mainview.show_dialog = True
-
self.mainview.set_title("x")
-
-
...
-
-
class MainView(gtk.Window):
-
def __init__(self):
-
gtk.Window.__init__(self)
-
self.connect('notify', self.do_notify)
-
self.show_dialog = False
-
...
-
def do_notify(self, *args):
-
if self.show_dialog:
-
print "notify " + str(threading.currentThread())
-
dialog = MessageBox(self.mainview, "Work completed")
-
dialog.show_all()
-
...
-
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.
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: -
class MessageBox(gtk.MessageDialog):
-
def __init__(self, parent, message):
-
gtk.MessageDialog.__init__(self, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message)
-
self.set_default_response(gtk.RESPONSE_OK)
-
self.connect('response', self._handle_clicked)
-
-
def _handle_clicked(self, *args):
-
self.destroy()
-
-
def show_dialog(self):
-
gobject.timeout_add(0, self._do_show_dialog)
-
-
def _do_show_dialog(self):
-
self.show_all()
-
return False
-
-
...
-
-
class TestThread(threading.Thread):
-
def __init__(self, mainview):
-
threading.Thread.__init__(self)
-
self.mainview = mainview
-
-
def run(self):
-
time.sleep(3)
-
dialog = MessageBox(self.mainview, "Work completed")
-
dialog.show_dialog()
-
...
-
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.
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.
Sign in to post your reply or Sign up for a free account.
Similar topics
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...
|
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...
|
by: John |
last post by:
Hi
How can I show a dialog from within the main form? frmdialog.show?
Thanks
Regards
|
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...
|
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.....
|
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...
|
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...
|
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...
|
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
...
|
by: ryjfgjl |
last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
|
by: taylorcarr |
last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: aa123db |
last post by:
Variable and constants
Use var or let for variables and const fror constants.
Var foo ='bar';
Let foo ='bar';const baz ='bar';
Functions
function $name$ ($parameters$) {
}
...
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
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...
|
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
|
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...
|
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...
| |