Using QThread , Signal() , Slot() So GUI won't freeze
- 
I try to run task upon button press the task should run on thread so the GUI won't freeze , I have mythread class button and 2 functions that will run in chain on after another , 
 function 1 - run_packet_task() calls
 function 2 - packet_handler(arg1,arg2...etc) - will update the guifunction 1 should start running when button clicked 
 function 2 called by function 1 & updates the guiI don't understand how to set this up // on On clicked , run on_Start_Capture_pushButton_clicked 
 connect(ui->Start_Capture_pushButton,&QPushButton::clicked ,this ,&MainWindow::on_Start_Capture_pushButton_clicked);// mySignal calls run_packet_task - signal emitted, slot executed 
 connect(thread, &mythread::on_Start_Capture_pushButton_clicked, this, &MainWindow::run_packet_task);Where should I implement signal and slot function so the gui will stay responsive on_Start_Capture_pushButton_clicked
 is implemented in mainwindow.cppwhen the button is clicked, it triggers the on_Start_Capture_pushButton_clicked slot, which starts the thread. As the thread runs, it emits the mySignal, which in turn executes the run_packet_task slot in the MainWindow class. Inside the run_packet_task slot, you can call the packet_handler function or perform any other desired operations. here is all the files : mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QMutex> #include <QString> #include "mythread.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class CaptureThread; // Forward declaration class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_Start_Capture_pushButton_clicked(); void run_packet_task(); void on_Stop_Capture_pushButton_clicked(); signals: void startCapture(); void mySignal(); private: Ui::MainWindow *ui; QMutex uiMutex; mythread *thread; //CaptureThread* captureThread; }; #endif // MAINWINDOW_Hmythread.h #ifndef MYTHREAD_H // mythread.h #define MYTHREAD_H #include <QThread> class mythread : public QThread { Q_OBJECT public: explicit mythread(QObject *parent = nullptr); void run() override; signals: void mySignal(); public slots: void on_Start_Capture_pushButton_clicked(); void mySlot(); }; #endif // MYTHREAD_Hmain.cpp #include "mainwindow.h" #include <QApplication> #include "mythread.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; mythread thread; w.show(); return a.exec(); }mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include <iomanip> #include <qmessagebox.h> #include <iostream> #include <WinSock2.h> #include <pcap.h> #include <ws2tcpip.h> #include <iphlpapi.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") #define NUM_PACKETS_TO_CAPTURE 10 #include <sstream> #include <QMutex> #include <QThread> #include "mythread.h" QMutex uiMutex; Ui::MainWindow* ui; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ::ui = ui; ui->setupUi(this); // Create an instance of MyThread thread = new mythread(this); // on On clicked , run on_Start_Capture_pushButton_clicked connect(ui->Start_Capture_pushButton,&QPushButton::clicked ,this ,&MainWindow::on_Start_Capture_pushButton_clicked); // mySignal calls run_packet_task - signal emitted, slot executed connect(thread, &mythread::on_Start_Capture_pushButton_clicked, this, &MainWindow::run_packet_task); //connect(ui->Start_Capture_pushButton, &QPushButton::clicked, this, &MainWindow::on_Start_Capture_pushButton_clicked); pcap_if_t* alldevs = nullptr; // Initialize the pointer to nullptr char errbuf[PCAP_ERRBUF_SIZE]; if (pcap_findalldevs(&alldevs, errbuf) == -1) { std::cerr << "Error finding network interfaces: " << errbuf << std::endl; //return nullptr; // Return nullptr on error } for (pcap_if_t* dev = alldevs; dev != nullptr; dev = dev->next) { // Display the adapter index and description ui->Choose_Adapter_comboBox->addItem(dev->description); // Increment the adapter index for the next adapter } } MainWindow::~MainWindow() { delete ui; } void packet_handler(u_char* user_data, const struct pcap_pkthdr* packet_header, const u_char* packet_data) { // Cast the user_data to a pointer of the desired type, if needed // Example: MyData* data = reinterpret_cast<MyData*>(user_data); // Create a stringstream to hold the packet information std::stringstream packetInfo; // Add packet information to the stringstream packetInfo << std::endl; packetInfo << "Packet Information:" << std::endl; packetInfo << "Capture Length: " << std::setw(5) << packet_header->caplen << std::endl; packetInfo << "Packet Length: " << std::setw(5) << packet_header->len << std::endl; packetInfo << "Packet Data:" << std::endl; // Print packet data as hexadecimal and ASCII int byte_count = 0; for (int i = 0; i < packet_header->caplen; i++) { packetInfo << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(packet_data[i]) << " "; byte_count++; // Add extra space after every 8 bytes for better readability if (byte_count % 8 == 0) packetInfo << " "; // Add newline after every 16 bytes and print ASCII representation if (byte_count % 16 == 0) { packetInfo << "| "; for (int j = i - 15; j <= i; j++) { if (packet_data[j] >= 32 && packet_data[j] <= 126) packetInfo << static_cast<char>(packet_data[j]); else packetInfo << "."; } packetInfo << std::endl; } } // Convert the packetInfo stringstream to a string std::string packetInfoString = packetInfo.str(); QString packetInfoQString = QString::fromStdString(packetInfoString); // Use QMutexLocker to lock the UI access while appending the text QMutexLocker locker(&uiMutex); ui->Packet_textBrowser->append(packetInfoQString); }void MainWindow::run_packet_task() { QString selectedDev_qt = ui->Choose_Adapter_comboBox->currentText(); char errbuf[PCAP_ERRBUF_SIZE]; pcap_if_t* alldevs = nullptr; pcap_if_t* selectedDev = nullptr; for (pcap_if_t* dev = alldevs; dev != nullptr; dev = dev->next) { if (selectedDev_qt == dev->description) { selectedDev = dev; break; } } pcap_t* handle = pcap_open_live(selectedDev->name, BUFSIZ, 1, 1000, errbuf); if (handle == nullptr) { std::cerr << "Error opening interface for packet capture: " << errbuf << std::endl; pcap_freealldevs(alldevs); } // Set the packet capture callback function QMutexLocker unlock(&uiMutex); pcap_loop(handle, NUM_PACKETS_TO_CAPTURE, packet_handler, nullptr); // Close the packet capture handle pcap_close(handle); // Free the allocated memory for the interface list pcap_freealldevs(alldevs);} void MainWindow::on_Start_Capture_pushButton_clicked() { //thread->start(); emit thread->mySignal(); //emit mySignal(); } void MainWindow::on_Stop_Capture_pushButton_clicked() { ui->Packet_textBrowser->clear(); }mythread.cpp #include "mythread.h" mythread::mythread(QObject *parent) : QThread(parent) { } void mythread::mySlot() { } void mythread::run() { }@__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: I try to run task upon button press the task should run on thread so the GUI won't freeze , I have mythread class button 
 and 2 functions that will run in chain on after another ,The whole thing makes no sense. Why you want to have that on_button_clickedslot in your thread?You could put your task in a "worker" class ( QObjectand notQThread) and connect (inMainWindow) your start button to a function to start processing. In there you can emit your signals, to send results to yourMainWindowLike described here: Maybe this helps as well: 
 https://doc.qt.io/qt-6/threads-technologies.html
- 
@__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: I try to run task upon button press the task should run on thread so the GUI won't freeze , I have mythread class button 
 and 2 functions that will run in chain on after another ,The whole thing makes no sense. Why you want to have that on_button_clickedslot in your thread?You could put your task in a "worker" class ( QObjectand notQThread) and connect (inMainWindow) your start button to a function to start processing. In there you can emit your signals, to send results to yourMainWindowLike described here: Maybe this helps as well: 
 https://doc.qt.io/qt-6/threads-technologies.html@Pl45m4 Thank you for the fast response, though i don't understand your answer except of the reference to the documentation as far as i know 
 connect(object 1,signal ,object2,slot);
 this part is very simple as far as I use 2 class object , or another thread i want to interact with , but , here I have the main thread which is object1 - ui in my case and button which is object2so it's get confusing to implement that , 
 i need anther thread ? if so how I do that ?
 what i put inside signal and where I put the signal() function ?
 i understand the basics and more but I don't understand how Iimplemnt it in my case
- 
@Pl45m4 Thank you for the fast response, though i don't understand your answer except of the reference to the documentation as far as i know 
 connect(object 1,signal ,object2,slot);
 this part is very simple as far as I use 2 class object , or another thread i want to interact with , but , here I have the main thread which is object1 - ui in my case and button which is object2so it's get confusing to implement that , 
 i need anther thread ? if so how I do that ?
 what i put inside signal and where I put the signal() function ?
 i understand the basics and more but I don't understand how Iimplemnt it in my case@__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: as far as i know 
 connect(object 1,signal ,object2,slot);That's correct, but it's not about how you connect, you should rework your whole structure Have a look at the table here to find out what you really want/need. Find out if your pcap lib (or the function you use from there) is async or not. Do you want to click start, capture X packages and end? Then check out the "One call" rows. If you want to start it at some point and capture packages for a longer time (or permanent until you stop), then have a look at the Worker approach in the 5th row and also in the other link. As it is right now, your pcap calls are in MainWindow and will block, even when you emit a signal from another thread to call that stuff. It's invoked by a signal across threads, but will still run in MainWindow's GUI thread and most likely block your GUI. 
