Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Using QThread , Signal() , Slot() So GUI won't freeze
Forum Updated to NodeBB v4.3 + New Features

Using QThread , Signal() , Slot() So GUI won't freeze

Scheduled Pinned Locked Moved Unsolved General and Desktop
42 Posts 8 Posters 6.2k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • _ Offline
    _ Offline
    __d4ve__
    wrote on last edited by
    #1

    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 gui

    function 1 should start running when button clicked
    function 2 called by function 1 & updates the gui

    I 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.cpp

    when 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_H
    
    

    mythread.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_H
    
    

    main.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()
    {
    
    }
    
    Christian EhrlicherC Pl45m4P 2 Replies Last reply
    0
    • _ __d4ve__

      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 gui

      function 1 should start running when button clicked
      function 2 called by function 1 & updates the gui

      I 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.cpp

      when 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_H
      
      

      mythread.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_H
      
      

      main.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()
      {
      
      }
      
      Christian EhrlicherC Online
      Christian EhrlicherC Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @__d4ve__ said in Using QThread , Signal() , Slot() So GUI won't freeze:

      connect(thread, &mythread::on_Start_Capture_pushButton_clicked, this, &MainWindow::run_packet_task);

      How should this compile? Please provide a minimal, compilable example.

      Apert from this - you must not access the ui from outside the main (gui) thread.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      1
      • _ Offline
        _ Offline
        __d4ve__
        wrote on last edited by
        #3

        Created in Qt Creator 10.0.1 URL to the code Google Drive

        1 Reply Last reply
        0
        • _ __d4ve__

          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 gui

          function 1 should start running when button clicked
          function 2 called by function 1 & updates the gui

          I 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.cpp

          when 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_H
          
          

          mythread.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_H
          
          

          main.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()
          {
          
          }
          
          Pl45m4P Offline
          Pl45m4P Offline
          Pl45m4
          wrote on last edited by Pl45m4
          #4

          @__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_clicked slot in your thread?

          You could put your task in a "worker" class (QObject and not QThread) and connect (in MainWindow) your start button to a function to start processing. In there you can emit your signals, to send results to your MainWindow

          Like described here:

          • https://wiki.qt.io/QThreads_general_usage

          Maybe this helps as well:
          https://doc.qt.io/qt-6/threads-technologies.html


          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

          ~E. W. Dijkstra

          _ 1 Reply Last reply
          3
          • Pl45m4P Pl45m4

            @__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_clicked slot in your thread?

            You could put your task in a "worker" class (QObject and not QThread) and connect (in MainWindow) your start button to a function to start processing. In there you can emit your signals, to send results to your MainWindow

            Like described here:

            • https://wiki.qt.io/QThreads_general_usage

            Maybe this helps as well:
            https://doc.qt.io/qt-6/threads-technologies.html

            _ Offline
            _ Offline
            __d4ve__
            wrote on last edited by
            #5

            @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 object2

            so 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

            Pl45m4P 1 Reply Last reply
            0
            • _ __d4ve__

              @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 object2

              so 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

              Pl45m4P Offline
              Pl45m4P Offline
              Pl45m4
              wrote on last edited by Pl45m4
              #6

              @__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

              • https://doc.qt.io/qt-6/threads-technologies.html#example-use-cases

              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.


              If debugging is the process of removing software bugs, then programming must be the process of putting them in.

              ~E. W. Dijkstra

              _ 1 Reply Last reply
              2
              • Pl45m4P Pl45m4

                @__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

                • https://doc.qt.io/qt-6/threads-technologies.html#example-use-cases

                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.

                _ Offline
                _ Offline
                __d4ve__
                wrote on last edited by
                #7

                @Pl45m4

                Headers:
                  mainwindow.h				  
                  mythread.h
                  network.h
                
                Sources:
                  main.cpp
                  mainwindow.cpp
                  mythread.cpp
                  network.cpp
                

                i have created sepearate class for handling packets now i need to integrate it with the gui by threading
                i have here few issues ,

                1. 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 box
                

                i created each element by itself and this functionality works without threads how can it be done with threads so gui won't freeze

                JonBJ 1 Reply Last reply
                0
                • _ __d4ve__

                  @Pl45m4

                  Headers:
                    mainwindow.h				  
                    mythread.h
                    network.h
                  
                  Sources:
                    main.cpp
                    mainwindow.cpp
                    mythread.cpp
                    network.cpp
                  

                  i have created sepearate class for handling packets now i need to integrate it with the gui by threading
                  i have here few issues ,

                  1. 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 box
                  

                  i created each element by itself and this functionality works without threads how can it be done with threads so gui won't freeze

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #8

                  @__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.

                  _ 1 Reply Last reply
                  1
                  • JonBJ JonB

                    @__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.

                    _ Offline
                    _ Offline
                    __d4ve__
                    wrote on last edited by
                    #9

                    @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() ) ?
                    
                    M 1 Reply Last reply
                    0
                    • _ __d4ve__

                      @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() ) ?
                      
                      M Offline
                      M Offline
                      mpergand
                      wrote on last edited by
                      #10

                      @__d4ve__

                      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);
                      }
                      
                      _ 1 Reply Last reply
                      1
                      • M mpergand

                        @__d4ve__

                        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);
                        }
                        
                        _ Offline
                        _ Offline
                        __d4ve__
                        wrote on last edited by
                        #11

                        @mpergand
                        why I need byte array ?
                        I added a new version of the code
                        hope some of you could assist with it

                        Can'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 )

                        Qt Packet Capture Download

                        1 Reply Last reply
                        0
                        • _ Offline
                          _ Offline
                          __d4ve__
                          wrote on last edited by
                          #12

                          I have came up with this flow

                          1. We have UI main thread
                            we choose interface -> interface assigned to selected variable

                          2. Start_button_clicked() -> Qt_thread created

                          3. Qt_thread -> runs packet_handling

                          4. Packet_handling -> update_ui(&Packet_info)

                          • Packet_info should be Locked under QMutex after sent to update_ui and Unlocked after UI updated
                          J.HilkJ 1 Reply Last reply
                          0
                          • _ __d4ve__

                            I have came up with this flow

                            1. We have UI main thread
                              we choose interface -> interface assigned to selected variable

                            2. Start_button_clicked() -> Qt_thread created

                            3. Qt_thread -> runs packet_handling

                            4. Packet_handling -> update_ui(&Packet_info)

                            • Packet_info should be Locked under QMutex after sent to update_ui and Unlocked after UI updated
                            J.HilkJ Offline
                            J.HilkJ Offline
                            J.Hilk
                            Moderators
                            wrote on last edited by
                            #13

                            @__d4ve__

                            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 WorkerObject subproject
                            https://github.com/DeiVadder/QtThreadExample/tree/master/projects/WorkerObject


                            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                            Q: What's that?
                            A: It's blue light.
                            Q: What does it do?
                            A: It turns blue.

                            _ 1 Reply Last reply
                            3
                            • J.HilkJ J.Hilk

                              @__d4ve__

                              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 WorkerObject subproject
                              https://github.com/DeiVadder/QtThreadExample/tree/master/projects/WorkerObject

                              _ Offline
                              _ Offline
                              __d4ve__
                              wrote on last edited by
                              #14

                              @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

                              Qt Prog link to Google Drive

                              M 1 Reply Last reply
                              0
                              • _ __d4ve__

                                @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

                                Qt Prog link to Google Drive

                                M Offline
                                M Offline
                                mpergand
                                wrote on last edited by mpergand
                                #15

                                @__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.

                                _ 1 Reply Last reply
                                0
                                • M mpergand

                                  @__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.

                                  _ Offline
                                  _ Offline
                                  __d4ve__
                                  wrote on last edited by
                                  #16

                                  @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);
                                  
                                  M 1 Reply Last reply
                                  0
                                  • _ __d4ve__

                                    @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);
                                    
                                    M Offline
                                    M Offline
                                    mpergand
                                    wrote on last edited by
                                    #17

                                    @__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.

                                    _ 1 Reply Last reply
                                    0
                                    • M mpergand

                                      @__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.

                                      _ Offline
                                      _ Offline
                                      __d4ve__
                                      wrote on last edited by
                                      #18

                                      @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 code

                                      I don't understand how to implement the solution you proposing

                                      M 1 Reply Last reply
                                      0
                                      • _ __d4ve__

                                        @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 code

                                        I don't understand how to implement the solution you proposing

                                        M Offline
                                        M Offline
                                        mpergand
                                        wrote on last edited by
                                        #19

                                        @__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.

                                        _ M 2 Replies Last reply
                                        0
                                        • M mpergand

                                          @__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.

                                          _ Offline
                                          _ Offline
                                          __d4ve__
                                          wrote on last edited by __d4ve__
                                          #20

                                          @mpergand

                                          i don't have user variable , though i have user data on packet_handler , create object where and why

                                          WorkerObject* wo=qobject_cast<WorkerObject*>(user);
                                          

                                          Pass this instead of what ?
                                          how the code should look your solution isn't clear

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved