-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrunnables.py
144 lines (108 loc) · 4.74 KB
/
runnables.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import math
import time
import sys
from PySide2 import QtWidgets as qtw
from PySide2 import QtCore as qtc
from PySide2 import QtGui as qtg
class MyRunnableSignals(qtc.QObject):
# We can choose any name that we want since we will manually emit them
# from our own QRunnable
started = qtc.Signal()
completed = qtc.Signal((int, bool))
progress = qtc.Signal(int)
failed = qtc.Signal(str)
class MyRunnable(qtc.QRunnable):
"""A Runnable is a simpler version of a QThread, with a similar interface.
A QRunnable doesn't have an
It doesn't offer signals by default, that's why we're creating our own.
For easy stuff, a runnable it's more than enough!
"""
def __init__(self, my_number):
super(MyRunnable, self).__init__()
self.my_number = my_number
self.signals = MyRunnableSignals()
def run(self):
"""This will be automatically called when it's time!
"""
self.signals.started.emit()
try:
# Let's check if a num is a square of 2
decimals, integer = math.modf(math.log(self.my_number, 2))
# A heavy and long calculation could happen here
for i in range(100):
self.signals.progress.emit(i)
time.sleep(0.05)
if decimals == 0.0:
# We can send different variable types from our signals
# Check the signal definition in MyRunnableSignals
self.signals.completed.emit(self.my_number, True)
else:
self.signals.completed.emit(self.my_number, False)
except Exception as err:
print 'error: %s' % err
self.signals.failed.emit('QRunnable error: %s' % err)
# A simple Panel class with some basic widgets that how to call a runnable
class Panel(qtw.QWidget):
def __init__(self):
super(Panel, self).__init__()
self.progress_dialog = None
self.label = qtw.QLabel('Number: -1')
self.current_number = -1
self.button = qtw.QPushButton('Start')
self.button.setToolTip('shortcut: s')
self.button.setShortcut('s')
self.button.clicked.connect(self.start_long_calculation)
self.calculation_result = qtw.QLabel('')
self.number_slider = qtw.QSlider(qtc.Qt.Orientation.Horizontal)
self.number_slider.sliderMoved.connect(self.on_slider_changed)
self.vlayout = qtw.QVBoxLayout()
self.vlayout.addWidget(self.label)
self.vlayout.addWidget(self.number_slider)
self.vlayout.addWidget(self.button)
self.vlayout.addSpacing(25)
self.vlayout.addWidget(self.calculation_result)
self.setLayout(self.vlayout)
def on_slider_changed(self, value):
self.current_number = value
self.label.setText('Number: %s' % value)
def start_long_calculation(self):
# We create an instance of our QRunnable
my_runnable = MyRunnable(self.current_number)
my_runnable.signals.started.connect(self.on_calculation_start)
my_runnable.signals.progress.connect(self.on_calculation_progress)
my_runnable.signals.completed.connect(self.on_calculation_success)
my_runnable.signals.failed.connect(self.on_calculation_fail)
# We grab the preexisting threadpool and use it to "queue"
# the execution of our runnable
# For more info on QThreadPool, see https://doc.qt.io/qt-5/qthreadpool.html
qtc.QThreadPool.globalInstance().start(my_runnable)
self.progress_dialog = qtw.QProgressDialog("Crunching numbers..",
"Abort", 0, 100, self)
self.progress_dialog.setWindowModality(qtc.Qt.WindowModal)
self.progress_dialog.setCancelButton(None)
self.progress_dialog.show()
def on_calculation_start(self):
sys.stdout.write('Calculation started.. crunching numbers.. '
'it will take a while...\n')
sys.stdout.flush()
def on_calculation_progress(self, value):
self.progress_dialog.setValue(value)
def on_calculation_success(self, number, result):
message = 'Calculation succeded! Is %s a square of 2? %s\n' % (number,
result)
sys.stdout.write(message)
sys.stdout.flush()
self.progress_dialog.close()
self.calculation_result.setText(message)
def on_calculation_fail(self, message):
sys.stderr.write('Calculation failed. %s\n' % message)
sys.stderr.flush()
self.progress_dialog.close()
self.calculation_result.setText(message)
def main():
app = qtw.QApplication()
panel = Panel()
panel.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()