【问题标题】:How to call Qt Thread (QThread) from another python file? (QThread is destroyed)如何从另一个 python 文件调用 Qt 线程(QThread)? (QThread 被销毁)
【发布时间】:2015-10-17 03:52:24
【问题描述】:

我应该如何调用在另一个 python 文件中定义的QThread

这是我的代码。

mymain.py

from PyQt4 import QtCore, QtGui
import PyQt4
import sys
import os
from time import sleep

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

class Ui_MainWindow(QtGui.QMainWindow):
  def __init__(self):
       QtGui.QWidget.__init__(self)
       self.setupUi(self)
  def setupUi(self, MainWindow):
       MainWindow.setObjectName(_fromUtf8("MainWindow"))
       self.showMaximized()
       MainWindow.setStyleSheet(_fromUtf8("background-color: rgb(0, 0, 0);"))
       self.centralwidget = QtGui.QWidget(MainWindow)
       self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
       self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
       self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
       self.gridLayout = QtGui.QGridLayout()
       self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
       spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
       self.gridLayout.addItem(spacerItem, 2, 0, 1, 1)
       self.horizontalLayout_2 = QtGui.QHBoxLayout()
       self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2"))
       self.verticalLayout = QtGui.QVBoxLayout()
       self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
       self.lblNowServing = QtGui.QLabel(self.centralwidget)
       font = QtGui.QFont()
       font.setFamily(_fromUtf8("Bebas Neue"))
       font.setPointSize(140)
       self.lblNowServing.setFont(font)
       self.lblNowServing.setStyleSheet(_fromUtf8("color: rgb(170, 0, 0);"))
       self.lblNowServing.setObjectName(_fromUtf8("lblNowServing"))
       self.lblNowServing.setAlignment(QtCore.Qt.AlignCenter)
       self.verticalLayout.addWidget(self.lblNowServing)
       self.lblNowServingNumber = QtGui.QLabel(self.centralwidget)
       font = QtGui.QFont()
       font.setFamily(_fromUtf8("DS-Digital"))
       font.setPointSize(350)
       self.lblNowServingNumber.setFont(font)
       self.lblNowServingNumber.setStyleSheet(_fromUtf8("color: rgb(170, 0, 0);"))
       self.lblNowServingNumber.setObjectName(_fromUtf8("lblNowServingNumber"))
       self.lblNowServingNumber.setAlignment(QtCore.Qt.AlignCenter)
       self.verticalLayout.addWidget(self.lblNowServingNumber)
       self.horizontalLayout_2.addLayout(self.verticalLayout)
       self.verticalLayout_2 = QtGui.QVBoxLayout()
       self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
       self.lblCounter = QtGui.QLabel(self.centralwidget)
       font = QtGui.QFont()
       font.setFamily(_fromUtf8("Bebas Neue"))
       font.setPointSize(140)
       self.lblCounter.setFont(font)
       self.lblCounter.setStyleSheet(_fromUtf8("color: rgb(170, 0, 0);"))
       self.lblCounter.setObjectName(_fromUtf8("lblCounter"))
       self.lblCounter.setAlignment(QtCore.Qt.AlignCenter)
       self.verticalLayout_2.addWidget(self.lblCounter)
       self.lblCounterNumber = QtGui.QLabel(self.centralwidget)
       font = QtGui.QFont()
       font.setFamily(_fromUtf8("DS-Digital"))
       font.setPointSize(350)
       self.lblCounterNumber.setFont(font)
       self.lblCounterNumber.setStyleSheet(_fromUtf8("color: rgb(170, 0, 0);"))
       self.lblCounterNumber.setObjectName(_fromUtf8("lblCounterNumber"))
       self.lblCounterNumber.setAlignment(QtCore.Qt.AlignCenter)
       self.verticalLayout_2.addWidget(self.lblCounterNumber)
       self.horizontalLayout_2.addLayout(self.verticalLayout_2)
       self.gridLayout.addLayout(self.horizontalLayout_2, 0, 0, 1, 1)
       spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
       self.gridLayout.addItem(spacerItem, 1, 0, 1, 1)
       self.horizontalLayout.addLayout(self.gridLayout)
       MainWindow.setCentralWidget(self.centralwidget)

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

   def retranslateUi(self, MainWindow):
       MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
       self.lblNowServing.setText(QtGui.QApplication.translate("MainWindow", "  NOW SERVING  ", None, QtGui.QApplication.UnicodeUTF8))
       self.lblCounter.setText(QtGui.QApplication.translate("MainWindow", "COUNTER", None, QtGui.QApplication.UnicodeUTF8))        
       self.lblCounterNumber.setText(str(1))
       self.lblNowServingNumber.setText(str(1))

