Linux 从后台工作线程修改 Qt GUI
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14545961/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Modify Qt GUI from background worker thread
提问by Emil Grigore
I work in Qt and when I press the button GO I need to continuously send packages to the network and modify the interface with the information I receive.
我在 Qt 中工作,当我按下按钮 GO 时,我需要不断地将包发送到网络并使用我收到的信息修改界面。
The problem is that I have a while(1)
in the button so the button never finishes so the interface is never updated. I thought to create a thread in the button and put the while(){}
code there.
问题是我while(1)
在按钮中有一个,所以按钮永远不会完成,所以界面永远不会更新。我想在按钮中创建一个线程并将while(){}
代码放在那里。
My question is how can I modify the interface from the thread? (For example how can I modify a textBox from the thread ?
我的问题是如何从线程修改接口?(例如,如何从线程修改文本框?
采纳答案by NIA
Important thing about Qt is that you mustwork with Qt GUI only from GUI thread, that is main thread.
关于 Qt 的重要一点是,您必须仅从 GUI 线程(即主线程)使用 Qt GUI。
That's why the proper way to do this is to notifymain thread from worker, and the code in main thread will actually update text box, progress bar or something else.
这就是为什么正确的方法是从 worker通知主线程,而主线程中的代码实际上会更新文本框、进度条或其他内容。
The best way to do this, I think, is use QThread instead of posix thread, and use Qt signalsfor communicating between threads. This will be your worker, a replacer of thread_func
:
我认为最好的方法是使用 QThread 而不是 posix 线程,并使用 Qt信号在线程之间进行通信。这将是你的工人,替代者thread_func
:
class WorkerThread : public QThread {
void run() {
while(1) {
// ... hard work
// Now want to notify main thread:
emit progressChanged("Some info");
}
}
// Define signal:
signals:
void progressChanged(QString info);
};
In your widget, define a slotwith same prototype as signal in .h:
在您的小部件中,定义一个与 .h 中的信号具有相同原型的插槽:
class MyWidget : public QWidget {
// Your gui code
// Define slot:
public slots:
void onProgressChanged(QString info);
};
In .cpp implement this function:
在 .cpp 中实现这个功能:
void MyWidget::onProgressChanged(QString info) {
// Processing code
textBox->setText("Latest info: " + info);
}
Now in that place where you want to spawn a thread (on button click):
现在在您想要生成线程的地方(单击按钮):
void MyWidget::startWorkInAThread() {
// Create an instance of your woker
WorkerThread *workerThread = new WorkerThread;
// Connect our signal and slot
connect(workerThread, SIGNAL(progressChanged(QString)),
SLOT(onProgressChanged(QString)));
// Setup callback for cleanup when it finishes
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
// Run, Forest, run!
workerThread->start(); // This invokes WorkerThread::run in a new thread
}
After you connect signal and slot, emiting slot with emit progressChanged(...)
in worker thread will send message to main thread and main thread will call the slot that is connected to that signal, onProgressChanged
here.
连接信号和插槽后,emit progressChanged(...)
在工作线程中发出插槽将向主线程发送消息,主线程将在onProgressChanged
此处调用连接到该信号的插槽。
P.s. I haven't tested the code yet so feel free to suggest an edit if I'm wrong somewhere
Ps 我还没有测试代码,所以如果我在某处错了,请随时提出编辑建议
回答by VB9-UANIC
you start thread passing some pointer to thread function (in posix the thread function have the signature void* (thread_func)(void*), something equal under windows too) - and you are completely free to send the pointer to your own data (struct or something) and use this from the thread function (casting pointer to proper type). well, memory management should be though out (so you neither leak memory nor use already freed memory from the thread), but this is a different issue
您开始线程传递一些指向线程函数的指针(在 posix 中,线程函数具有签名void* (thread_func)(void*),在 Windows 下也相同)-并且您可以完全自由地将指针发送到您自己的数据(结构或其他东西)并从线程函数中使用它(将指针转换为正确的类型)。好吧,应该考虑内存管理(因此您既不会泄漏内存也不会使用已从线程中释放的内存),但这是一个不同的问题
回答by pra7
you can use invokeMethod() or Signals and slots mechanism ,Basically there are lot of examples like how to emit a signal and how to receive that in a SLOT .But ,InvokeMethod seems interesting .
您可以使用 invokeMethod() 或 Signals and slot 机制,基本上有很多示例,例如如何发出信号以及如何在 SLOT 中接收信号。但是,InvokeMethod 似乎很有趣。
Below is example ,where it shows How to change the text of a label from a thread:
下面是示例,其中显示了如何更改线程中的标签文本:
//file1.cpp
//file1.cpp
QObject *obj = NULL; //global
QLabel *label = new QLabel("test");
obj = label; //Keep this as global and assign this once in constructor.
Next in your WorkerThread you can do as below:
接下来在您的 WorkerThread 中,您可以执行以下操作:
//file2.cpp (ie.,thread)
//file2.cpp(即线程)
extern QObject *obj;
void workerThread::run()
{
for(int i = 0; i<10 ;i++
{
QMetaObject::invokeMethod(obj, "setText",
Q_ARG(QString,QString::number(i)));
}
emit finished();
}