- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试使用 QtConcurrent::run 在我的 MainWindow 类中执行一个函数,以便 UI 在计算期间保持响应。以下是我的实现方式:
void MainWindow::on_calculate_pb_clicked()
{
QFuture<void> future = QtConcurrent::run(this,&MainWindow::calculation);
}
void MainWindow::calculation()
{
progressBar->show();
loadMap();
integral.clear();
positions.clear();
offset.clear();
lines = 0;
for(int i=0;i<paths.size();i++)
{
if(i ==0)
{
lines = countNumberOfLines(paths.at(i));
}
double file = i+1;
ui->statusBar->showMessage(QString("Processing file %1 of %2").arg(file).arg(paths.size()));
calculateIntegral(paths.at(i));
offset.push_back(ui->tableWidget->item(i,1)->text().toDouble());
}
makePositionVector();
plotData(ui->customPlot);
ui->export_pb->setEnabled(true);
progressBar->hide();
ui->statusBar->showMessage("Done",3000);
}
void MainWindow::calculateIntegral(QString path)
{
QVector<double> mappeddata,tempdata;
mappeddata.resize(map.size());
tempdata.resize(numberofdetectors);
double currentLine = 0;
QFile File(path);
if(File.exists()==true){
File.open(QIODevice::ReadOnly);
QTextStream in(&File);
double val;
while(!in.atEnd())
{
for(int j = 0;j<numberofdetectors;j++)
{
in >> val;
tempdata[j]+=val;
currentLine++;
double progress = currentLine/lines*100;
progressBar->setValue(progress);
}
}
for(int i =0;i<map.size();i++)
{
mappeddata[i] = tempdata.at(map.at(i));
}
for(int k = 0;k<numberofdetectors; k++)
{
integral.push_back(mappeddata.at(k));
}
}
File.close();
}
它工作正常,用户界面响应迅速,进度条更新正确,但是在输出中我多次收到错误“QObject::setParent:无法设置父级,新父级在不同的线程中”循环执行。
知道是什么原因造成的,或者对更好地实现 QtConcurrent::run 有什么建议吗?
谢谢
最佳答案
您不能从工作线程中接触任何 Qt 提供的 QWidget
对象,因为它们的大多数方法都不是线程安全的。
相反,解决此问题的一种方法是在 worker 中进行计算,然后将更新状态的仿函数提交到主线程。参见 this answer了解详情。
您的代码将变为:
void MainWindow::calculation()
{
postToThread([this]{ progressBar->show(); });
loadMap();
integral.clear();
positions.clear();
offset.clear();
lines = 0;
for(int i=0;i<paths.size();i++)
{
if (i == 0)
lines = countNumberOfLines(paths.at(i));
auto file = i+1;
postToThread([this]{
ui->statusBar->showMessage(
tr("Processing file %1 of %2").arg(file).arg(paths.size()));
});
calculateIntegral(paths.at(i));
postToThread([this]{
offset.push_back(ui->tableWidget->item(i,1)->text().toDouble());
});
}
makePositionVector();
postToThread([this]{
plotData(ui->customPlot);
ui->export_pb->setEnabled(true);
progressBar->hide();
ui->statusBar->showMessage("Done",3000);
});
}
以类似的方式修改 calculateIntegral
,但请确保您不会过于频繁地发出进度更新。
还要确保 UI 代码不会在其他地方访问您从 worker 更新的成员。这可能很难,因为您混合了 UI 和计算。相反,将 worker 抽象为没有 UI 的 QObject
,并通过指示进度/状态的信号将其连接到其他代码。您仍将在该对象中使用 QtConcurrent::run
,但确保没有其他线程访问该对象的私有(private)状态变得更简单。
要将完成的结果从 worker 仿函数中推出,您可以发出一个包含结果的信号。 Data
类型的复制成本应该很低,例如您可以使用 QSharedData
/QSharedDataPointer
来实现它。或者您可以通过 QSharedPointer
保存它。
class Computation : public QObject {
Q_OBJECT
void work() {
Data data;
... // updates data
emit finished(data);
}
public:
Q_SLOT void compute() {
QtConcurrent::run(&Worker::work, this);
}
Q_SIGNAL void finished(Data data);
};
您还可以将结果存储在对象中,并注意在计算处于事件状态时不会访问它们:
class Computation : public QObject {
Q_OBJECT
bool m_active { false };
Data m_data;
void work() {
... // updates m_data
m_active = false;
}
public:
Q_SLOT void compute() {
m_active = true;
QtConcurrent::run(&Worker::work, this);
}
const Data & data() const {
Q_ASSERT(! m_active);
return m_data;
}
};
当然,如果您在主线程中存储对 data()
的引用,然后调用 compute()
,您将有未定义的行为,所以不要不要那样做。
如果任何数据类型是隐式共享容器,如 QVector
或 QString
,您应该按值返回它们,并且任何访问都是线程安全的:
QVector<MyData> data() const {
Q_ASSERT(! m_active);
return m_data;
}
请注意,QFile
是一个正确的 C++ 类。当它被破坏时,它会释放持有的任何资源。手动关闭文件是不必要的:编译器应该在这里帮助你,这就是 C++ 对象模型与例如Java 的。
关于c++ - QtConcurrent::run with MainWindow 函数,警告消息 "QObject::setParent: Cannot set parent, new parent is in a different thread",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38523509/
我有一个布局,我添加了很多自定义小部件,例如 layout.addWidget(widget) .稍后我想删除所有这些自定义小部件并添加新小部件。当谈到 deleteLater 时,我对执行此操作的最
背景:我和我的同事正在维护我们继承的百万行遗留应用程序。它的前端是用 VB6 编写的,由于我们将几乎所有资源都投入到将其转换为 C#,因此我们正在寻找针对我们的特定问题的快速而粗略的解决方案。 应用程
我正在尝试通过 PInvoke 使用 SetParent API 将 childForm 设置为主 Excel 窗口的子窗口: Form childForm = new MyForm(); IntPt
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Embedding HWND into external process using SetParent 我
我试图在 Unity 中以设定的时间间隔生成一颗星星。但我想让这些明星成为 parent ,不要让我的检查员感到困惑。 但是当我尝试这样做时,它给出了“NullReferenceExeption:对象
我有一个表单和一个面板,这是我处理 setparent 的代码,效果很好。 hWnd = FindWindow("MapleStoryClass", null); Panel_Handle(); Se
一旦应用程序现在将其用作父表单,您将如何从表单中取消 Hook ? [DllImport("user32.dll")] public static extern int SetParent(IntPt
我的组件出现错误,TypeError: control.setParent is not a function .使用 FormBuilder,我构建了一个 FormArray 并在构造函数中启动了表
我有一个通用的 Element 类,其中包含同一类的元素。基于此,我将创建具体的类,例如 Boxes extends Element 我不明白的一点是 setParent(this); 为什么我需要转
我使用 PyQt5 开发的 GUI 遇到问题。 应用尝试从不同的线程更新窗口进度条的值(QThreadPool())。当它尝试更新进度条时,Python 会发出如下警告: QObject::setPa
问候语 我有一个后续类(class)。 class MyClass : public QObject { Q_OBJECT public: Q_INVOKABLE QVariant s
我需要为桌面上的一些应用程序窗口创建一个水印窗口(markHwnd),水印窗口样式为: uint dwStyle = Win32API.WS_CLIPSIBLINGS |
user32.dll 的文档 SetParent函数指出 When you change the parent of a window, you should synchronize the UIST
我创建了两个应用程序MainApps和SubApps,SubApps有一个模式类型对话框,例如登录/注销表单等,并且工作正常。 将其附加到 MainApps 后,模态对话框显示为正常的框形式。它的行为
我写了一个 QT - webkit 应用程序。当我的 pSeudo 驱动程序获取字符“l”时,此应用程序会触发回调。但是,应用程序在 firecallback 期间崩溃 - 它说 - QObject:
这不是建议问题的拷贝。来 self 的问题:“我不是在问如何编写代码。代码有效。” + “如果这个 SHELLDLL_DefView 基本上是桌面窗口,因此我应该接受应该避免小工具功能,或者如果这有点
我尝试编写一个 qt 小部件,以便在尝试打开文件时弹出一个对话框。我目前到目前为止: class FileDialog : public QWidget { Q_OBJECT protecte
我想创建一个函数来构建一个可以动态添加到窗口菜单栏的上下文菜单。考虑以下用于添加简单 QMenu 的最小示例: from PyQt5 import QtWidgets class MainWindow
SetParent 函数接受子窗口句柄和新的父窗口句柄。当子窗口处于不同的 Windows 进程中时,这似乎也有效。 我看过a post声称这不受官方支持,但是 current docs别再提这个了。
我正在尝试使用 SetParent 函数将我的进程中的一个窗口嵌入到外部进程的窗口中,遇到了一些问题,我希望有人能帮助我解决这些问题。首先,这是我目前正在做的将我的窗口嵌入到应用程序中的概述: HWN
我是一名优秀的程序员,十分优秀!