PyQt4: inheriting QThread - python

I have a QWidget which calls some python code using a QThread. This code then also does some logic and calls another class. In this class, I want to pass a signal up to my QWidget, so that "Hello World" is printed. The code as it stands gives the error sm instance has no attribute 'sayHello', which I know - I'm just pretty clueless how to make the run method call a different class so that all the signals work.
widget.py
from prog import TaskThread
from PyQt4 import QtCore, QtGui
class MyWidget(QtGui.QWidget):
def __init__(self):
self.btn = QtGui.QPushButton('Run!', self)
self.btn.clicked.connect(self.onStart)
self.myLongTask = TaskThread()
self.myLongTask.sayHello.connect(self.sayHi)
def onStart(self):
self.myLongTask.start()
def sayHi(self):
print "hello world"
prog.py
from PyQt4 import QtCore
from sm import sc
class TaskThread(QtCore.QThread):
sayHello = QtCore.pyqtSignal()
def run(self):
sm.sc()
sm.py
class sc():
def __init__(self):
for i in range(0,50):
print i
if i == 5: self.sayHello.emit()

I had to change your code slightly to get it to run on my machine but manually passing the signal instance to the sc class definitely raises the signal. The output may be interleaved with the printing of the i loop.
widget.py
from prog import TaskThread
import sys
from PyQt4 import QtCore, QtGui
class flexemWidget(QtGui.QWidget):
def __init__(self):
super(flexemWidget, self).__init__()
self.btn = QtGui.QPushButton('Run!', self)
self.btn.clicked.connect(self.onStart)
self.myLongTask = TaskThread()
self.myLongTask.sayHello.connect(self.sayHi)
self.show()
def onStart(self):
self.myLongTask.start()
def sayHi(self):
print "hello world"
app = QtGui.QApplication(sys.argv)
ex = flexemWidget()
sys.exit(app.exec_())
prog.py
from PyQt4 import QtCore
from sm import sc
class TaskThread(QtCore.QThread):
sayHello = QtCore.pyqtSignal()
def run(self):
sc(self.sayHello)
sc.py
from PyQt4 import QtCore
class sc():
def __init__(self, signal):
for i in range(0,50):
print i
if i == 5: signal.emit()

Related

PyQt5 .ui file not loading

So my expected outcome is for the login.ui to show when the login button is clicked. My code reached the def gotologin function and the class LoginScreen , but it doesn't load the ui
import sys
from PyQt5.uic import loadUi
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QDialog, QApplication
class WelcomeScreen(QDialog):
def __init__(self):
super(WelcomeScreen, self).__init__()
loadUi('welcomescreen.ui', self)
self.login.clicked.connect(self.gotologin)
def gotologin(self):
login = LoginScreen()
widget.addWidget(login)
widget.setCurrentIndex(widget.currentIndex()+1)
class LoginScreen(QDialog):
def __init__(self):
super(LoginScreen, self).__init__()
loadUi('login.ui', self)
app = QApplication(sys.argv)
welcome = WelcomeScreen()
widget = QtWidgets.QStackedWidget()
widget.addWidget(welcome)
widget.setFixedHeight(800)
widget.setFixedWidth(1200)
window = WelcomeScreen()
window.show()
try:
sys.exit(app.exec_())
except:
print('Exiting')
Your logic is strange since you are creating 2 WelcomeScreen: One added to the QStackedWidget and the second as a window. Besides that, the QStackedWidget has never been shown. And as the icing on the cake you don't limit the scopes of the variables.
Considering the above, it is better to create a controller that implements the logic of switching widgets and limits scopes.
import sys
from functools import cached_property
from PyQt5.uic import loadUi
from PyQt5.QtWidgets import QApplication, QDialog, QStackedWidget
class WelcomeScreen(QDialog):
def __init__(self):
super(WelcomeScreen, self).__init__()
loadUi("welcomescreen.ui", self)
class LoginScreen(QDialog):
def __init__(self):
super(LoginScreen, self).__init__()
loadUi("login.ui", self)
class Controller:
def __init__(self):
self.stacked_widget.addWidget(self.welcome)
self.stacked_widget.addWidget(self.login)
self.welcome.login.clicked.connect(self.goto_login)
#cached_property
def stacked_widget(self):
return QStackedWidget()
#cached_property
def welcome(self):
return WelcomeScreen()
#cached_property
def login(self):
return LoginScreen()
def goto_login(self):
self.stacked_widget.setCurrentWidget(self.login)
def main(args):
app = QApplication(args)
controller = Controller()
controller.stacked_widget.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main(sys.argv)
And finally, do not silence the exceptions since their reason for being is to indicate that something is wrong. I prefer that when the program fails then it shouts at me that a silent error since the latter is the cause of many bugs.

