Search code examples
pythonsocketspyqtpyqt5qthread

How to send packet data to dialog?


I made some received tcp packet dialog by pyqt5.
This code are load dialog, call receive tcp packet in qthread.
I want to send packet data to dialog.
How to send?

It's my code.

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import socketserver


class MyTCPHandler(socketserver.StreamRequestHandler):
    def handle(self):
        try:
            data = self.rfile.read(28)
            # how to send packet data to dialog?

        except Exception as e:
            print('MyTCPHandler.handle exception error: ', e)


class TestThread(QThread):
    HOST, PORT = '192.168.0.100', 8484

    def __init__(self, parent=None):
        super().__init__()

    def receive_packet(self):
        socketserver.TCPServer.allow_reuse_address = True
        server = socketserver.TCPServer((self.HOST, self.PORT), MyTCPHandler)
        server.serve_forever()

    def run(self):
        print('run thread')
        self.receive_packet()


class TestGUI(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.btn1 = QPushButton("start thread", self)
        self.textbox1 = QLineEdit(self)
        vertBox = QVBoxLayout()
        vertBox.addWidget(self.btn1)
        vertBox.addWidget(self.textbox1)
        self.setLayout(vertBox)
        self.setGeometry(700, 500, 300, 100)
        self.btn1.clicked.connect(self.threadStart)
        self.show()

        self.th = TestThread(self)


    @pyqtSlot()
    def threadStart(self):
        self.th.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    form = TestGUI()
    app.exec_()


Solution

  • To send the information of a thread you can use QMetaObject.invokeMethod(), so it is necessary to pass the GUI, and in this case we take advantage that the parent of the QThread is the GUI.

    You can set a new property to pass the GUI to the handler, and from the handler access that property through self.server.

    Finally, we implemented a slot that receives the information.

    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    import socketserver
    
    
    class MyTCPHandler(socketserver.StreamRequestHandler):
        def handle(self):
            try:
                data = self.rfile.read(28)
                QMetaObject.invokeMethod(self.server.w, "setData",
                    Qt.QueuedConnection, Q_ARG(bytes, data))
    
            except Exception as e:
                print('MyTCPHandler.handle exception error: ', e)
    
    
    class TestThread(QThread):
        HOST, PORT = '192.168.0.102', 8000
        def __init__(self, parent=None):
            super().__init__(parent)
    
        def receive_packet(self):
            socketserver.TCPServer.allow_reuse_address = True
            server = socketserver.TCPServer((self.HOST, self.PORT), MyTCPHandler)
            server.w = self.parent()
            server.serve_forever()
    
        def run(self):
            print('run thread')
            self.receive_packet()
    
    
    class TestGUI(QDialog):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.btn1 = QPushButton("start thread", self)
            self.textbox1 = QLineEdit(self)
            vertBox = QVBoxLayout()
            vertBox.addWidget(self.btn1)
            vertBox.addWidget(self.textbox1)
            self.setLayout(vertBox)
            self.setGeometry(700, 500, 300, 100)
            self.btn1.clicked.connect(self.threadStart)
            self.show()
    
            self.th = TestThread(self)
    
        @pyqtSlot(bytes)
        def setData(self, data):
            print(data)
    
        @pyqtSlot()
        def threadStart(self):
            self.th.start()
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        form = TestGUI()
        sys.exit(app.exec_())
    

    @Plus: with signals

    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    import socketserver
    
    
    class MyTCPHandler(socketserver.StreamRequestHandler):
        def handle(self):
            try:
                data = self.rfile.read(28)
                self.server.qthread.dataChanged.emit(data)
    
            except Exception as e:
                print('MyTCPHandler.handle exception error: ', e)
    
    
    class TestThread(QThread):
        HOST, PORT = '192.168.0.102', 8000
        dataChanged = pyqtSignal(bytes)
        def __init__(self, parent=None):
            super().__init__(parent)
    
        def receive_packet(self):
            socketserver.TCPServer.allow_reuse_address = True
            server = socketserver.TCPServer((self.HOST, self.PORT), MyTCPHandler)
            server.qthread = self
            server.serve_forever()
    
        def run(self):
            print('run thread')
            self.receive_packet()
    
    
    class TestGUI(QDialog):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.btn1 = QPushButton("start thread", self)
            self.textbox1 = QLineEdit(self)
            vertBox = QVBoxLayout()
            vertBox.addWidget(self.btn1)
            vertBox.addWidget(self.textbox1)
            self.setLayout(vertBox)
            self.setGeometry(700, 500, 300, 100)
            self.btn1.clicked.connect(self.threadStart)
            self.show()
    
            self.th = TestThread(self)
            self.th.dataChanged.connect(self.setData)
    
        @pyqtSlot(bytes)
        def setData(self, data):
            print(data)
    
        @pyqtSlot()
        def threadStart(self):
            self.th.start()
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        form = TestGUI()
        sys.exit(app.exec_())