- 
@__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: as far as i know 
 connect(object 1,signal ,object2,slot);That's correct, but it's not about how you connect, you should rework your whole structure Have a look at the table here to find out what you really want/need. Find out if your pcap lib (or the function you use from there) is async or not. Do you want to click start, capture X packages and end? Then check out the "One call" rows. If you want to start it at some point and capture packages for a longer time (or permanent until you stop), then have a look at the Worker approach in the 5th row and also in the other link. As it is right now, your pcap calls are in MainWindow and will block, even when you emit a signal from another thread to call that stuff. It's invoked by a signal across threads, but will still run in MainWindow's GUI thread and most likely block your GUI. Headers: mainwindow.h mythread.h network.h Sources: main.cpp mainwindow.cpp mythread.cpp network.cppi have created sepearate class for handling packets now i need to integrate it with the gui by threading 
 i have here few issues ,- 
but i dont understand how to implement this Creating Qthreads or using regualr threads ? 
 mainWindow runs on main thread so from this i understand i need to create QThread object since its QTapp
 then connecting this QThread object to relvant function , what's the relvant function ?
 its the start button which will start the packet_capture from the choosen device , and will update UI
 connect(object_1 , signal(), object_2 , slot()) 
 connect(ui->button, &QPushButton::clicked, myThread, &MyThread::handleButtonClicked);now the main issue is how i update the ui from the thread should use connect function from the thread ``` connect(myThread, signal_packet_handled, mainWindow::textBrowser , ? what should i use here ? )main_ui -> button clicked --> choosen_adpater_from_dropbox --> start_capture button clicked --> 1000 packets should be captured and printed to textBroswer boxi created each element by itself and this functionality works without threads how can it be done with threads so gui won't freeze 
- 
- 
Headers: mainwindow.h mythread.h network.h Sources: main.cpp mainwindow.cpp mythread.cpp network.cppi have created sepearate class for handling packets now i need to integrate it with the gui by threading 
 i have here few issues ,- 
but i dont understand how to implement this Creating Qthreads or using regualr threads ? 
 mainWindow runs on main thread so from this i understand i need to create QThread object since its QTapp
 then connecting this QThread object to relvant function , what's the relvant function ?
 its the start button which will start the packet_capture from the choosen device , and will update UI
 connect(object_1 , signal(), object_2 , slot()) 
 connect(ui->button, &QPushButton::clicked, myThread, &MyThread::handleButtonClicked);now the main issue is how i update the ui from the thread should use connect function from the thread ``` connect(myThread, signal_packet_handled, mainWindow::textBrowser , ? what should i use here ? )main_ui -> button clicked --> choosen_adpater_from_dropbox --> start_capture button clicked --> 1000 packets should be captured and printed to textBroswer boxi created each element by itself and this functionality works without threads how can it be done with threads so gui won't freeze @__d4ve__ 
 Without going into any specifics of your particular situation. The pretty simple, broad principle is: use signals and slots to exchange data/synchronise between threads. If the UI wants a thread to do something, send a signal, accompanied by whatever minimal data required. If a thread has done something and wants the UI to update, send a signal from the thread and the UI will do the updates in its slot. Do not directly read or write UI stuff in the thread.