PyQt5 QMainWindow/QAxWidget thread problem

I want to have different thread between QMainWindow and QAxWidget.
As I know, QMainWindow should have MainThread.
So I write down code as below.
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
class Main_Thread(QtWidgets.QMainWindow):
def __init__(self):
# setting QMainWindow with widgets... + super().__init__()
sub_instance = Sub_Thread()
sub_thread = QtCore.QThread()
sub_instance.moveToThread(sub_thread)
sub_thread.started.connect(sub_instance.run)
sub_thread.start()
class Sub_Thread(QObject):
def __init__(self):
super().__init__()
def run(self):
ocx = QAxContainer.QAxWidget('connection path')
ocx.signal.connect(slot) # line★
ocx(AcitveX) have a lot of signal...
I have error that ocx has no that kind of signal when I write 'line★'
What that kind of problem is occurring?
ocx should be made in MainThread?

pyqtSignal() connects bool object instead of str

Let's say I have this snippet of code:
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import pyqtSignal
from ui_helloworld import Ui_MainWindow
from ui_hellodialog import Ui_Hi
from sys import argv
from sys import exit
class MainWindow(QMainWindow):
update = pyqtSignal(str)
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.h = HelloDialog()
self.ui.pushButton.clicked.connect(self.update_label)
self.ui.doIt.clicked.connect(self.h.update_label)
def update_label(self):
self.h.show()
def update_label_hello(self, msg):
self.update.emit(msg)
class HelloDialog(QDialog):
def __init__(self):
super(HelloDialog, self).__init__()
self.ui = Ui_Hi()
self.ui.setupUi(self)
def update_label(self, msg):
print msg
# Crashes the program:
# TypeError: setText(self, str): argument 1 has unexpected type 'bool'
# >> self.ui.label.setText(msg)
self.ui.label.setText("Hello world!")
def main():
app = QApplication(argv)
window = MainWindow()
window.show()
exit(app.exec_())
if __name__=="__main__":
main()
It's fairly simple. It's 2 windows, one is a QMainWindow and the other is a QDialog. The MainWindow has 2 buttons, pushButton and doIt:
pushButton opens the HelloDialog
doIt emit the update signal
The problem is, that the slot in HelloDialog Is receiving a boolean from the update signal in MainWindow, but I declared it as a str object.
Why does the the update_label slot receive a bool and not a str object?
localhost :: Documents/Python/qt » python main.py
{ push `doIt` object }
False
The Ui_MainWidow and Ui_Hi classes are pyuic5 generated.
I did not need to connect to self.h.update_label directly. I had to connect to the method inside MainWindow called update_label_hello to doIt, and then connect the pyqtSignal to the slot in HelloDialog
So, the final result is this:
init of MainWindow:
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.h = HelloDialog()
self.ui.pushButton.clicked.connect(self.update_label_)
self.ui.doIt.clicked.connect(self.update_label_hello)
self.update.connect(self.h.update_label)

Custom signals and multithreading

