-
Notifications
You must be signed in to change notification settings - Fork 6
/
progressbar.py
160 lines (135 loc) · 5.03 KB
/
progressbar.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# Persistent wait bar
#
# (c) Inserm U1216 2018 - Francois Tadel
# License GNU GPL v3
import sys
from soma.qt_gui.qt_backend import QtCore
from soma.qt_gui.qt_backend import QtGui
# ===== PROGRESS WINDOW =====
class ProgressDialog(QtGui.QDialog):
def __init__(self, parent=None, progressText='...', progressTitle='Process', cancelEnabled=True):
super(ProgressDialog, self).__init__(parent)
# Dialog window
self.setWindowTitle(progressTitle)
self.resize(300, 100)
# Layout: Vertical list
vbox = QtGui.QVBoxLayout()
# Text label
self.labelMessage = QtGui.QLabel(progressText)
self.labelMessage.setAlignment(QtCore.Qt.AlignCenter)
vbox.addWidget(self.labelMessage)
# Progress bar
self.progressBar = QtGui.QProgressBar()
self.progressBar.setAlignment(QtCore.Qt.AlignCenter)
self.progressBar.setObjectName("progressBar")
self.progressBar.setMinimum(0)
self.progressBar.setMaximum(0)
self.progressBar.setMaximum(0)
vbox.addWidget(self.progressBar)
# Cancel button
self.cancelEnabled = cancelEnabled
self.buttonCancel = QtGui.QPushButton("Cancel")
self.buttonCancel.setObjectName("buttonCancel")
self.buttonCancel.setEnabled(self.cancelEnabled)
vbox.addWidget(self.buttonCancel)
# Set layout
self.setLayout(vbox)
# Associated worker
self.worker = None
# Start a thread
def start(self, func, isModal=False):
self.worker = ProgressThread(func)
self.worker.progress.connect(self.setProgress)
self.worker.progress_text.connect(self.setText)
self.worker.finished.connect(self.terminated)
self.worker.start()
if self.cancelEnabled:
self.buttonCancel.clicked.connect(self.cancel)
if isModal:
res = self.exec_()
return self.worker.output()
else:
self.show()
return None
# Callback: Cancel button clicked
def cancel(self):
if self.worker is not None:
self.worker.terminate()
self.hide()
# Event: Progress dialog closed
def closeEvent(self, event):
if self.cancelEnabled:
QtGui.QFrame.closeEvent(self, event)
self.cancel()
# Event: Thread terminated
def terminated(self):
self.hide()
# Set progress bar value
def setProgress(self, progress):
# Valid progress bar values
if (progress >= 0) and (progress <= 100):
self.progressBar.setMaximum(100)
self.progressBar.setValue(progress)
# Infinite progress bar
else:
self.progressBar.setMaximum(0)
self.progressBar.setValue(0)
# Set progress window text
def setText(self, text):
self.labelMessage.setText(text)
@staticmethod
def call(func, isModal=True, parent=None, progressText='...', progressTitle='Process', cancelEnabled=True):
progress = ProgressDialog(parent, progressText, progressTitle, cancelEnabled)
res = progress.start(func, isModal)
return res
# ===== PROCESSING THREAD =====
class ProgressThread(QtCore.QThread):
""" Executes a python function in a separate thread. """
progress = QtCore.pyqtSignal(int, name='PROGRESS')
progress_text = QtCore.pyqtSignal(str, name='PROGRESS_TEXT')
def __init__(self, func, parent=None):
""":param func : The function that will be run in a separate thread
:param parent : a parent object for the QThread (default is None)
"""
QtCore.QThread.__init__(self,parent)
self.func = func
self.out = None
def output(self):
""" Returns the output value of the function when execution is terminated"""
return self.out
def run(self):
"""
Reimplementation of the run function of the QThread.
This SHOULD NOT BE CALLED DIRECTLY as it would run in the current thread.
Run self.start() to start the execution in a separate thread
"""
self.out = self.func(self)
# ===== EXAMPLE =====
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
btn = QtGui.QPushButton('Start', self)
btn.resize(btn.sizeHint())
btn.move(50, 50)
self.setWindowTitle('Example')
btn.clicked.connect(self.test)
def test(self):
res = ProgressDialog.call(self.activeWait, False, self, "Processing...", "Example process")
print(res)
def activeWait(self, thread):
import time
for n in range(0,200):
print(n)
if (n > 20):
thread.progress.emit(n)
thread.progress_text.emit("Processing event #{}".format(n))
n += 1
time.sleep(0.1)
# ===== MAIN =====
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()