Ao executar um aplicativo com uma interface com janelas, é importante garantir que não haja congelamentos. Para isso, cálculos complexos devem ser executados em um encadeamento separado. O conceito de um aplicativo multiencadeado vai bem com a abordagem de slots de sinal Qt, sem a necessidade de redefinir qualquer método run ().
Ideia principal. Em uma aplicação multithread, os cálculos são realizados em uma thread separada, ao final é emitido um sinal, transmitindo o resultado em seus argumentos. Um slot já pertencente ao MainWindow será chamado. Os resultados do cálculo estarão nos argumentos do slot e não será difícil produzi-los.
Fazendo uma analogia com microcontroladores, um sinal é uma transição ao longo de um vetor de interrupção e um slot é um manipulador de interrupção. Para que uma “interrupção” ocorra, o sinal deve ser emitido: emitir mysignalvoid (); então o Qt começará a procurá-lo com um "manipulador" (slot). No Qt, você pode pendurar muitos slots em um único sinal.
A figura a seguir mostra o algoritmo do aplicativo demo. O segmento de processamento a cada segundo interroga de acordo com a legenda de um dispositivo USB HID. Em seguida, é emitido um sinal de emissão, que processa um slot que já pertence à MainWindow e que, consequentemente, tem a capacidade de desenhar no formulário.

Portanto, temos classes que podem usar a abordagem de slot de sinal. Para fazer isso, a declaração deles usa a macro Q_OBJECT.
class Worker : public QObject { Q_OBJECT
Para passar o resultado dos cálculos nos argumentos, é necessário
registrar os tipos usados para os argumentos. Você pode fazer isso em locais diferentes, mas geralmente no construtor da classe, que funcionará com estes tipos:
Worker::Worker(){ qRegisterMetaType<std::size_t>("size_t"); qRegisterMetaType<uint8_t const *>("uint8_t const *");
Em seguida, um cronômetro é criado no construtor do encadeamento de processamento. A cada segundo, o slot de processamento updateUSBDataCallback será chamado. Preste atenção à sintaxe da conexão do slot de sinal no Qt5.
this->timerDeviceRead = new QTimer(); connect(Worker::timerDeviceRead, &QTimer::timeout, this, &Worker::updateUSBDataCallback); this->timerDeviceRead->start();
A seguir, está o corpo do slot de thread de processamento. Todo o código de pensamento longo deve estar aqui.
void Worker::updateUSBDataCallback(){ size_t mysize = 65; uint8_t buf[65] = { "I like USB HID" }; emit GuiUpdatePlease(buf,mysize);
Para demonstrar aqui, imediatamente após o sinal ser emitido para o slot MainWindow, o conteúdo da matriz é modificado descaradamente. E como a matriz é passada pelo ponteiro, é obtida uma leitura suja. Para evitar essa situação, o sinal do encadeamento de processamento deve ser conectado ao slot GuiUpdateCallback () de uma certa maneira:
MainWindow::MainWindow{ connect(worker, &Worker::GuiUpdatePlease, this, &MainWindow::GuiUpdateCallback, Qt::BlockingQueuedConnection);
Nesse caso, emitindo um sinal, o encadeamento de processamento fica bloqueado até o final do slot GuiUpdateCallback ().
Se o longo "uint8_t const *" confunde você no texto do programa, você pode obter o sinônimo TU8PTR:
typedef uint8_t const * TU8PTR;
Código fonte