gpt4 book ai didi

c++ - Qt - MainWindow 在运行时卡住

转载 作者:行者123 更新时间:2023-11-30 05:22:59 26 4
gpt4 key购买 nike

我试图从数据库中获取大量数据,但在运行主窗口时卡住。

我在 Windows 下工作并根据此 link 5秒后Windows自动将程序设置为挂起状态。

有什么方法可以防止卡住吗?

代码如下:

void MainWindow::on_getDataButtonClicked()
{
ui->centralWidget->setEnabled(false);
QApplication::setOverrideCursor(Qt::WaitCursor);
try
{
Client client(user, password);

std::future<map<string, map<string, string> > > fut =
std::async(std::launch::async, &Client::get_data, &client);

// While not all data has been retrieved, set message to the status bar.
while (fut.wait_for(std::chrono::seconds(0)) != std::future_status::ready)
{
ui->statusBar->showMessage("Getting data.");
std::this_thread::sleep_for(std::chrono::milliseconds(500));
ui->statusBar->showMessage("Getting data..");
std::this_thread::sleep_for(std::chrono::milliseconds(500));
ui->statusBar->showMessage("Getting data...");
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}

map<string, map<string, string> > exported_strings = std::move(fut.get());

ui->statusBar->showMessage("%All data has been retrieved!");
}
catch (std::string& s)
{
QMessageBox::critical(this, "Error", QString::fromStdString(s));
}
catch (std::exception& e)
{
QMessageBox::critical(this, "Error", QString(e.what()));
}
catch (...)
{
QMessageBox::critical(this, "Error", "An unknown error has occurred.");
}
ui->centralWidget->setEnabled(true);
QApplication::restoreOverrideCursor();
}

附带说明一下,调试时主窗口不会卡住。

最佳答案

如果您正在等待并在 while 循环中阻塞 GUI 线程,那么进行异步工作是没有意义的。您需要摆脱 while 循环。

您可以使用 QtConcurrent::run 而不是 std::async,并使用 QFutureWatcher 来获得异步通知,而不会阻塞,当异步任务已经完成。

// https://github.com/KubaO/stackoverflown/tree/master/questions/async-sane-39396761
#include <QtWidgets>
#include <QtConcurrent>
#include <map>
#include <string>

struct Client {
using result_type = std::map<std::string, std::map<std::string, std::string>>;
result_type get_data() {
QThread::sleep(5); // pretend to do some work
return result_type();
}
};

class MainWindow : public QMainWindow {
Q_OBJECT
Client::result_type exported_strings;
QWidget centralWidget;
QVBoxLayout layout{&centralWidget};
QPushButton getDataButton{"Get Data"};
QStatusBar statusBar;
QTimer statusTimer;
QString statusMessage;

void setBusyStatus(const QString & status) {
centralWidget.setEnabled(false);
QApplication::setOverrideCursor(Qt::WaitCursor);
statusMessage = status;
statusTimer.start(0);
}
void setNormalStatus(const QString & status) {
centralWidget.setEnabled(true);
QApplication::restoreOverrideCursor();
statusBar.showMessage(status);
statusTimer.stop();
}
Q_SLOT void on_getDataButtonClicked();
public:
MainWindow() {
setStatusBar(&statusBar);
setCentralWidget(&centralWidget);
layout.addWidget(&getDataButton);
int n = 0;
connect(&statusTimer, &QTimer::timeout, [=]() mutable {
statusBar.showMessage(QStringLiteral("%1%2").arg(statusMessage).arg(QString{n+1, QChar{'.'}}));
n = (n+1)%3;
statusTimer.start(500);
});
connect(&getDataButton, &QPushButton::clicked, this, &MainWindow::on_getDataButtonClicked);
}
};

void MainWindow::on_getDataButtonClicked()
{
auto future = QtConcurrent::run([=]{
Client client;
return client.get_data();
});
auto watcher = new QFutureWatcher<Client::result_type>{this};
connect(watcher, &QFutureWatcher<Client::result_type>::finished, this, [=]{
exported_strings = std::move(watcher->result());
watcher->deleteLater();
setNormalStatus("All data has been retrieved!");
});
watcher->setFuture(future);
setBusyStatus("Getting data");
}

int main(int argc, char ** argv) {
QApplication app{argc, argv};
MainWindow w;
w.show();
return app.exec();
}
#include "main.moc"

或者,您可以从异步代码中发出一个信号,让您保留 std::async 的使用,如果您愿意的话:

#include <QtWidgets>
#include <future>
#include <map>
#include <string>

struct Client {
using result_type = std::map<std::string, std::map<std::string, std::string>>;
result_type get_data() {
QThread::sleep(5); // pretend to do some work
return result_type();
}
};

class MainWindow : public QMainWindow {
Q_OBJECT
Client::result_type exported_strings;
QWidget centralWidget;
QVBoxLayout layout{&centralWidget};
QPushButton getDataButton{"Get Data"};
QStatusBar statusBar;
QTimer statusTimer;
QString statusMessage;

std::future<Client::result_type> resultFuture;

void setBusyStatus(const QString & status) {
centralWidget.setEnabled(false);
QApplication::setOverrideCursor(Qt::WaitCursor);
statusMessage = status;
statusTimer.start(0);
}
void setNormalStatus(const QString & status) {
centralWidget.setEnabled(true);
QApplication::restoreOverrideCursor();
statusBar.showMessage(status);
statusTimer.stop();
}
Q_SLOT void on_getDataButtonClicked();
Q_SIGNAL void hasResult();
public:
MainWindow() {
setStatusBar(&statusBar);
setCentralWidget(&centralWidget);
layout.addWidget(&getDataButton);
int n = 0;
connect(&statusTimer, &QTimer::timeout, [=]() mutable {
statusBar.showMessage(QStringLiteral("%1%2").arg(statusMessage).arg(QString{n+1, QChar{'.'}}));
n = (n+1)%3;
statusTimer.start(500);
});
connect(&getDataButton, &QPushButton::clicked, this, &MainWindow::on_getDataButtonClicked);
}
};

void MainWindow::on_getDataButtonClicked()
{
connect(this, &MainWindow::hasResult, this, [this](){
exported_strings = std::move(resultFuture.get());
setNormalStatus("All data has been retrieved!");
}, Qt::UniqueConnection);

resultFuture = std::async(std::launch::async, [this]{
Client client;
auto result = client.get_data();
emit hasResult();
return result;
});
setBusyStatus("Getting data");
}

int main(int argc, char ** argv) {
QApplication app{argc, argv};
MainWindow w;
w.show();
return app.exec();
}
#include "main.moc"

关于c++ - Qt - MainWindow 在运行时卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39396761/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com