Update PlainText from another Thread



  • Hello,

    I have a class "SerialReceiver" which received data in a seperate thread from the serial port. This class trigger a callback, when a valid telegram is received. This callback is defined as follows:

    void __stdcall SerialReceiver::ReceiveCallback(unsigned char, unsigned short, unsigned char*, int, void*);
    

    SerialReceiver.c:

    void SerialReceiver::Connect(char* Port, int Baud, void* obj, ReceiveCallback_t Callback)
    {
        Connect to serial port....
        pCallback = Callback;
        Parent = obj;
    }
    
    void __stdcall SerialInterface::SerialReceiver(unsigned char Data1, unsigned short Data2, unsigned char* Data3, int Data4, void* This)
    {
        SerialReceiver* sender = static_cast<SerialReceiver*>(p_This);
    
        sender->Callback(Data1, Data2, Data3, Data4, sender->Parent);
    }
    

    Now I have a class, named "Console" which inherit from a PlainText Object and I register a callback from this class to my SerialClass:

    Console.h:

        signals:
            void ReceiveSignal(unsigned char, unsigned short, unsigned char*, int, void*);
    
        private slots:
            void ReceiveSlot(unsigned char, unsigned short, unsigned char*, int, void*);
    
        private:
             static void __stdcall ReceiveCallback(unsigned char, unsigned short, unsigned char*, int, void*);
    

    Console.c:

    SerialInterface.Connect("COM1", 9600, this, &Console::ReceiveCallback);
    connect(this,
         SIGNAL(ReceiveSignal(unsigned char, unsigned short, unsigned char*, int, void*)),
          this,
          SLOT(ReceiveSlot(unsigned char, unsigned short, unsigned char*, int, void*)));
    
    void __stdcall Console::ReceiveCallback(unsigned char Data1, unsigned short Data2, unsigned char* Data3, int Data4, void* This)
    {  
        Console* sender = (Console*)This;
        Q_EMIT sender->ReceiveSlot(Data1, Data2, Data3, Data4, This);
    }
    
    void Console::ReceiveSlot(unsigned char Data1, unsigned short Data2, unsigned char* Data3, int Data4, void* This)
    {
        printMessage("Message received...");
        printMessage(">> Data1: 0x" + QString("%1").arg(Data1, 0, 16));
        printMessage(">> Data2: 0x" + QString("%1").arg(Data2, 0, 16));
    }
    
    void Console::printMessage(QString message)
    {
        this->insertPlainText(message+ "\n");
        QScrollBar *bar = verticalScrollBar();
        bar->setValue(bar->maximum());
    }
    

    I want to use the signal/slot to print the data, which I received from via serial port from another thread, into my PlainText.
    My programm crashes with the following message after some time working:

    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QTextDocument(0x17903298), parent's thread is QThread(0x178ee168), current thread is QThread(0x1794e698)
    

    How can I update my PlainText with the data I received from another thread?


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    You're not emitting ReceiveSignal, you're calling ReceiveSlot directly and ReceiveCallback is called from that other thread.

    Since you are getting data from a serial port, why not use QSerialPort and use signals and slots for the whole chain ? That will also allow you to avoid having that callback system.



  • Hello and thank you for your answer.

    my SerialReceiver is a standard C++ class, which I use in some other codes. The class contains some protocollhandling and error detection. I don´t want to write it again with QSerialPort, so I adapt my Qt code to the functionality of my C++ class.

    Edit: Think I solved it...thank you for your hint with the missing emit for the signal :)


  • Lifetime Qt Champion

    Then I'd recommend writing a small QObject wrapper around your SerialReceiver. That will make things more clear and clean.

    In any case, since you got it working, please mark the thread as solved using the "Topic Tools" button so that other forum members may know a solution has been found :)



  • I wrote something similar and the way I updated the plainTextEdit was indirectly. The thread would append to a QString (a buffer) then at regular intervals (using QTimer from the main thread) the buffer contents were transferred to the plainTextEdit from the main thread. The transfer and clear for the buffer requires something like a QMutex or equivalent so you are not clearing the buffer while it is being written from the other thread.

    The only downside is that the text is updated in blocks. I don't check the buffers from the main thread at a high frequency (once every 500 ms or something like that) but otherwise it works good.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.