C++ QT-主窗口不';除非它';关门了
我试图通过每500毫秒在线程中调用C++ QT-主窗口不';除非它';关门了,c++,qt,user-interface,C++,Qt,User Interface,我试图通过每500毫秒在线程中调用updateGUI函数来更新主窗口。除非关闭窗口,否则将显示该窗口,但不会使用新值进行更新。执行此操作时,将使用新值打开一个新窗口。我找到了,但它没有回答我的问题。我知道(如qt文档中所述) QApplication::exec进入主事件循环并等待 调用exit() 我尝试使用processEvents(),但主窗口反复打开和关闭,速度非常快,我甚至看不到它。这是我的密码: float distanceToObject; bool objectDetected;
updateGUI
函数来更新主窗口。除非关闭窗口,否则将显示该窗口,但不会使用新值进行更新。执行此操作时,将使用新值打开一个新窗口。我找到了,但它没有回答我的问题。我知道(如qt文档中所述)
QApplication::exec
进入主事件循环并等待
调用exit()
我尝试使用processEvents()
,但主窗口反复打开和关闭,速度非常快,我甚至看不到它。这是我的密码:
float distanceToObject;
bool objectDetected;
Modes currentMode;
void timerStart(std::function<void(void)> func, unsigned int interval)
{
std::thread([func, interval]()
{
while (true)
{
auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
func();
std::this_thread::sleep_until(x);
}
}).detach();
}
int updateGUI(void)
{
int argc = 0;
char **argv = NULL;
QApplication a(argc, argv);
MainWindow w;
// Set text of a label
w.setDistance(QString::number(distanceToObject));
// Also update objectDetected and currentMode values
w.show();
//a.processEvents();
return a.exec();
}
void sendMsg(void)
{
// Send heartbeat signal to another device
}
void receiveMsg(void)
{
// Read messages from the other device and update the variables
// These two values change continuously
objectDetected = true;
distanceToObject = 5.4;
}
void decide(void)
{
// The core function of the program. Takes relatively long time
// Run a decision-making algorithm which makes decisions based on the values received from the other device.
// Update some variables according to the made decisions
currentMode = Auto;
// Execute functions according to the made decisions.
setMode(currentMode);
}
int main(void)
{
timerStart(updateGUI, 500);
timerStart(sendMsg, 1000);
timerStart(receiveMsg, 10);
timerStart(decide, 500);
}
浮动距离对象;
检测到布尔对象;
模式电流模式;
void timerStart(std::function func,unsigned int interval)
{
线程([func,interval]()
{
while(true)
{
自动x=std::chrono::Standy_clock::now()+std::chrono::毫秒(间隔);
func();
std::this_thread::sleep_until(x);
}
}).detach();
}
int updateGUI(void)
{
int argc=0;
字符**argv=NULL;
质量保证申请a(argc、argv);
主窗口w;
//设置标签的文本
w、 setDistance(QString::number(distanceToObject));
//同时更新objectDetected和currentMode值
w、 show();
//a、 processEvents();
返回a.exec();
}
void sendMsg(void)
{
//向其他设备发送心跳信号
}
void receiveMsg(void)
{
//从其他设备读取消息并更新变量
//这两个值不断变化
objectDetected=true;
距离对象=5.4;
}
作废决定(作废)
{
//程序的核心功能。需要相对较长的时间
//运行决策算法,该算法根据从其他设备接收到的值做出决策。
//根据做出的决策更新一些变量
电流模式=自动;
//根据做出的决策执行功能。
设置模式(当前模式);
}
内部主(空)
{
timerStart(updateGUI,500);
timerStart(sendMsg,1000);
timerStart(接收消息,10);
timerStart(决定,500);
}
如何使用变量的值正确更新主窗口?您的线程不会更新
MainWindow
,但会在每次迭代中创建一个全新的QApplication
和MainWindow
。在退出应用程序(例如关闭窗口)之前,您的线程应该卡在QApplication::exec
内。只有这样,线程的循环才能取得进一步的进展
通常,从主线程外部执行更新时必须非常小心,因为通常GUI操作必须在主线程内部执行
考虑使用QThread
,它已经附带了自己的事件循环,您可以使用它来通知/更新使用相应插槽的窗口
如果没有关于你真正想要达到的目标的更多细节,就不可能给你更多的方向。一、 至少,建议您在主线程内创建QApplication
和main窗口
(例如main
)。然后,这取决于您试图“更新”的内容。如果您需要处理一些数据,那么您可以在第二个线程中执行该操作,并使用信号槽将结果发送到MainWindow
实例。如果需要在窗口上绘制,则必须直接在主线程中完成,或者可以找到一种方法从线程中渲染到单独的缓冲区(即QImage
),然后将此缓冲区发送到主线程,以便将其绘制到窗口中
我试图勾勒出这样的事情是如何做到的。然而,请注意,它既不完整也不可编译,只是一个大纲 首先,您有一个
main窗口
,并在其中添加一个信号
,通知所有观察者开始工作(稍后将变得清晰)。此外,您还添加了插槽
,每当您的某个值发生更改时,将调用这些插槽。这些插槽
在主线程中运行(并且是主窗口
的成员),因此可以根据需要更新窗口:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
// constructors and stuff
void startWorking()
{
emit startWorkers();
}
public slots:
void onModeChanged(Modes m)
{
// update your window with new mode
}
void onDistanceChanged(float distance)
{
// update your window with new distance
}
signals:
void startWorkers();
};
接下来,构建一个Worker
类,该类封装了您喜欢做的所有“后台工作”(基本上是您的线程在原始代码中所做的):
请注意,Worker
必须继承QObject
,并且您的doWork
方法必须是公共插槽。此外,您还可以为要通知的主窗口
的每个值添加一个信号
。它们不需要实现,因为它是由Qt-MOC(元对象编译器)生成的。每当相应值中的一个发生变化时,只需发出相应的信号
并传递新值即可
最后,你把所有的东西放在一起:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow window;
// create a worker object
Worker* worker = new Worker;
// connect signals and slots between worker and main window
QObject::connect(worker, &Worker::modeModified,
&window, &MainWindow::onModeChanged);
QObject::connect(worker, &Worker::distanceModified,
&window, &MainWindow::onDistanceChanged);
QObject::connect(&window, &MainWindow::startWorkers,
worker, &Worker::doWork);
// create a new thread
QThread* thread = new QThread;
// send worker to work inside this new thread
worker->moveToThread(thread);
thread->start();
// show window and start doing work
window.show();
window.startWorking();
// start main loop
int result = app.exec();
// join worker thread and perform cleanup
return result;
}
好吧,让我们来看看。首先,在主线程内创建QApplication
和MainWindow
。接下来,创建Worker
对象的一个实例(可以在这里创建多个)。然后将工作人员的信号连接到窗口的插槽,反之亦然。一旦建立了这些连接,每当发出信号时,Qt就会调用连接的插槽(并传输传递的值)。请注意,此连接跨线程边界工作。每当从与接收对象的线程不同的线程发出信号时,Qt将发送一条消息,该消息在接收对象的线程中处理
然后,使用QObject::moveToThread
告诉Qt您希望您的工作线程生活在另一个线程中。有关如何正确使用QThread
及其内部对象的详细说明,请参阅
其余的是
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow window;
// create a worker object
Worker* worker = new Worker;
// connect signals and slots between worker and main window
QObject::connect(worker, &Worker::modeModified,
&window, &MainWindow::onModeChanged);
QObject::connect(worker, &Worker::distanceModified,
&window, &MainWindow::onDistanceChanged);
QObject::connect(&window, &MainWindow::startWorkers,
worker, &Worker::doWork);
// create a new thread
QThread* thread = new QThread;
// send worker to work inside this new thread
worker->moveToThread(thread);
thread->start();
// show window and start doing work
window.show();
window.startWorking();
// start main loop
int result = app.exec();
// join worker thread and perform cleanup
return result;
}
class Worker : public QObject
{
Q_OBJECT
public:
Worker()
{
QObject::connect(&modeTimer_, &QTimer::timeout,
this, &Worker::onModeTimerTimeout);
QObject::connect(&distanceTimer_, &QTimer::timeout,
this, &Worker::onDistanceTimerTimeout);
modeTimer_.start(500); // emit timeout() every 500ms
distanceTimer_.start(100); // emit timeout() every 100ms
}
public slots:
void onModeTimerTimeout()
{
// recompute mode
Modes m = // ...
emit modeModified(m);
}
void onDistanceTimerTimeout()
{
// recompute distance
float distance = // ...
emit distanceModified(distance);
}
signals:
void modeModified(Modes m);
void distanceModified(float distance);
private:
QTimer modeTimer_;
QTimer distanceTimer_;
};