- 
- 
@__d4ve__ 
 Without going into any specifics of your particular situation. The pretty simple, broad principle is: use signals and slots to exchange data/synchronise between threads. If the UI wants a thread to do something, send a signal, accompanied by whatever minimal data required. If a thread has done something and wants the UI to update, send a signal from the thread and the UI will do the updates in its slot. Do not directly read or write UI stuff in the thread.@JonB 
 I understand how it works but having troubles accomplish it in my prog , mostly because this function :pcap_loop(handle, NUM_PACKETS_TO_CAPTURE, packet_handler, nullptr);the following function loops through packet_handler and should print packets into textBrowser but i shouldn't involve any UI updates in external functions so the question is here how it supposed to work signal() , slot() the signal should be placed in the packet_handler function ? if so how should the connect function should be ? connect(object1 , signal() , object2 , slot() ) connect(thread, packet_handler_signal(&packet_info) , ui->txtBrowser, append_txtBrowserFunction() ) ?
- 
@JonB 
 I understand how it works but having troubles accomplish it in my prog , mostly because this function :pcap_loop(handle, NUM_PACKETS_TO_CAPTURE, packet_handler, nullptr);the following function loops through packet_handler and should print packets into textBrowser but i shouldn't involve any UI updates in external functions so the question is here how it supposed to work signal() , slot() the signal should be placed in the packet_handler function ? if so how should the connect function should be ? connect(object1 , signal() , object2 , slot() ) connect(thread, packet_handler_signal(&packet_info) , ui->txtBrowser, append_txtBrowserFunction() ) ?The struct pcap_pkthdr and the packet data are not to be freed by the callback routine, and are not guaranteed to be valid after the callback routine returns; if the code needs them to be valid after the callback, it must make a copy of them. So the first thing to do is to create a QByteArray with the data and emit the signal with it as a parameter. @__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: ui->txtBrowser, Usely the receiver is the top level object (window?) 
 So the signal should look like:dataReceived(const QByteArray data)and in the slot: MyWindow::appendData(const QByteArray data) { QString str=QString::fromLocal8bit(data); // or other conversions ui->textBrowser->append(str); }
- 
The struct pcap_pkthdr and the packet data are not to be freed by the callback routine, and are not guaranteed to be valid after the callback routine returns; if the code needs them to be valid after the callback, it must make a copy of them. So the first thing to do is to create a QByteArray with the data and emit the signal with it as a parameter. @__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: ui->txtBrowser, Usely the receiver is the top level object (window?) 
 So the signal should look like:dataReceived(const QByteArray data)and in the slot: MyWindow::appendData(const QByteArray data) { QString str=QString::fromLocal8bit(data); // or other conversions ui->textBrowser->append(str); }@mpergand 
 why I need byte array ?
 I added a new version of the code
 hope some of you could assist with itCan't put the pieces together ... 
 Button Clicked -> new thread created ( captures packets ) -> delivers it to -> UI -> ui.textbrowser get updated and so on in loop until packet limit exceeded ( about 1000 packets )
 ( everything working without threads but ui freezes )
- 
I have came up with this flow - 
We have UI main thread 
 we choose interface -> interface assigned to selected variable
- 
Start_button_clicked() -> Qt_thread created 
- 
Qt_thread -> runs packet_handling 
- 
Packet_handling -> update_ui(&Packet_info) 
 - Packet_info should be Locked under QMutex after sent to update_ui and Unlocked after UI updated
 
- 
- 
I have came up with this flow - 
We have UI main thread 
 we choose interface -> interface assigned to selected variable
- 
Start_button_clicked() -> Qt_thread created 
- 
Qt_thread -> runs packet_handling 
- 
Packet_handling -> update_ui(&Packet_info) 
 - Packet_info should be Locked under QMutex after sent to update_ui and Unlocked after UI updated
 the premiss of this examples are to call a long computation (fibonacci in this case) up on a button press and displaying the result on screen, without freeze. So exactly your situation https://github.com/DeiVadder/QtThreadExample in particular I would suggest WorkerObjectsubproject
 https://github.com/DeiVadder/QtThreadExample/tree/master/projects/WorkerObject
- 
- 
the premiss of this examples are to call a long computation (fibonacci in this case) up on a button press and displaying the result on screen, without freeze. So exactly your situation https://github.com/DeiVadder/QtThreadExample in particular I would suggest WorkerObjectsubproject
 https://github.com/DeiVadder/QtThreadExample/tree/master/projects/WorkerObject@J-Hilk This examples helped me alot to understand the concept , but the app still won't compile because of 3 errors , I updated the code and linked it 
- 
@J-Hilk This examples helped me alot to understand the concept , but the app still won't compile because of 3 errors , I updated the code and linked it @__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: but the app still won't compile because of 3 errors , What errors ? 
 No one will read the all code to find out !Anyway, i anticiped, you will fail by emiting a signal from your static callback :) You need to pass the address of your workObject as user param here: 
 int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, *u_char user)
 and make a cast in the callback:WorkerObject* wo=qobject_cast<WorkerObject*>(user);if it doesn't work, please post code and error texts here. 
