在Qt的特定功能内不断更新QMessageBox



我有一个程序,当它运行时,首先要求用户初始化系统。在该问题表单中,有 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>");
}
}
}

initializePlotsinitializeGraphsinitializeInterests相似。

问题从这里开始:

我想在初始化后为每个人显示一条消息(正如我在initializeInterests中提到的 star),但我的initializeMBox(是一个QMessageBox)不会连续显示消息,当所有人初始化时,所有消息都会突然显示。应该注意的是,我看到我的initializeMBox越来越大,但似乎我的QMessageBox被冻结了。

我不能使用QtConcurrent::run因为我的QMessageBox是通过我提到的 star 从mainwindow(以及从基本线程)更新

的。如何获得持续更新的QMessageBox

  1. 不要重新进入事件循环。将id->exec()替换为id->show()。管理对话框的生存期 - 也许根本不应该动态创建它。

  2. 不要阻止initializeInterests.与其更改组合框,不如获取其数据,将其发送到异步作业,在那里设置所有内容,然后将结果发回。

  3. 通过常量引用而不是值传递容器。

  4. 不要通过串联创建字符串。

  5. 如果输入人员列表很长,请对其进行排序以加快查找速度。

例如:

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。

最新更新