class valChange(QtCore.QThread):
    def __init__(self):
        QtCore.QThread.__init__(self)
    def run(self):
        self.myctr = 0
        self.myval = 0

        self.lblNowServingNumber.setText(str(myval))
        self.lblCounterNumber.setText(str(myctr))            

if __name__=='__main__':
    app = QtGui.QApplication(sys.argv)
    ex = Ui_MainWindow()
    ex.show()
    sys.exit(app.exec_())

exarg.py

from PyQt4 import QtCore, QtGui
import mymain
import sys, getopt

def main(argv):
 ctr = ''
 val = ''
 try:
    opts, args = getopt.getopt(argv,"hi:o:",["ifile=","ofile="])
 except getopt.GetoptError:
    print 'test.py -i <ctr> -o <val>'
    sys.exit(2)
 for opt, arg in opts:
    if opt == '-h':
       print 'test.py -i <ctr> -o <val>'
       sys.exit()
    elif opt in ("-i", "--ifile"):
       ctr = arg
    elif opt in ("-o", "--ofile"):
       val = arg

  m = mymain.valChange()
  m.myctr = ctr
  m.myval = val
  m.start()

if __name__ == "__main__":
 app = QtGui.QApplication(sys.argv)
 main(sys.argv[1:])

这就是我所做的,我在 shell 中运行 mymain.py。我使用此命令在终端/命令行中运行 exarg.py

sudo python exarg.py -i 3 -o 4

但我总是收到错误提示:

'QThread:在线程仍在运行时被销毁'

任何 cmets/建议将不胜感激。谢谢。

【问题讨论】:

  • 我觉得这与您的原始代码相去甚远。您的线程中有未定义的变量。更不用说您似乎正在尝试直接从线程修改 GUI(这不是一个好主意,除非您喜欢随机崩溃!)。
  • 我更新了 mymain.py 以便您可以查看完整代码。是的,我正在尝试使用 QThread 修改 Gui 中的 Qlabel。有什么建议吗?

标签: python python-2.7 pyqt pyqt4 qthread


【解决方案1】:

您的代码目前存在一些问题。

首先,您似乎没有在任何地方调用app.exec_()(至少在您运行exarg.py 时)来实际启动您的QApplication。但也许你只是忘了包括那个?

其次是在函数中创建线程,并将其分配给变量m。一旦函数main 结束,该局部变量就会被垃圾回收并且你的线程被销毁。您需要确保不会发生这种情况。通过将m 设为全局变量,或者从函数返回m 并持有对它的引用,或者您无法在函数内部创建它。只要您始终持有对您的线程的引用,它就不会被销毁,您也不会看到该错误消息!

最后,您应该切勿直接从线程修改 GUI 对象。 Qt 小部件不是线程安全的!您需要做的是在线程中定义一个信号,并在创建线程时将一个插槽(来自主线程)连接到该信号。然后,您可以emit 来自您的线程的信号(这是线程安全的),它将调用主线程中的一个插槽,您可以在其中修改 GUI。 This question/answer 大致演示了如何执行此操作。

编辑:另外,global myctr 等代码令人困惑。你不应该需要那个。只需在线程中以self.myctr 的身份访问它们,因为您在调用m.start() 之前已经编写了m.myctr = ctr

【讨论】:

    猜你喜欢
    • 2020-05-24
    • 2014-09-18
    • 2013-03-20
    • 2021-11-16
    • 2017-09-24
    • 2021-05-27
    • 2015-04-27
    相关资源
    最近更新 更多