- 
@__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: but the app still won't compile because of 3 errors , What errors ? 
 No one will read the all code to find out !Anyway, i anticiped, you will fail by emiting a signal from your static callback :) You need to pass the address of your workObject as user param here: 
 int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, *u_char user)
 and make a cast in the callback:WorkerObject* wo=qobject_cast<WorkerObject*>(user);if it doesn't work, please post code and error texts here. @mpergand That's the error I get : C:\Users\Dave\Desktop\C++ Exercises\Qt Creator Projects\Project 1 - Network Packet GUI\Packet_Capture_GUI\workerobject.cpp:54: error: C2352: 'workerobject::update_gui': a call of a non-static member function requires an object ..\Packet_Capture_GUI\workerobject.cpp(54): error C2352: 'workerobject::update_gui': a call of a non-static member function requires an object C:\Users\Dave\Desktop\C++ Exercises\Qt Creator Projects\Project 1 - Network Packet GUI\Packet_Capture_GUI\workerobject.h(29): note: see declaration of 'workerobject::update_gui'Here is my code for packet handling : void MainWindow::Packet_loop() { workerobject* worker = new workerobject(); QThread *thread_01 = new QThread(this); worker->moveToThread(thread_01); thread_01->start(); connect(thread_01 ,&QThread::started,worker, &workerobject::packet_looper); connect(worker, &workerobject::update_gui, this, &MainWindow::Update_textBrowser); } void MainWindow::Update_textBrowser(QString packetInfoQString) { ui->Packet_textBrowser->append(packetInfoQString); }signal declared this way : signals: void update_gui(QString packetInfoQString);that's how packet handling declaration looks like : public slots: void Update_textBrowser(QString packetInfoQString); // void Packet_loop(); private slots: void packet_handler(uchar* user_data, const struct pcap_pkthdr* packet_header, const uchar* packet_data);
