Reputation: 1538
I'm developping a simple UI for a TCP Server, and need to update the UI with log messages sent from the server, but the problem is that any connection to that server is in a separate thread, so I can't touch directly the UI's widgets (as they are not reentrant).
I've read some articles on the subject and chose what seems like the most elegant (and easy) way to do it: signals.
I've done the following :
class Ui_Dialog(QtCore.QObject):
def __init__(self):
super(QtCore.QObject, self).__init__()
def setupUi(self, Dialog):
Dialog.setObjectName(_fromUtf8("Dialog"))
Dialog.resize(800, 580)
self.serverLog = QtGui.QTextEdit(Dialog)
self.serverLog.setGeometry(QtCore.QRect(0, 0, 800, 480))
self.serverLog.setObjectName(_fromUtf8("serverLog"))
#OTHER WIDGETS AND CODE DEFINED HERE
self.server = None
#SIGNALS
self.clearLogButton.clicked.connect(self.serverLog.clear)
self.stopButton.clicked.connect(self.connectServer)
self.startButton.clicked.connect(self.connectServer)
def connectServer(self):
if (self.server is None):
host = str(self.ipEdit.text())
port = int(self.portEdit.text())
try:
self.server = server.MainServer((host, port), server.MyHTTPHandler)
self.server.setup(self)
self.printLog( "Hooray ! Server connected at {}:{}".format(host, port) )
# Start a thread with the server -- that thread will then start one more thread for each request
MainServer_thread = threading.Thread(target=self.server.serve_forever)
MainServer_thread.daemon = True
self.server.trigger.connect(QtCore.QObject(self.printLog))
MainServer_thread.start()
self.server.trigger.connect(self.printLog)
except errno.EADDRINUSE:
self.printLog("#ERROR: Address already in use. Try a different port.")
except errno.EADDRNOTAVAIL:
self.printLog("#ERROR: Address not available.")
def printLog(self, string):
self.serverLog.append(_fromUtf8(string))
And in the server class:
class MainServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
trigger = QtCore.pyqtSignal(str)
def printLog(self, message):
print message
self.trigger.emit(message)
But when I run my app, I get this message error :
TypeError: pyqtSignal must be bound to a QObject, not 'instance'
If there's any other (easy) way to update the UI from another thread (and class) or you know how to fix this error, please let me know !
Upvotes: 2
Views: 2325
Reputation: 1538
Just solved it using a medium object (of class QObject
) contained in my server class:
class Logger(QtCore.QObject):
trigger = QtCore.pyqtSignal(str)
def __init__(self):
super(Logger,self).__init__()
def send(self, string):
self.trigger.emit(string)
Upvotes: 1
Reputation:
That's pretty much this:
class Signals(QObject):
trigger = pyqtSignal(str)
To use them in MainServer
:
class MainServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
def __init__(self, parent=None):
self.signals = Signals()
self.signals.trigger.emit("triggered")
Upvotes: 3