1
0

Add TaskThread, use to simplify WaitingDialog

This will be useful as a client thread for hardware wallets
This commit is contained in:
Neil Booth
2016-01-16 16:54:51 +09:00
parent d9a84875dc
commit c714acf739
2 changed files with 70 additions and 34 deletions

View File

@@ -4,6 +4,8 @@ import traceback
import sys
import threading
import platform
import Queue
from collections import namedtuple
from functools import partial
from electrum.i18n import _
@@ -211,39 +213,26 @@ class WindowModalDialog(QDialog, MessageBoxMixin):
if title:
self.setWindowTitle(title)
class WaitingDialog(QThread, MessageBoxMixin):
class WaitingDialog(WindowModalDialog):
'''Shows a please wait dialog whilst runnning a task. It is not
necessary to maintain a reference to this dialog.'''
def __init__(self, parent, message, task, on_finished=None):
global dialogs
dialogs.append(self) # Prevent GC
QThread.__init__(self)
self.task = task
self.on_finished = on_finished
self.dialog = WindowModalDialog(parent, _("Please wait"))
vbox = QVBoxLayout(self.dialog)
def __init__(self, parent, message, task, on_success=None, on_error=None):
assert parent
WindowModalDialog.__init__(self, parent, _("Please wait"))
vbox = QVBoxLayout(self)
vbox.addWidget(QLabel(message))
self.dialog.show()
self.dialog.connect(self, SIGNAL("finished()"), self.finished)
self.start()
self.accepted.connect(self.on_accepted)
self.show()
self.thread = TaskThread(self)
self.thread.add(task, on_success, self.accept, on_error)
def run(self):
try:
self.result = self.task()
self.error = None
except BaseException as e:
traceback.print_exc(file=sys.stdout)
self.error = str(e)
self.result = None
def wait(self):
self.thread.wait()
def on_accepted(self):
self.thread.stop()
def finished(self):
global dialogs
dialogs.remove(self)
self.dialog.accept()
if self.error:
self.show_error(self.error, parent=self.dialog.parent())
if self.on_finished:
self.on_finished(self.result)
def line_dialog(parent, title, label, ok_label, default=None):
dialog = WindowModalDialog(parent, title)
@@ -548,6 +537,46 @@ class ButtonsTextEdit(QPlainTextEdit, ButtonsWidget):
return o
class TaskThread(QThread):
'''Thread that runs background tasks. Callbacks are guaranteed
to happen in the context of its parent.'''
Task = namedtuple("Task", "task cb_success cb_done cb_error")
doneSig = pyqtSignal(object, object, object)
def __init__(self, parent, on_error=None):
super(TaskThread, self).__init__(parent)
self.on_error = on_error
self.tasks = Queue.Queue()
self.doneSig.connect(self.on_done)
self.start()
def add(self, task, on_success=None, on_done=None, on_error=None):
on_error = on_error or self.on_error
self.tasks.put(TaskThread.Task(task, on_success, on_done, on_error))
def run(self):
while True:
task = self.tasks.get()
if not task:
break
try:
result = task.task()
self.doneSig.emit(result, task.cb_done, task.cb_success)
except BaseException:
self.doneSig.emit(sys.exc_info(), task.cb_done, task.cb_error)
def on_done(self, result, cb_done, cb):
# This runs in the parent's thread.
if cb_done:
cb_done()
if cb:
cb(result)
def stop(self):
self.tasks.put(None)
if __name__ == "__main__":
app = QApplication([])
t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done", _('OK')))