如何在 QThread 和 QGui 之间传递参数?

How to pass arguments between QThread and QGui?

我在 QtGui 应用程序上工作,在后台进行套接字编程我想从 gui 中的行编辑中获取 IP 地址和端口并将其传递给 QThread 线程正常工作,但我无法传递我尝试使用构造函数的参数,但它停止了所有项目。

我想在启动 QThread 之前将参数从 Gui 传递给 class 中的构造函数或自定义函数。

我还需要绘制从套接字接收到的数据。 所以解决这个问题的任何方法 我尝试将对象指针传递给 class 但出现了很多错误

这里是线程代码和ui代码

//client code
#include "clientclass.h"
#include <QThread>
#include <QDebug>

clientClass::clientClass(char *serverIp, unsigned int serverPort, char *idname ="SCR")
{
    this->ip=serverIp;
    this->port=serverPort;
    this->id=idname;


    std::cout<<ip<<port<<id<<std::endl;

};

int clientClass::connection()
{

    SOCKET socketDescriptor;
    int numRead;

    char id[20]="SCR";

    unsigned int maxEpisodes;
    unsigned int maxSteps;
    char trackName[1000];
    BaseDriver::tstage stage;

    tDriver drive;
    strcpy(drive.trackName,trackName);
    drive.stage = stage;


    tSockAddrIn serv_addr;
    struct timeval timeVal;
    fd_set readSet;
    char buf[UDP_MSGLEN];

    // Create a socket (UDP on IPv4 protocol)
    socketDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
    if (INVALID(socketDescriptor))
    {
        response = "Error: cannot create socket";
        return (1);
    }

    // Set some fields in the serverAddress structure.

    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port=htons((this->port));
    serv_addr.sin_addr.s_addr = inet_addr(this->ip);
    //std::cout<<serv_addr.sin_port<<std::endl;
    std::cout<<serv_addr.sin_addr.s_addr<<std::endl;

    bool shutdownClient=false;
    unsigned long curEpisode=0;
    do
    {

        do
        {
            // Initialize the angles of rangefinders
            float angles[19];
            drive.init(angles);
            string initString = SimpleParser::stringify(string("init"),angles,19);
            response =QString ("Sending id to server: %1").arg(id);
            initString.insert(0,id);
            response =QString("Sending init string to the server");
            if (sendto(socketDescriptor, initString.c_str(), initString.length(), 0,
                       (struct sockaddr *) &serv_addr,
                       sizeof(serv_addr)) < 0)
            {

                response ="Error: cannot send data ";
                CLOSE(socketDescriptor);
                return (1);
            }

            // wait until answer comes back, for up to UDP_CLIENT_TIMEUOT micro sec
            FD_ZERO(&readSet);
            FD_SET(socketDescriptor, &readSet);
            timeVal.tv_sec = 0;
            timeVal.tv_usec = UDP_CLIENT_TIMEUOT;

            if (select(socketDescriptor+1, &readSet, NULL, NULL, &timeVal))
            {
                // Read data sent by the solorace server
                memset(buf, 0x0, UDP_MSGLEN);  // Zero out the buffer.
                numRead = recv(socketDescriptor, buf, UDP_MSGLEN, 0);
                if (numRead < 0)
                {
                    response ="Error: didn't get response from server";
                }
        else
        {
                    response = "Received";

                    if (strcmp(buf,"***identified***")==0)
                            break;
                }
          }

        }  while(1);

    unsigned long currentStep=0;

        while(1)
        {
            // wait until answer comes back, for up to UDP_CLIENT_TIMEUOT micro sec
            FD_ZERO(&readSet);
            FD_SET(socketDescriptor, &readSet);
            timeVal.tv_sec = 0;
            timeVal.tv_usec = UDP_CLIENT_TIMEUOT;



            cout<<"in connection"<<endl;



            if (select(socketDescriptor+1, &readSet, NULL, NULL, &timeVal))
            {
                // Read data sent by the solorace server
                memset(buf, 0x0, UDP_MSGLEN);  // Zero out the buffer.
                numRead = recv(socketDescriptor, buf, UDP_MSGLEN, 0);

                if (numRead < 0)
                {
                    response = "Error : didn't get response from server";
                    CLOSE(socketDescriptor);
                    return (1);
                }

                if (strcmp(buf,"***shutdown***")==0)
                {
                    drive.onShutdown();
                    shutdownClient = true;
                    response="Client Shutdown";
                    break;
                }

                if (strcmp(buf,"***restart***")==0)
                {
                    drive.onRestart();
                    response ="Client Restart";
                    break;
                }
                /**************************************************
                 * Compute The Action to send to the solorace sever
                 **************************************************/

        if ( (++currentStep) != maxSteps)
        {
                    string action = drive.drive(string(buf));
                    memset(buf, 0x0, UDP_MSGLEN);
                    sprintf(buf,"%s",action.c_str());

        }
        else
            sprintf (buf, "(meta 1)");

                if (sendto(socketDescriptor, buf, strlen(buf)+1, 0,
                           (struct sockaddr *) &serv_addr,
                           sizeof(serv_addr)) < 0)
                {
                    response = "Error : cannot send data ";
                    CLOSE(socketDescriptor);
                    return (1);
                }
            }
            else
            {
                response ="Server did not respond in 1 second ";
            }
        }
    } while(shutdownClient==false && ( (++curEpisode) != maxEpisodes) );

    if (shutdownClient==false)
    drive.onShutdown();
    CLOSE(socketDescriptor);
    return 0;
}