I've been trying to make this code work, but I still can't see where the flaw is.
I'm trying to emit the signal from a new thread, so the main receives the signal and executes a function.
If I try to do it within the same thread, everything works fine - but with this code, the thread is created, but the signal is never connected.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import QtCore
class WorkThread(QtCore.QThread):
def __init__(self):
QtCore.QThread.__init__(self)
def run(self):
print("From thread")
self.emit(QtCore.SIGNAL("trying"))
return
class Foo(QObject):
def handle_trigger(self):
print ("trigger signal received")
def new_thread(self):
self.get_thread = WorkThread()
self.connect(self.get_thread, QtCore.SIGNAL("trying"), self.handle_trigger)
self.get_thread.start()
a = Foo()
a.new_thread()
Edited based on comments.
There is one main problem with your code. You're not actually starting the Qt application, so there is no main event loop running. You must add the following lines:
app = QApplication(sys.argv)
app.exec_()
Also, you should use the new-style Qt signals/slots if possible, or if you stick with the old-style, know that the Qt Signal should be in the form of a C function if you want it to also work with PySide. To change this to work with PySide, it would be QtCore.SIGNAL("trying()"), not QtCore.SIGNAL("trying"). See the comments (specifically mine and #ekhumoro's comments) for details.
Here's a working version of your code (using the old-style signals/slots), I tried to change the least amount possible so that you could see the small changes. I had to use PySide instead, but it should work with PyQt as well:
from PySide.QtCore import *
from PySide.QtGui import *
from PySide import QtCore
import sys
class WorkThread(QtCore.QThread):
def __init__(self):
QtCore.QThread.__init__(self)
def run(self):
print("From thread")
self.emit(QtCore.SIGNAL("trying()"))
class Foo(QObject):
def handle_trigger(self):
print ("trigger signal received")
self.get_thread.quit()
self.get_thread.wait()
QApplication.quit()
def new_thread(self):
self.get_thread = WorkThread()
self.connect(self.get_thread, QtCore.SIGNAL("trying()"), self.handle_trigger)
self.get_thread.start()
a = Foo()
a.new_thread()
app = QApplication(sys.argv)
app.exec_()
And here's a version using the new signal/slot style (see #three_pineapples comment). This is the recommended way to implement signals/slots in PyQt/PySide.
from PySide.QtCore import *
from PySide.QtGui import *
from PySide import QtCore
import sys
class WorkThread(QtCore.QThread):
ranThread = QtCore.Signal()
# for PyQt, use QtCore.pyqtSignal() instead
def __init__(self):
QtCore.QThread.__init__(self)
def run(self):
print("From thread")
self.ranThread.emit()
class Foo(QObject):
def handle_trigger(self):
print ("trigger signal received")
self.get_thread.quit()
self.get_thread.wait()
QApplication.quit()
def new_thread(self):
self.get_thread = WorkThread()
self.get_thread.ranThread.connect(self.handle_trigger)
self.get_thread.start()
a = Foo()
a.new_thread()
app = QApplication(sys.argv)
app.exec_()
I muddled through this myself and I think this will work for you.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import QtCore
class WorkThread(QtCore.QThread):
def __init__(self):
QtCore.QThread.__init__(self)
tryThis = QtCore.Signal(str) #added this variable
def run(self):
print("From thread")
x = "trying"
self.tryThis.emit(QtCore.SIGNAL(x)) #pass your new variable like this
return
class Foo(QObject):
def handle_trigger(self):
print ("trigger signal received")
def new_thread(self):
self.get_thread = WorkThread()
self.get_thread.start()
self.get_thread.tryThis.connect(self.handle_trigger,QtCore.Qt.QueuedConnection) #passed it here
a = Foo()
a.new_thread()

textChanged event not triggering in Pyqt4

How come the textChanged event is not happening whenever I input some data in the QLineEdit?
from PyQt4.Qt import Qt, QObject,QLineEdit
from PyQt4.QtCore import pyqtSlot,SIGNAL,SLOT
from PyQt4 import QtGui, QtCore
import sys
class DirLineEdit(QLineEdit, QtCore.QObject):
"""docstring for DirLineEdit"""
#pyqtSlot(QtCore.QString)
def textChanged(self, string):
QtGui.QMessageBox.information(self,"Hello!","Current String is:\n"+string)
def __init__(self):
super(DirLineEdit, self).__init__()
self.connect(self,SIGNAL("textChanged(QString&)"),
self,SLOT("textChanged(QString *)"))
app = QtGui.QApplication(sys.argv)
smObj = DirLineEdit()
smObj.show()
app.exec_()
everything seems to be correct to me, what am I missing ?
Replace following line:
self.connect(self,SIGNAL("textChanged(QString&)"),
self,SLOT("textChanged(QString *)"))
with:
self.connect(self,SIGNAL("textChanged(QString)"),
self,SLOT("textChanged(QString)"))
Or you can use self.textChanged.connect (handler should be renamed because the name conflicts):
class DirLineEdit(QLineEdit, QtCore.QObject):
def on_text_changed(self, string):
QtGui.QMessageBox.information(self,"Hello!","Current String is:\n"+string)
def __init__(self):
super(DirLineEdit, self).__init__()
self.textChanged.connect(self.on_text_changed)

Categories

Resources