当我在python pyqt

时间:2016-09-20 22:49:31

标签: python python-3.x pyqt pyqt4 qthread

我的代码有线程,但是当我关闭gui时,它仍然可以在后台运行。我怎么能阻止线程?有什么东西stop(),close()? 我不使用信号,插槽?我必须用这个吗?

from PyQt4 import QtGui, QtCore
import sys
import time
import threading

class Main(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.kac_ders=QtGui.QComboBox()
        self.bilgi_cek=QtGui.QPushButton("Save")
        self.text=QtGui.QLineEdit()
        self.widgetlayout=QtGui.QFormLayout()
        self.widgetlar=QtGui.QWidget()
        self.widgetlar.setLayout(self.widgetlayout)
        self.bilgiler=QtGui.QTextBrowser()
        self.bilgi_cek.clicked.connect(self.on_testLoop)
        self.scrollArea = QtGui.QScrollArea()
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setWidget(self.widgetlar)
        self.analayout=QtGui.QVBoxLayout()
        self.analayout.addWidget(self.text)
        self.analayout.addWidget(self.bilgi_cek)
        self.analayout.addWidget(self.bilgiler)
        self.centralWidget=QtGui.QWidget()
        self.centralWidget.setLayout(self.analayout)
        self.setCentralWidget(self.centralWidget)

    def on_testLoop(self):
        self.c_thread=threading.Thread(target=self.kontenjan_ara)
        self.c_thread.start()

    def kontenjan_ara(self):

        while(1):
                self.bilgiler.append(self.text.text())
                time.sleep(10)


app = QtGui.QApplication(sys.argv)
myWidget = Main()
myWidget.show()
app.exec_()

2 个答案:

答案 0 :(得分:3)

一些事情:

  1. 您不应该从主线程外部调用GUI代码。 GUI元素不是线程安全的。 self.kontenjan_ara来自GUI元素的更新和读取,它不应该是您thread的目标。

  2. 在几乎所有情况下,您都应该使用QThreads而不是python线程。它们与Qt中的事件和信号系统很好地集成。

  3. 如果您只想每隔几秒运行一次,可以使用QTimer

    def __init__(self, parent=None):
        ...
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.kontenjan_ara)
        self.timer.start(10000)
    
    def kontenjan_ara(self):
        self.bilgiler.append(self.text.text())
    

    如果您的线程操作在计算上更复杂,您可以使用信号创建工作线程并在工作线程和主GUI线程之间传递数据。

    class Worker(QObject):
    
        work_finished = QtCore.pyqtSignal(object)
    
        @QtCore.pyqtSlot()
        def do_work(self):
            data = 'Text'
            while True:
                # Do something with data and pass back to main thread
                data = data + 'text'
                self.work_finished.emit(data)
                time.sleep(10)
    
    
    class MyWidget(QtGui.QWidget):
    
        def __init__(self, ...)
            ...
            self.worker = Worker()
            self.thread = QtCore.QThread(self)
            self.worker.work_finished.connect(self.on_finished)
            self.worker.moveToThread(self.thread)
            self.thread.started.connect(self.worker.do_work)
            self.thread.start()
    
        @QtCore.pyqtSlot(object)
        def on_finished(self, data):
            self.bilgiler.append(data)
            ...
    

    当主线程退出事件循环时,Qt将自动终止所有子线程。

答案 1 :(得分:2)

我选择重写这个答案,因为我未能正确看待问题的背景。正如其他答案和评论所说,您的代码缺乏线程安全性。

解决这个问题的最好方法是尝试在线程中真正思考",限制自己只使用生活在同一个线程中的对象,或称为"线程安全&## 34。

投掷一些信号和插槽会有所帮助,但也许你想回想一下原来的问题。在您当前的代码中,每次按下按钮时,启动的新主题,即每10秒执行两项操作:   - 阅读self.text中的一些文字   - 将其附加到self.bilgiler

这两个操作都是非线程安全的,并且必须从拥有这些对象的线程(主线程)中调用。你想让工作线程" schedule& amp;等待"阅读&附加oeprations,而不仅仅是"执行"它们。

我建议使用另一个答案(通过使用与Qt事件循环良好集成的正确QThreads自动修复线程停止问题),这将使您使用更清晰的方法,与Qt集成更多。

您可能还想重新考虑您的问题,因为可能有一种更简单的方法来处理您的问题,例如:每次点击bilgi_cek时都不会产生线程,或者使用Queue对象以便您的问题worker完全不知道你的GUI,只能使用线程安全对象与它进行交互。

祝你好运,抱歉,如果我引起任何困惑。我的原始答案仍然可用here。我认为将另一个答案标记为这个问题的有效答案是明智的。