|
1
by Gary van der Merwe
Initial commit. |
1 |
#!/usr/bin/env python
|
2 |
||
3 |
import sys |
|
4 |
import threading |
|
5 |
import time |
|
6 |
from PyQt4 import QtCore, QtGui |
|
7 |
||
8 |
main_event_loop = None |
|
|
4
by Gary van der Merwe
Don't send signals if not necessary. |
9 |
main_tread = threading.currentThread() |
10 |
gui_thread = None |
|
11 |
||
12 |
def runs_in_gui_thread(func): |
|
13 |
def runs_in_gui_thread_decorate(*args, **kargs): |
|
14 |
run_in_thread(gui_thread, gui_thread.app, func, *args, **kargs) |
|
15 |
return runs_in_gui_thread_decorate |
|
16 |
||
17 |
def runs_in_main_thread(func): |
|
18 |
def runs_in_main_thread_decorate(*args, **kargs): |
|
19 |
run_in_thread(main_tread, main_event_loop, func, *args, **kargs) |
|
20 |
return runs_in_main_thread_decorate |
|
21 |
||
22 |
def run_in_thread(thread, signal_object, func, *args, **kargs): |
|
23 |
current_thread = threading.currentThread() |
|
24 |
if not current_thread == thread: |
|
25 |
print 'Signal sent from %s to %s to run %s' % ( |
|
26 |
current_thread.name, thread.name, func.__name__) |
|
27 |
signal_object.emit(QtCore.SIGNAL("run_func"), func, args, kargs) |
|
28 |
else: |
|
29 |
func(*args, **kargs) |
|
30 |
||
|
1
by Gary van der Merwe
Initial commit. |
31 |
|
32 |
def run_func(func, args, kargs): |
|
33 |
func(*args, **kargs) |
|
34 |
||
35 |
class GUIThread(threading.Thread): |
|
36 |
app = None |
|
37 |
app_created = threading.Event() |
|
38 |
main_event_loop = None |
|
39 |
||
40 |
def __init__(self, main_event_loop_created, |
|
41 |
start_func, start_func_args, start_func_kargs, |
|
42 |
*args, **kargs): |
|
43 |
threading.Thread.__init__(self, *args, **kargs) |
|
44 |
self.main_event_loop_created = main_event_loop_created |
|
45 |
self.start_func = start_func |
|
46 |
self.start_func_args = start_func_args |
|
47 |
self.start_func_kargs = start_func_kargs |
|
48 |
||
49 |
def run(self): |
|
50 |
# uncomment to test for a slow QApplication start
|
|
51 |
#time.sleep(3)
|
|
52 |
self.app = QtGui.QApplication(sys.argv) |
|
53 |
self.app_created.set() |
|
|
4
by Gary van der Merwe
Don't send signals if not necessary. |
54 |
self.app.connect(self.app, QtCore.SIGNAL('run_func'), run_func) |
|
1
by Gary van der Merwe
Initial commit. |
55 |
|
56 |
main_event_loop_created.wait() |
|
57 |
# Not setting the return val for this func results in the window not
|
|
58 |
# showing. I don't understand why. It is possible to have a list
|
|
59 |
# of windows work.
|
|
60 |
win = self.start_func(*self.start_func_args, **self.start_func_kargs) |
|
61 |
||
62 |
ret = self.app.exec_() |
|
63 |
self.main_event_loop.exit(ret) |
|
|
5
by Gary van der Merwe
Fix segfault by deleting app in the gui_thread. |
64 |
del self.app |
|
1
by Gary van der Merwe
Initial commit. |
65 |
|
66 |
def command_run(): |
|
67 |
print_where() |
|
68 |
win = CommandWindow() |
|
69 |
win.show() |
|
70 |
return win |
|
71 |
||
72 |
def print_where(): |
|
73 |
func_name = sys._getframe(1).f_code.co_name |
|
74 |
thread_name = threading.currentThread().name |
|
75 |
print '%s in %s' % (func_name, thread_name) |
|
76 |
||
77 |
||
78 |
class CommandWindow(QtGui.QLabel): |
|
79 |
def __init__(self, *args, **kargs): |
|
80 |
QtGui.QLabel.__init__(self, *args, **kargs) |
|
|
3
by Gary van der Merwe
Resize. |
81 |
self.resize(QtCore.QSize(300, 20)) |
|
1
by Gary van der Merwe
Initial commit. |
82 |
|
83 |
def show(self): |
|
84 |
QtGui.QWidget.show(self) |
|
|
2
by Gary van der Merwe
Don't need timer to run load. |
85 |
self.load() |
|
1
by Gary van der Merwe
Initial commit. |
86 |
|
|
4
by Gary van der Merwe
Don't send signals if not necessary. |
87 |
@runs_in_main_thread
|
|
1
by Gary van der Merwe
Initial commit. |
88 |
def load(self): |
89 |
print_where() |
|
90 |
self.get_text() |
|
91 |
||
|
4
by Gary van der Merwe
Don't send signals if not necessary. |
92 |
@runs_in_main_thread
|
|
1
by Gary van der Merwe
Initial commit. |
93 |
def get_text(self): |
94 |
print_where() |
|
95 |
self.got_text('Hello World.') |
|
96 |
||
|
4
by Gary van der Merwe
Don't send signals if not necessary. |
97 |
@runs_in_gui_thread
|
|
1
by Gary van der Merwe
Initial commit. |
98 |
def got_text(self, text): |
99 |
print_where() |
|
100 |
self.setText(text) |
|
101 |
||
102 |
||
103 |
if __name__ == '__main__': |
|
104 |
main_event_loop_created = threading.Event() |
|
105 |
gui_thread = GUIThread(main_event_loop_created, command_run, [], {}, name='GUIThread') |
|
106 |
gui_thread.start() |
|
107 |
||
108 |
# We don't want to create this event loop before the app is created in
|
|
109 |
# the gui thread.
|
|
110 |
gui_thread.app_created.wait() |
|
111 |
||
112 |
# this fails because it's not in the GUI Thread
|
|
113 |
#win = QtGui.QWidget()
|
|
114 |
#win.show()
|
|
115 |
||
116 |
main_event_loop = QtCore.QEventLoop() |
|
117 |
main_event_loop.connect(main_event_loop, QtCore.SIGNAL('run_func'), run_func) |
|
118 |
main_event_loop_created.set() |
|
119 |
||
120 |
gui_thread.main_event_loop = main_event_loop |
|
121 |
ret = main_event_loop.exec_() |
|
122 |
gui_thread.join() |
|
123 |
sys.exit(ret) |
|
124 |
||
125 |
||
126 |