- 
@mpergand That's the error I get : C:\Users\Dave\Desktop\C++ Exercises\Qt Creator Projects\Project 1 - Network Packet GUI\Packet_Capture_GUI\workerobject.cpp:54: error: C2352: 'workerobject::update_gui': a call of a non-static member function requires an object ..\Packet_Capture_GUI\workerobject.cpp(54): error C2352: 'workerobject::update_gui': a call of a non-static member function requires an object C:\Users\Dave\Desktop\C++ Exercises\Qt Creator Projects\Project 1 - Network Packet GUI\Packet_Capture_GUI\workerobject.h(29): note: see declaration of 'workerobject::update_gui'Here is my code for packet handling : void MainWindow::Packet_loop() { workerobject* worker = new workerobject(); QThread *thread_01 = new QThread(this); worker->moveToThread(thread_01); thread_01->start(); connect(thread_01 ,&QThread::started,worker, &workerobject::packet_looper); connect(worker, &workerobject::update_gui, this, &MainWindow::Update_textBrowser); } void MainWindow::Update_textBrowser(QString packetInfoQString) { ui->Packet_textBrowser->append(packetInfoQString); }signal declared this way : signals: void update_gui(QString packetInfoQString);that's how packet handling declaration looks like : public slots: void Update_textBrowser(QString packetInfoQString); // void Packet_loop(); private slots: void packet_handler(uchar* user_data, const struct pcap_pkthdr* packet_header, const uchar* packet_data);
- 
@__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: 'workerobject::update_gui': a call of a non-static member function requires an object Exactly what I said in my previous post. @mpergand I didn't understand your answer currently 
 the function looks like this :pcap_loop(handle ,NUM_PACKETS_TO_CAPTURE ,packet_handler , nullptr);try download the code i uploaded and run it in Qt Creator 
 if needed I can give you writing permissions to edit the codeI don't understand how to implement the solution you proposing 
- 
@mpergand I didn't understand your answer currently 
 the function looks like this :pcap_loop(handle ,NUM_PACKETS_TO_CAPTURE ,packet_handler , nullptr);try download the code i uploaded and run it in Qt Creator 
 if needed I can give you writing permissions to edit the codeI don't understand how to implement the solution you proposing 
- 
@__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: pcap_loop(handle ,NUM_PACKETS_TO_CAPTURE ,packet_handler , nullptr); pass this, instead of nullptr. 
- 
@__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze: pcap_loop(handle ,NUM_PACKETS_TO_CAPTURE ,packet_handler , nullptr); pass this, instead of nullptr. @mpergand said in Using QThread , Signal() , Slot() So GUI won't freeze: pcap_loop(handle ,NUM_PACKETS_TO_CAPTURE ,packet_handler , this);and in the callback: void workerobject::packet_handler(u_char* user_data, const struct pcap_pkthdr* packet_header, const u_char* packet_data) { ... WorkerObject* wo=qobject_cast<WorkerObject*>(user_data); assert(wo); wo->update_gui(...);
- 
@mpergand said in Using QThread , Signal() , Slot() So GUI won't freeze: pcap_loop(handle ,NUM_PACKETS_TO_CAPTURE ,packet_handler , this);and in the callback: void workerobject::packet_handler(u_char* user_data, const struct pcap_pkthdr* packet_header, const u_char* packet_data) { ... WorkerObject* wo=qobject_cast<WorkerObject*>(user_data); assert(wo); wo->update_gui(...);@mpergand Your solution doesn't work / not understandable packet_handler function just process the data and I use emit to pass the processed data to function which will update the GUI the main issue i encounter here is with static / not static functions errors i mentioned above , any way thank you for trying 
 


