2

How should I call a QThread that is defined in another python file?

here's my code.

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:])

this is what i did, I run the mymain.py in shell. and i run the exarg.py in terminal/command line using this command

sudo python exarg.py -i 3 -o 4

but I always got an error saying:

'QThread: Destroyed while thread is still running'

any comments/suggestions would be highly appreciated. thanks.

three_pineapples
  • 11,579
  • 5
  • 38
  • 75
  • I feel like this has been cut down too far from your original code. You have undefined variables in your thread. Not to mention the fact that it looks like you are trying to modify the GUI directly from a thread (not a good idea unless you like random crashes!). – three_pineapples Jul 27 '15 at 04:41
  • I updated mymain.py so you can view the full code. and yes im trying to modify a Qlabel in the Gui using QThread. any suggestions? – Polan Santiago Jul 27 '15 at 04:48

1 Answers1

1

There are a couple of things wrong with your code as it currently stands.

The first is that you don't appear to call app.exec_() anywhere (at least when you run exarg.py) to actually start your QApplication. But perhaps you just forgot to include that?

Second is that you create your thread inside a function, and assign it to the variable m. As soon as the function main ends, that local variable is garbage collected and your thread is destroyed. You need to make sure this doesn't happen. Either by making m a global variable, or returning m from the function and holding a reference to it, or you could not create it inside the function. As long as you always hold a reference to your thread, it will not be destroyed and you will not see that error message!

Finally, you should never modify GUI objects from a thread directly. Qt widgets are not thread safe! What you need to do is define a signal in your thread, and connect a slot (from the main thread) to that signal when you create the thread. You can then emit a signal from your thread (this is thread-safe) which will call a slot in the main thread where you are allowed to modify the GUI. This question/answer demonstrates approximately how to do this.

EDIT: Also, the global myctr etc. code is confusing. You shouldn't need that. Just access them as self.myctr from within the thread since you have written m.myctr = ctr before calling m.start().

Community
  • 1
  • 1
three_pineapples
  • 11,579
  • 5
  • 38
  • 75