我在后台套接字编程的QtGui应用程序上工作,我想从图形用户界面中的行编辑中获取IP地址和端口,并将其传递给QThread,线程是work,但我不能传递参数,我尝试使用构造函数,但它停止所有项目。
在开始QThread工作之前,我想从Gui中将参数传递给类中的构造函数或自定义函数。
此外,我需要使从套接字接收的数据绘图。所以为了解决这个问题,我尝试将对象指针传递给类,但是得到了很多bug
这里是线程代码和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;
}
发布于 2019-06-11 05:39:13
创建一个新的Worker
子类化QObject
类,并使用信号/插槽在您的worker和UI之间进行通信。
在我看来,每次要运行流程时创建一个新的worker比重用同一个worker要容易得多。因此,在创建新的worker之前,您必须删除该worker。您可以使用QObject::deleteLater
插槽来实现此目的。
当您必须将结果发送到UI时,您需要在Worker
类中触发一个信号,并且在您的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;
};
调用worker并显示从它接收到的结果的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;
};
https://stackoverflow.com/questions/56531707
复制相似问题