I'm running into a very strange error while using QThread
in PySide. As I run my code, when I click on the button that is supposed to launch the thread and send Signal
, I get :
AttributeError: 'builtin_function_or_method' object has no attribute 'displayText'
at line :
self.displayMessage.connect(self.window.displayText)
NB : displayText
is a method that I defined in my MainWindow(QWidget)
class, while displayMessage
is the signal to be emitted.
This error seems, according to the Internet, to occur in various situations, and I couldn't find one that suits my case yet. Therefore I have 2 questions :
- Have you guys ever met this error before in a similar situation, and could you (if yes) give me some tips ?
- Am I doing it right ? I can't post my code directly down here, so I created a short verifiable example in which I used the same process. Unfortunately, it seems to work perfectly. Please tell me if at least my construction is correct.
Thank you very much.
EDIT : I eventually figured out that I have forgotten a self
somewhere in my big code, but the actual error was hidden to me behind this one that I didn't know. I'm still interested in whether or not this code is reliable, and am fully open to suggestions of improvement.
Without thread
When you click "GO !" and try to move the window, you can see that it freezes for a second.
#!/usr/bin/env python
# -*- encoding : utf-8 -*-
import sys
import time
from PySide.QtCore import *
from PySide.QtGui import *
class MainWindow(QWidget):
def __init__(self, qt_app):
QWidget.__init__(self)
worker = Worker(self)
self.qt_app = qt_app
self.setGeometry(100, 100, 220, 40)
self.infoPanel = QTextEdit(self)
self.infoPanel.setReadOnly(True)
self.goButton = QPushButton('GO !', self)
self.goButton.clicked.connect(lambda: worker.displayOnWindow())
self.layout = QVBoxLayout()
self.layout.addWidget(self.infoPanel)
self.layout.addWidget(self.goButton)
self.setLayout(self.layout)
def launch(self):
self.show()
self.qt_app.exec_()
class Worker():
def __init__(self, window):
self.counter = 0
self.window = window
def displayOnWindow(self):
time.sleep(1)
self.window.infoPanel.append(str(self.counter))
self.counter += 1
if __name__=='__main__':
qt_app = QApplication(sys.argv)
mw = MainWindow(qt_app)
mw.launch()
With thread
Now you can move the window without trouble, since the sleeping thread is not the one that displays the window. I've written a sub-class for my thread because in the original code there are some functions that will be called by several buttons.
#!/usr/bin/env python
# -*- encoding : utf-8 -*-
import sys
import time
from PySide.QtCore import *
from PySide.QtGui import *
class MainWindow(QWidget):
def __init__(self, qt_app):
QWidget.__init__(self)
worker = SubWorker(self)
self.qt_app = qt_app
self.setGeometry(100, 100, 220, 40)
self.infoPanel = QTextEdit(self)
self.infoPanel.setReadOnly(True)
self.goButton = QPushButton('GO !', self)
self.goButton.clicked.connect(lambda: worker.start())
self.layout = QVBoxLayout()
self.layout.addWidget(self.infoPanel)
self.layout.addWidget(self.goButton)
self.setLayout(self.layout)
def launch(self):
self.show()
self.qt_app.exec_()
@Slot(int)
def displayOnWindow(self, i):
self.infoPanel.append(str(i))
class Worker(QThread):
displayMessage = Signal(int)
def __init__(self, window):
QThread.__init__(self)
self.counter = 0
self.window = window
self.displayMessage.connect(self.window.displayOnWindow)
def run(self, *args, **kwargs):
return QThread.run(self, *args, **kwargs)
class SubWorker(Worker):
def __init__(self, window):
Worker.__init__(self, window)
def run(self):
time.sleep(1)
self.displayMessage.emit(self.counter)
self.counter += 1
if __name__=='__main__':
qt_app = QApplication(sys.argv)
mw = MainWindow(qt_app)
mw.launch()
Aucun commentaire:
Enregistrer un commentaire