So one of the few ways I know of, that transfers data from a thread to the main GUI thread of an application, is to place the data in a python Queue
. This Queue
is read by a QThread
(a Qt threading implementation that supports Qt signals and slots). The QThread
makes a blocking call to queue.get()
. When data is placed in the Queue
by your handle()
method, the QThread
unblocks, reads the data out of the queue, and emits a thread-safe signal to the GUI thread. As a demonstration, I added the data into the QTextEdit
.
So basically you need an intermediary between a python thread and the Qt GUI which generally interacts via signals/slots. The QThread performs this task, linking the thread-safe Queue
object, with the thread-safe qt signal emission.
This effectively follows a similar answer I gave here, but here you have a socket instead of a custom thread putting the data in the queue.
You might also be interested in this SO post, which explains why some of the lines of code I have used to make the QThread
and connect the signals, etc, are written in the order they are!
P.S. I added a line to shutdown the socket server when the app window is closed (the socket server used to keep running in the background)
Server Window code
import SocketServer
import concurrent.futures
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from Queue import Queue
HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
# create a global queue object that both the handle() method and the QThread (see later in the code) can access
queue = Queue()
class MyRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
print('...connected from:', self.client_address)
data = self.rfile.readline().strip()
print('Data from client %s' % data)
queue.put(data)
class ServerWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setGeometry(1500, 100, 500, 500)
self._control = QtGui.QWidget()
self.setCentralWidget(self._control)
l = QtGui.QVBoxLayout(self._control)
self.t = QtGui.QTextEdit()
l.addWidget(self.t)
self.executor = futures.ThreadPoolExecutor(max_workers=1)
self.startServerThread()
self.show()
@QtCore.pyqtSlot(str)
def receive_data(self, data):
self.t.moveCursor(QtGui.QTextCursor.End)
self.t.insertPlainText( data )
def startServerThread(self):
self.executor.submit(self.startServer)
# How to get information from the thread while it is still running?
def startServer(self):
print('starting server')
self.tcpServ = SocketServer.TCPServer(ADDR, MyRequestHandler)
print('waiting for connection...')
self.tcpServ.serve_forever()
# How to get information from the client (custom request handler)
# back to the GUI in a thread safe manner?
# This class runs in a QThread and listens on the end of a queue and emits a signal to the GUI
class MyReceiver(QtCore.QObject):
mysignal = QtCore.pyqtSignal(str)
def __init__(self,queue,*args,**kwargs):
QtCore.QObject.__init__(self,*args,**kwargs)
self.queue = queue
@QtCore.pyqtSlot()
def run(self):
while True:
text = self.queue.get()
self.mysignal.emit(text)
def launch():
app = QtGui.QApplication(sys.argv)
ex = ServerWindow()
# Create thread that will listen on the other end of the queue, and send the text to the textedit in our application
thread = QtCore.QThread()
my_receiver = MyReceiver(queue)
my_receiver.mysignal.connect(ex.receive_data)
my_receiver.moveToThread(thread)
thread.started.connect(my_receiver.run)
thread.start()
ret_code = app.exec_()
ex.tcpServ.shutdown()
sys.exit(ret_code)
if __name__ == '__main__':
launch()