@jerch:
Besten Dank. Ich habe deine Ausführung mal als Blaupause genommen und versucht meinen Quelltext drüber zu spulten. Vermutlich ist dies mir misslungen, aber wir werden es ja sehen. Wie immer habe ich ein paar frage, die ich am Ende des Beitrages stellen werde.
Code: Alles auswählen
import sys
from time import sleep
from PyQt4.QtCore import QThread, pyqtSignal, Qt, QStringList, QObject, QTimer
from PyQt4.QtGui import QVBoxLayout, QPushButton, QDialog, QProgressBar, QApplication, \
QMessageBox, QTreeWidget, QTreeWidgetItem, QLabel
def create_items(total):
for elem in range(total):
yield elem
class TaskThread(QThread):
'''
Thread container for a Task.
Overrides `run` to initialize and run a single task object.
'''
def __init__(self, obj, args, kwargs, parent=None):
QThread.__init__(self, parent)
obj.moveToThread(self)
self.obj = obj
self.args = args
self.kwargs = kwargs
def run(self):
try:
self.obj.init(*self.args, **self.kwargs)
except:
pass
self.obj.result = self.obj.run()
QApplication.processEvents()
def _close(self):
self.quit()
self.wait()
self.obj.thread = None
self.obj.deleteLater()
self.deleteLater()
class Task(QObject):
'''
Task - a `run` method based self containing theaded task.
Executes the `init` and `run` method within a subthread.
The provided `processEvents` method should be called once in a while
in `run` to be able to catch events and trigger slots.
Any result of `run` will be emitted via the `finished` signal.
'''
finished = pyqtSignal(object)
def __init__(self, *args, **kwargs):
QObject.__init__(self, None)
self.result = None
self.thread = TaskThread(self, args, kwargs, None)
self.thread.finished.connect(self._finished)
def processEvents(self):
QApplication.processEvents()
def start(self):
self.thread.start()
def _finished(self):
self.finished.emit(self.result)
class TaskWithSignalsAndSlots(Task):
'''
Task example with signal and slot dispatching.
'''
notify_counter = pyqtSignal(object)
notify_item = pyqtSignal(object)
def init(self):
self.keep_running = True
def run(self):
total = 1000
x = (total/100*1)
a = x
counter = 0
for item in create_items(total):
counter += 1
self.notify_counter.emit(counter)
self.notify_item.emit(item)
if counter == x:
x += a
sleep(0.5)
if not self.keep_running:
break
self.processEvents()
def stop(self):
self.keep_running = False
class MyCustomDialog(QDialog):
finish = pyqtSignal()
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.tree = QTreeWidget(self)
self.label = QLabel(self)
self.pushButton_start = QPushButton("Start", self)
self.pushButton_stopp = QPushButton("Stopp", self)
self.pushButton_close = QPushButton("Close", self)
layout = QVBoxLayout(self)
layout.addWidget(self.label)
layout.addWidget(self.tree)
layout.addWidget(self.pushButton_start)
layout.addWidget(self.pushButton_stopp)
layout.addWidget(self.pushButton_close)
self.init_PushButton()
def init_PushButton(self):
self.pushButton_start.clicked.connect(self.on_start)
self.pushButton_stopp.clicked.connect(self.on_finish)
self.pushButton_close.clicked.connect(self.on_close)
def fill_tree_widget(self, i):
parent = QTreeWidgetItem(self.tree)
self.tree.addTopLevelItem(parent)
parent.setText(0, unicode(i))
parent.setCheckState(0, Qt.Unchecked)
parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
def on_label(self, i):
self.label.setText("Result: {}".format(int(i)))
def clear_widget(self):
list_widgets = [self.label,
self.tree]
for widget in list_widgets:
widget.clear()
def on_start(self):
self.clear_widget()
task = TaskWithSignalsAndSlots()
task.notify_counter.connect(self.on_label)
task.notify_item.connect(self.fill_tree_widget)
self.finish.connect(task.stop)
timer = QTimer()
timer.setSingleShot(False)
timer.timeout.connect(task.stop)
timer.start()
task.start()
def on_finish(self):
self.finish.emit()
def on_close(self):
self.close()
def closeEvent(self, event):
self.on_finish()
def main():
app = QApplication(sys.argv)
window = MyCustomDialog()
window.resize(600, 400)
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Ist das so, wie du es dir vorgestellt hast, jerch? Zunächst einmal habe ich alle »QCoreApplication()«-Klassen in »QApplication()« umgeschrieben (
Zeile 31 und 57). Ich hoffe einfach, dass ich an dieser Stelle richtig gehandelt habe. Meine Intention: Da ich in meinem Beispiel die »QApplication()«-Klasse verwende (
Zeile 173), so verwende ich diese weiterhin.
Allerdings habe ich so meine Zweifel, dass ich dich irgendwie richtig verstanden habe. Denn die komplette Arbeit wurde in diesem Fall wieder in die »run()«-Methode der »TaskWithSignalsAndSlots()«-Klasse verschoben (
Zeile 75-97). Ich weiß einfach nicht wohin mit dieser Arbeitsaufgabe. Irgendwo muss es ja ausgeführt werden.
Nun folgen ein paar Fragen: Du hast eine »TaskThread()«-Klasse erstellt, die von »QThread()«-Klasse erbt (
Zeile 13). Du hast diese Klasse überschrieben, damit die »run()«-Methode einzelnes
Task-Objekte zu initialisieren und auszuführen (
Zeilen 25 - 31). Ich frage mal ganz naiv: war das notwendig? Heißt das jetzt, dass die »QThread()«-Klasse ansonsten mehrere Objekte initialisiert und ausgeführt hätte? Welchen Vorteil habe ich jetzt daraus gewonnen?
Als nächstest hast du die »Task()«-Klassen definiert, die von der »QObject()«-Klassen erbt (Zeile 41). Neben den Tatsachen, dass du insgesamt drei Methoden (»processEvents()« (
Zeile 56), »start()« (
Zeile 59) und »_finished()«(
Zeile 62)) definiert hast, wird hier objektweit die »TaskThread()«-Klasse erzeugt (
Zeile 53). Anschließend wird dann die »finished()-Methode der »TaskThread()«-Klasse mit der »_finished()«-Methode der »Taks()«-Klasse verbunden (
Zeile 54). Die eigentliche Arbeit findet »TaskWithSignalsAndSlots()«-Klasse, die von der »Task()«-Klasse erbt, statt (
Zeile 65). Soweit ich das nachvollziehen kann, findet hier die direkte Interaktion zwischen dem Programm und dem Benutzer über die GUI statt.
Jetzt konnte ich zwar einzelne Elemente aufzählen, aber irgendwie habe ich die ganze Dimension noch nicht verstanden. Ich komme mir vor, wie jemand, der in einem Wort alle Buchstaben benennen kann, aber nicht darauf kommt, was das nun für ein Wort ist, und welche Bedeutung dahintersteckt.
Des Weiteren habe ich deine Anmerkung zu der »moveToThread()«-Methode der »WorkObject()«- Klasse nicht ganz verstanden. Was genau und konkret war das falsch? Liegt es daran, weil ich in meinem vorherigen Beispiel die »WorkObject()«- Klasse dialogweit erzeugt und diese dann auf lokaler Ebene in der »on_start()«- Methode der »MyCustomDialog()«- Klasse in die »QThread()«- Klasse verschoben habe? Wieso ist dieser Vorgang mehr als ungünstig?