在 QDialog::exec() 期间使用 QThreads 执行 QWidget::grab()
Posted
技术标签:
【中文标题】在 QDialog::exec() 期间使用 QThreads 执行 QWidget::grab()【英文标题】:Using QThreads to execute QWidget::grab() during QDialog::exec() 【发布时间】:2017-03-02 20:13:34 【问题描述】:我编写了一个 Qt 程序,当用户上传某个数据文件并按下按钮时,会生成一系列图。当按下按钮时,程序将计算一系列计算并绘制一些图形,并在函数调用QDialog::exec()
上将它们显示在屏幕上。我想要实现的是grab
使用QWidget::grab()
生成的绘图的屏幕截图。所以基本上QWidget::grab()
在QDialog::exec()
之后被调用。但是由于QDialog::exec()
一直运行直到用户关闭特定窗口,所以在关闭窗口后调用QWidget::grab()
不会产生预期的结果。
这是我的代码的一部分;
在mainwindow.cpp
graphWindow.setWindowState(Qt::WindowMaximized);
graphWindow.exec();
graphWindow.savePlots();
在graphWindow.savePlots()
void GraphWindow::savePlots()
QStringList plotNames;
plotNames << "Income Statement (Plot A)" << "Income Statement (Plot B)" << "Balance Sheet (Plot A)"
<< "Balance Sheet (Plot B)" << "Cash Flow Plot" << "Holistic Stock Performance";
for(int item = 0; item < ui->graphTab->count(); item++)
ui->graphTab->setCurrentIndex(item);
QWidget * currentWidget = ui->graphTab->widget(item);
int height = currentWidget->height();
int width = currentWidget->width();
int x = currentWidget->x();
int y = currentWidget->y();
QRect grabRect(x,y,width,height);
//destImagePath is a global variable
QString imageFilePath = destImagePath;
imageFilePath.append(plotNames.at(item));
imageFilePath.append(".png");
currentWidget->grab(grabRect).save(imageFilePath);
//Reset to first tab after grab
ui->graphTab->setCurrentIndex(0);
我正在考虑通过运行另一个QThread
来绕过QDialog::exec()
,它在窗口仍在运行时执行GraphWindow::savePlots()
,以便屏幕抓取产生所需的结果。
有没有更好的方法来做到这一点?我认为创建一个新的QThread
只是为了调用一个函数是非常低效的。即使不是,您能否解释一下如何在并发QThreads
中实现。
【问题讨论】:
从工作线程调用小部件方法是错误的:只要 GUI 设计为在 UI 线程上运行,它可能工作也可能不工作。您应该只调用savePlots()
并执行对话框。只需在对话框退出之前执行此操作即可。
是在构造函数中调用它吗? (我知道它不会起作用,因为第一次创建对象时没有任何东西可以抓取)我如何从对话框中调用saveplots()
?我知道你的意思,但对如何实施它不是很有信心。如果您能详细说明会非常有帮助吗?
为什么来自构造函数?图片什么时候准备好?你应该知道。我们看不到。
哦,我认为图像应该已经显示在窗口中,以便 grab()
工作。这就是我在saveplots()
之前调用exec()
的原因。我会试试你说的。谢谢。
【参考方案1】:
在您的情况下,实际上不需要使用 QThread 或使用 QtConcurrent::run,您可以改为使用对主线程上的插槽的调用排队
QTimer::singleShot(0, &graphWindow, &GraphWindow::savePlots);
graphWindow.exec();
在您的情况下的优势在于它将在主线程上运行,因此您不必为捕获而烦恼线程、同步等(即使 Qt 使它更容易)。
这种方法的唯一限制是它会在捕获期间有效地“冻结”您的应用程序。这通常应该是可以接受的,因为它会明显少于一秒。
【讨论】:
像魅力一样工作。非常感谢。我对您的代码做了一些小调整(在编辑中添加)。以上是关于在 QDialog::exec() 期间使用 QThreads 执行 QWidget::grab()的主要内容,如果未能解决你的问题,请参考以下文章
在插槽中调用 QDialog::exec 会阻塞主事件循环吗?
关于Qt的事件循环以及QEventLoop的简单使用(QEventLoop::quit()能够终止事件循环,事件循环是可以嵌套的)