1

次のコードの問題は、キャンセル ボタンを押した後にワーカー スレッドが終了せず、def pdialog(self) が while ループが終了するまで停止しないことです。プログレスバーが進行状況を印刷するのを止めたいので、バックグラウンドプロセスを停止します。

import sys
from PyQt4 import QtGui, QtCore
import time

#from t6 import Ui_dialog_progress
#from t6 import Ui_dialog_file

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s


class Ui_dialog_progress(object):
    def setupUi(self, dialog_progress):
        dialog_progress.setObjectName("dialog_progress")
        dialog_progress.resize(401, 165)
        self.gridLayout = QtGui.QGridLayout(dialog_progress)
        self.gridLayout.setObjectName("gridLayout")
        self.lblFileName = QtGui.QLabel(dialog_progress)
        self.lblFileName.setText("")
        self.lblFileName.setObjectName("lblFileName")
        self.gridLayout.addWidget(self.lblFileName, 0, 0, 1, 2)
        self.pbarFileSize = QtGui.QProgressBar(dialog_progress)
        self.pbarFileSize.setProperty("value", 0)
        self.pbarFileSize.setObjectName("pbarFileSize")
        self.gridLayout.addWidget(self.pbarFileSize, 1, 0, 1, 2)
        self.label_2 = QtGui.QLabel(dialog_progress)
        self.label_2.setObjectName("label_2")
        self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
        self.pbarTotal = QtGui.QProgressBar(dialog_progress)
        self.pbarTotal.setProperty("value", 0)
        self.pbarTotal.setObjectName("pbarTotal")
        self.gridLayout.addWidget(self.pbarTotal, 3, 0, 1, 2)
        self.lblTotal = QtGui.QLabel(dialog_progress)
        self.lblTotal.setText("")
        self.lblTotal.setObjectName("lblTotal")
        self.gridLayout.addWidget(self.lblTotal, 4, 0, 1, 2)
        spacerItem = QtGui.QSpacerItem(213, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem, 6, 0, 1, 1)
        spacerItem1 = QtGui.QSpacerItem(20, 5, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
        self.gridLayout.addItem(spacerItem1, 5, 1, 1, 1)
        self.btnPbarCancel = QtGui.QPushButton(dialog_progress)
        self.btnPbarCancel.setObjectName("btnPbarCancel")
        self.gridLayout.addWidget(self.btnPbarCancel, 6, 1, 1, 1)

        self.retranslateUi(dialog_progress)
        QtCore.QMetaObject.connectSlotsByName(dialog_progress)

    def retranslateUi(self, dialog_progress):
        dialog_progress.setWindowTitle(QtGui.QApplication.translate("dialog_progress", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
        self.label_2.setText(QtGui.QApplication.translate("dialog_progress", "Total:", None, QtGui.QApplication.UnicodeUTF8))
        self.btnPbarCancel.setText(QtGui.QApplication.translate("dialog_progress", "Cancel", None, QtGui.QApplication.UnicodeUTF8))

class Ui_dialog_file(object):
    def setupUi(self, dialog_file):
        dialog_file.setObjectName(_fromUtf8("dialog_file"))
        dialog_file.resize(101, 59)
        self.btnCreate = QtGui.QPushButton(dialog_file)
        self.btnCreate.setGeometry(QtCore.QRect(10, 20, 77, 25))
        self.btnCreate.setObjectName(_fromUtf8("btnCreate"))
        self.retranslateUi(dialog_file)
        QtCore.QMetaObject.connectSlotsByName(dialog_file)

    def retranslateUi(self, dialog_file):
        dialog_file.setWindowTitle(QtGui.QApplication.translate("dialog_file", "file", None, QtGui.QApplication.UnicodeUTF8))
        self.btnCreate.setText(QtGui.QApplication.translate("dialog_file", "Create", None, QtGui.QApplication.UnicodeUTF8))

class ProgressDialog(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent = None)
        self.ui = Ui_dialog_progress()
        self.ui.setupUi(self)
        self.setWindowModality(QtCore.Qt.ApplicationModal)

class MyThread(QtCore.QThread):
    trigger = QtCore.pyqtSignal()
    updatePD = QtCore.pyqtSignal()
    def __init__(self, parent=None):
        super(MyThread, self).__init__(parent)

    def run(self):
        self.trigger.emit()

class Main(QtGui.QDialog):
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.ui = Ui_dialog_file()
        self.ui.setupUi(self)
        self.ui.btnCreate.clicked.connect(self.start_threads)

    def start_threads(self):
        self.mythread = MyThread(self)
        self.mythread.trigger.connect(self.pdialog)
        self.connect(self.mythread, QtCore.SIGNAL("updateFileProgress(int)"), self.updateFileProgress)
        self.connect(self.mythread, QtCore.SIGNAL("updateTotalProgress(int)"), self.updateTotalProgress)
        self.pd = ProgressDialog()
        signal = QtCore.SIGNAL("clicked()")
        self.pd.ui.btnPbarCancel.connect(self.pd.ui.btnPbarCancel, signal, self.abort)
        self.mythread.start()

    def abort(self):
        self.pd.close()
        self.mythread.terminate()

    def updateFileProgress(self, j):
        self.pd.ui.pbarFileSize.setValue(j)
        print j

    def updateTotalProgress(self, i):
        self.pd.ui.pbarTotal.setValue(i)
        print i

    def pdialog(self):
        self.pd.show()
        i = 1
        self.pd.ui.pbarTotal.setValue(0)
        self.pd.ui.pbarFileSize.setValue(0)
        j = 1
        while i < 100:
            while j <= 100:
                time.sleep(0.01)
                self.mythread.emit(QtCore.SIGNAL("updateFileProgress(int)"), j)
                QtGui.qApp.processEvents()
                j += 1
            i += 1
            j = 1
            self.mythread.emit(QtCore.SIGNAL("updateTotalProgress(int)"), i)
            QtGui.qApp.processEvents()
        self.pd.close()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    mainwindow = Main()
    mainwindow.show()
    sys.exit(app.exec_())
4

1 に答える 1

2

terminate()スレッドの終了には使用しないでください。

http://qt-project.org/doc/qt-4.8/qthread.html#terminateを参照してください

void QThread::terminate () [スロット]

スレッドの実行を終了します。スレッドは、オペレーティング システムのスケジュール ポリシーに応じて、すぐに終了する場合と終了しない場合があります。同期終了には、terminate() の後に QThread::wait() を使用します。

スレッドが終了すると、スレッドの終了を待っているすべてのスレッドが起動されます。

警告:この機能は危険であり、使用しないことをお勧めします。スレッドは、そのコード パスの任意の時点で終了できます。データの変更中にスレッドを終了できます。スレッドがそれ自体をクリーンアップしたり、保持されているミューテックスのロックを解除したりする可能性はありません。要するに、この関数は絶対に必要な場合にのみ使用してください。

スレッドを穏やかに停止する方法はたくさんあります。
たとえば、フラグ変数を使用してワーカー関数に停止を通知できます。

def start_threads(self):
    self.end_flag = False
    self.mythread = MyThread(self)
    self.mythread.trigger.connect(self.pdialog)
    self.connect(self.mythread, QtCore.SIGNAL("updateFileProgress(int)"), self.updateFileProgress)
    self.connect(self.mythread, QtCore.SIGNAL("updateTotalProgress(int)"), self.updateTotalProgress)
    self.pd = ProgressDialog()
    signal = QtCore.SIGNAL("clicked()")
    self.pd.ui.btnPbarCancel.connect(self.pd.ui.btnPbarCancel, signal, self.abort)
    self.mythread.start()

def abort(self):
    self.pd.close()
    #self.mythread.terminate()
    self.end_flag = True

def pdialog(self):
    self.pd.show()
    i = 1
    self.pd.ui.pbarTotal.setValue(0)
    self.pd.ui.pbarFileSize.setValue(0)
    j = 1
    while i < 100:
        while j <= 100:
            if self.end_flag:
                self.pd.close()
                return
            time.sleep(0.01)
            self.mythread.emit(QtCore.SIGNAL("updateFileProgress(int)"), j)
            QtGui.qApp.processEvents()
            j += 1
        i += 1
        j = 1
        self.mythread.emit(QtCore.SIGNAL("updateTotalProgress(int)"), i)
        QtGui.qApp.processEvents()
    self.pd.close()
于 2013-02-24T12:02:43.563 に答える