>

// ui code 
<
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <time.h>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    thread =new QThread();
    QString response;

    mine = new clientClass("127",3001,"SCR");

    mine->moveToThread(thread);


    connect(thread, SIGNAL(started()),mine, SLOT(connection()));

}

MainWindow::~MainWindow()
{
    delete ui;
    delete thread;
    delete mine;
}

void MainWindow::on_pushButton_clicked()
{
    thread->start();

    if(thread->isRunning()) std::cout<< "is running"<<endl;


}

创建一个新的 class Worker Subclassing QObject 并使用 signals/slots 在您的工作人员和 UI 之间进行通信。

在我看来,每次您想 运行 流程时都创建一个新的 worker 比重用同一个 worker 更容易。因此,您必须在创建新工作人员之前删除该工作人员。您可以为此使用 QObject::deleteLater 插槽。

当您必须将结果发送到 UI 时,您需要在 Worker class 中触发一个信号,并且在 MainWindow 中需要一个插槽来处理结果。

您还需要一个标志来停止 worker 并打破无限循环。

一个工人的例子:

class MyWorker: public QObject
{
    Q_OBJECT
public:
    MyWorker(QString const& aAddress, unsigned int aPort, QObject* parent=nullptr): QObject(parent),
        address(aAddress), port(aPort)
    {}
    virtual ~MyWorker()
    {
        qDebug() << "Deleted" << address << port;
    }
public slots:
    void run()
    {
        running = true;
        int count = 0;
        while(running)
        {
            QCoreApplication::processEvents();
            for (int i = 0; i != 100000; ++i) { // Long time processing
            for (int i = 0; i != 100; ++i) {}
            }
            ++count;
            resultAvailable(QString("Loop count %1").arg(count));
        }
        finished(); // Inform that the worker has finished its task
    }

    void stop() // Call it to stop the thread
    {
        qDebug() << QThread::currentThreadId();
        running = false;
    }
signals:
    void resultAvailable(QString const&); // Will send message to the UI
    void finished();
private:
    QString address;
    unsigned int port;
    bool running;
};

一个 UI 调用工作器并显示从它收到的结果。

class MyWindow: public QWidget
{
    Q_OBJECT
public:
    MyWindow(QWidget* parent=nullptr): QWidget(parent),
    address(new QLineEdit),
    port(new QLineEdit),
    ok(new QPushButton("Run")),
    label(new QLabel())
    {

        QVBoxLayout* layout = new QVBoxLayout(this);
        layout->addWidget(address);
        layout->addWidget(port);
        layout->addWidget(ok);
        layout->addWidget(label);
        connect(ok, &QPushButton::clicked, this, &MyWindow::process);
    }
public slots:
    void process()
    {
        // Create a new worker and its thread
        QThread* workerThread = new QThread(this);
        MyWorker* worker = new MyWorker(address->text(), port->text().toUInt());
        worker->moveToThread(workerThread); // Put the worker in a dedicated thread

        connect(ok, &QPushButton::clicked, worker, &MyWorker::stop); // If user clicks on the ok btn again, delete the previous worker
        connect(worker, &MyWorker::resultAvailable, this, &MyWindow::processResult); // Process the data sent by the worker in the UI
        connect(worker, &MyWorker::finished, workerThread, &QThread::quit); // Stop the thread when the worker has finished
        connect(workerThread, &QThread::finished, workerThread, &MyWorker::deleteLater); // Delete the thread when finished
        connect(workerThread, &QThread::finished, worker, &MyWorker::deleteLater); // Delete the thread when finished
        connect(workerThread, &QThread::started, worker, &MyWorker::run); // Starts the worker when the thread is launched
        workerThread->start(); // The worker will be called
    }

    void processResult(QString const& result)
    {
        label->setText("The result: " + result);
    }
private:
    QLineEdit* address;
    QLineEdit* port;
    QPushButton* ok;
    QLabel* label;
};