我有一个程序,当它运行时,首先要求用户初始化系统。在该问题表单中,有 3 个复选框,用户可以为特定人员或每个人选中它们,并且系统会为该人员初始化与该复选框相关的项目。
选中复选框后,将调用特定函数和随后的特定类并完成初始化。
在mainwindow.cpp
中,我有:
InitializeDialog *id=new InitializeDialog;
connect(id,&InitializeDialog::initializeSignal,this,&MainWindow::initializeSlot);
id->exec();
id
是问题表单,其中包含 3 个复选框。和:
void MainWindow::initializeSlot(QStringList persons, bool interests, bool plots, bool graphs)
{
initializeMBox->setWindowTitle(tr("Initializing System")+"...");
initializeMBox->setText(tr("Please wait until initialization has been done") + ".<br>");
initializeMBox->show();
initializeMBox->setStandardButtons(0);
if (interests)//checkbox 1 is checked
initializeInterests(persons);
if (plots)//checkbox 2 is checked
initializePlots(persons);
if(graphs)//checkbox 3 is checked
initializeGraphs(persons);
initializeMBox->setStandardButtons(QMessageBox::Ok);
}
再说一遍:
void MainWindow::initializeInterests(QStringList persons)
{
for(int p=0;p<persons_comboBox_->count();p++)
{
persons_comboBox_->setCurrentIndex(p);
if (persons.contains(persons_comboBox_->currentText()))
{
//..
//create a specific class object and some specific functions
//..
//*
initializeMBox->setText(initializeMBox->text() + "<div><img src=":/tickIcon.png" height="10" width="10">" + " " + tr("Interests analyzed for the persons") + ": " + persons_comboBox_->currentText() + ".</div>");
}
}
}
initializePlots
和initializeGraphs
与initializeInterests
相似。
问题从这里开始:
我想在初始化后为每个人显示一条消息(正如我在initializeInterests
中提到的 star),但我的initializeMBox
(是一个QMessageBox
)不会连续显示消息,当所有人初始化时,所有消息都会突然显示。应该注意的是,我看到我的initializeMBox
越来越大,但似乎我的QMessageBox
被冻结了。
我不能使用QtConcurrent::run
因为我的QMessageBox
是通过我提到的 star 从mainwindow
(以及从基本线程)更新
的。如何获得持续更新的QMessageBox
?
-
不要重新进入事件循环。将
id->exec()
替换为id->show()
。管理对话框的生存期 - 也许根本不应该动态创建它。 -
不要阻止
initializeInterests
.与其更改组合框,不如获取其数据,将其发送到异步作业,在那里设置所有内容,然后将结果发回。 -
通过常量引用而不是值传递容器。
-
不要通过串联创建字符串。
-
如果输入人员列表很长,请对其进行排序以加快查找速度。
例如:
class StringSignal : public QObject {
Q_OBJECT
public:
Q_SIGNAL void signal(const QString &);
};
void MainWindow::initializeInterests(const QStringList &personsIn) {
auto in = personsIn;
std::sort(in.begin(), in.end());
QStringList persons;
persons.reserve(in.size());
for (int i = 0; i < persons_comboBox_->count(); ++i) {
auto const combo = persons_comboBox->itemText(i);
if (std::binary_search(in.begin(), in.end(), combo))
persons << combo;
}
QtConcurrent::run([persons = std::move(persons), w = this](){
StringSignal source;
connect(&source, &StringSignal::signal, w, [w](const QString & person){
w->initalizeMBox->setText(
QStringLiteral("%1 <div><img src=...> %2: %3.</div>")
.arg(w->initalizeMBox->text())
.arg(tr("Interests analyzed for the person"))
.arg(person)
);
});
for (auto &person : persons) { // persons is const
// create a specific object etc.
QThread::sleep(1); // let's pretend we work hard here
source.signal(person);
}
});
}
您提到的"特定对象"的创建不应访问 gui 线程中的任何内容。如果没有 - 传递所需数据的副本,或以线程安全的方式访问它。有时这是有意义的,而不是复制数据,而是将其移动到工作线程中,然后在工作线程完成后 - 通过 lambda 将其移回 GUI。