最简单的中断pyqt4的方法?

时间:2016-06-04 14:01:32

标签: python multithreading pyqt pyqt4

我正在用Python构建一个简单的速度阅读器作为练习。基本上是Spritz克隆。

运行后停止printword()函数的正确方法是什么?我应该把它放在一个帖子里吗?使用线程还是QThread?我有点失落。

#!/usr/bin/env python3

from time import sleep

import sys
from PyQt4 import QtGui, QtCore    

class Fastreader(QtGui.QWidget):

    def __init__(self):
        super(Fastreader, self).__init__()
        self.initUI()

    def initUI(self):

        self.le = QtGui.QLineEdit(self)
        self.le.setAlignment(QtCore.Qt.AlignCenter)
        self.le.move(20, 20)

        self.btn = QtGui.QPushButton('Play', self)
        self.btn.move(20, 50)
        self.btn.clicked.connect(self.printword)

        self.btn = QtGui.QPushButton('Stop', self)
        self.btn.move(120, 50)

        self.setGeometry(300, 300, 225, 80)
        self.setWindowTitle('fastreader')
        self.show()

    def printword(self):

        cb = QtGui.QApplication.clipboard()
        text = cb.text()

        words_per_minute = 200

        sleeptime = 60.0/words_per_minute

        for word in text.split(" "):
                self.le.setText(word)
                self.le.repaint()
                sleep(sleeptime)

def main():

    app = QtGui.QApplication(sys.argv)
    ex = Fastreader()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

非常感谢!

2 个答案:

答案 0 :(得分:0)

我会使用带有回调的计时器,以避免在Qt中使用线程或睡眠。你可以尝试这样的事情:

def initUI(self):
    ...
    self.btn = QtGui.QPushButton('Play', self)
    self.btn.move(20, 50)
    self.btn.clicked.connect(self.play)

    self.btn = QtGui.QPushButton('Stop', self)
    self.btn.move(120, 50)
    self.btn.clicked.connect(self.stop)
    ...

def play(self):
    cb = QtGui.QApplication.clipboard()
    text = cb.text()
    self.words = text.split(' ') 
    self.current_word = 0

    words_per_minute = 200

    # setInterval apparently takes msecs
    sleeptime = 60000.0 / words_per_minute

    self.timer = QtCore.QTimer(self)
    self.timer.setInterval(sleeptime)
    self.timer.timeout.connect(self.printword)
    self.timer.start()

def stop(self):
    self.timer.stop()

def printword(self):
    word = self.words[self.current_word]
    self.le.setText(word)

    self.current_word += 1
    if self.current_word == len(self.words):
        self.timer.stop()

你甚至不必以这种方式调用self.le.repaint()。

答案 1 :(得分:0)

以下是我使用QThread的解决方案,请检查。我还使用slotsignal机制在主线程和工作线程之间传输数据。

嗯,最初我认为以这种方式改变它很容易。但事实证明,需要做一些改变。但请将其视为使用QThread

的示例
from time import sleep

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *


class Fastreader(QWidget):

    def __init__(self):
        super(Fastreader, self).__init__()
        self.initUI()

    def initUI(self):
        self.le = QLineEdit(self)
        self.le.setAlignment(Qt.AlignCenter)
        self.le.move(20, 20)

        self.btnplay = QPushButton('Play', self)
        self.btnplay.move(20, 50)

        self.btnstop = QPushButton('Stop', self)
        self.btnstop.move(120, 50)

        self.mthread = QThread() # New thread to run the Measurement Engine
        self.worker = PrintWord() # Measurement Engine Object

        # Transfer worker to the new thread. Calls to the worker will execute in mthread.
        self.worker.moveToThread(self.mthread)
        self.mthread.finished.connect(self.worker.deleteLater) # Cleanup after thread finished

        self.btnplay.clicked.connect(self.worker.printword)
        self.btnstop.clicked.connect(self.worker.kill, Qt.DirectConnection)

        self.worker.wordshow.connect(self.showword)
        self.mthread.start() 

        self.setGeometry(300, 300, 225, 80)
        self.setWindowTitle('fastreader')
        self.show()

    @pyqtSlot(str)
    def showword(self, word):
        self.le.setText(word)
#        self.le.repaint()

    def closeEvent(self, event):
        """ Example how to capture all window close events and perform an action before closing. It reimplements the default closeEvent"""
        print("Close Event Received")

        # Cleanup mthread.
        self.mthread.quit()
        self.mthread.wait()

        # Accept the event, so that the window really closed. 
        # ignore() wold leave the window alive, for example if there is unsaved data. 
#        event.accept()

class PrintWord(QObject):
    wordshow   = pyqtSignal(str)              # started measurement loop

    def __init__(self):
        self.dokill = False # Flag to interrupt the loop if needed
        QObject.__init__(self) # Don't forget to call base class constructor
        self.printword()

    def printword(self):

        cb = QApplication.clipboard()
        text = cb.text()

        words_per_minute = 200

        sleeptime = 60.0/words_per_minute
        self.dokill = False
        for word in text.split(" "):
                if self.dokill:
                    break
                self.wordshow.emit(word)
                sleep(sleeptime)
#                print word

    @pyqtSlot()
    def kill(self):
        """ Set loop interruption flag to exit the measurment loop """
        self.dokill = True

def main():
    app = QApplication(sys.argv)
    ex = Fastreader()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()