显示 QDialog 时出现 QT Thread 问题

Posted

技术标签:

【中文标题】显示 QDialog 时出现 QT Thread 问题【英文标题】:QT Thread issue when display QDialog box 【发布时间】:2015-04-16 01:51:06 【问题描述】:

我在 Qt/C++ 中开发了一个应用程序,它类似于文件浏览器。目前,在删除某些文件或复制某些文件时,我有一个线程来管理整个应用程序并进行复制,而另一个线程刚刚创建以显示带有取消按钮的进度条。这是非常基本的,但是当我浏览 android 设备文件系统时,任何删除副本的访问都会冻结 UI,并且访问是由应用程序线程完成的。这不是问题,因为我不希望用户在复制或删除时玩 UI。

我的问题主要是线程的实时问题。当我使用 Qt creator 作为 IDE 和调试时,删除工作没有任何问题,并且进度条也显示没有任何问题。当我只是在 Qt Creator 中使用该应用程序时,该应用程序在尝试显示对话框时经常崩溃。

我很确定它与线程有关。当使用调试器和 Qt 创建器时,整个应用程序会减慢跟踪、调试...

这是我的 TreeView.cpp 要求删除时的代码,例如:

DialogProgressIndicator *DeleteProgress = new DialogProgressIndicator;
        DeleteProgress->moveToThread(&ProgressThread);
        connect(&ProgressThread, &QThread::finished, DeleteProgress, &QObject::deleteLater);
        connect(this, &PulsTreeWidget::DisplayProgress, DeleteProgress, &DialogProgressIndicator::ShowDlg);
        connect(this, &PulsTreeWidget::UpdateProgress, DeleteProgress, &DialogProgressIndicator::UpdateIndicator);
        connect(this, &PulsTreeWidget::CloseProgress, DeleteProgress, &DialogProgressIndicator::CloseDlg);
        connect(DeleteProgress,&DialogProgressIndicator::CancelAction, this, &PulsTreeWidget::CatchActionCancel);
        ProgressThread.start();
        DisplayProgress();

删除完成后,我将按照以下方法关闭所有内容:

CloseProgress();
            ProgressThread.quit();
            disconnect(&ProgressThread, &QThread::finished, FileTransferProgress, &QObject::deleteLater);
            disconnect(this, &PulsTreeWidget::DisplayProgress, FileTransferProgress, &DialogProgressIndicator::ShowDlg);
            disconnect(this, &PulsTreeWidget::UpdateProgress, FileTransferProgress, &DialogProgressIndicator::UpdateIndicator);
            disconnect(this, &PulsTreeWidget::CloseProgress, FileTransferProgress, &DialogProgressIndicator::CloseDlg);
            disconnect(FileTransferProgress,&DialogProgressIndicator::CancelAction, this, &PulsTreeWidget::CatchActionCancel);

PulsTreeWidget 类定义如下:

class PulsTreeWidget : public QTreeWidget

    Q_OBJECT
    QThread ProgressThread;

public:
    PulsTreeWidget(PulsDeviceMngr& device, PulsMainUI& parent);
    ~PulsTreeWidget();

signals:
    void DisplayProgress();
    void CloseProgress();
    void UpdateProgress(int);

进度条由类管理

DialogProgressIndicator.cpp

#include <QApplication>

#include "dialogprogressindicator.h"
#include "ui_dialogprogressindicator.h"

DialogProgressIndicator::DialogProgressIndicator(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DialogProgressIndicator)

    ui->setupUi(this);
    ui->progressBar->setRange(0,100);
    ui->progressBar->setValue(1);

    connect(ui->Cancel, SIGNAL(clicked()), this, SLOT(onClickCancel()));


void DialogProgressIndicator::ShowDlg() 
    ui->progressBar->show();


void DialogProgressIndicator::CloseDlg() 
    ui->progressBar->close();


DialogProgressIndicator::~DialogProgressIndicator()

    delete ui;


void DialogProgressIndicator::UpdateIndicator(int value) 
    ui->progressBar->setValue(value);
    QApplication::processEvents();


void DialogProgressIndicator::onClickCancel() 
    emit CancelAction();
    disconnect(ui->Cancel, SIGNAL(clicked()), this, SLOT(onClickCancel()));

我已遵循 Qt 指南,但在执行“DisplayProgress”时它仍然崩溃

有什么想法吗?在另一个线程中我正在做的时候真的崩溃了

void DialogProgressIndicator::ShowDlg() 
    ui->progressBar->show();

我正在添加崩溃日志:

Application Specific Information:
abort() called

Thread 0:: Dispatch queue: com.apple.main-thread
0   com.apple.AppKit                0x00007fff89e6561f -[NSView(NSInternal) _allocAuxiliary:] + 833
1   com.apple.AppKit                0x00007fff89e67a59 -[NSView _commonAwake] + 36
2   com.apple.AppKit                0x00007fff89e6c841 -[NSView initWithFrame:] + 457
3   libqcocoa.dylib                 0x0000000103c2078f 0x103c0c000 + 83855
4   libqcocoa.dylib                 0x0000000103c20a1d 0x103c0c000 + 84509
5   libqcocoa.dylib                 0x0000000103c18f36 0x103c0c000 + 53046
6   libqcocoa.dylib                 0x0000000103c14b72 0x103c0c000 + 35698
7   QtGui                           0x0000000100f77603 QWindow::create() + 51
8   QtWidgets                       0x0000000101509e13 QWidgetPrivate::create_sys(unsigned long long, bool, bool) + 1107
9   QtWidgets                       0x00000001014df86c QWidget::create(unsigned long long, bool, bool) + 444
10  QtWidgets                       0x00000001014eeebd QWidget::setVisible(bool) + 237
11  QtWidgets                       0x000000010169679d QDialog::setVisible(bool) + 205
12  com.yourcompany.puls_connect    0x0000000100022305 DialogProgressIndicator::ShowDlg() + 21
13  com.yourcompany.puls_connect    0x000000010001a51e void QtPrivate::FunctionPointer<void (DialogProgressIndicator::*)()>::call<void, void>(void (DialogProgressIndicator::*)(), DialogProgressIndicator*, void**) + 142
14  com.yourcompany.puls_connect    0x000000010001a3fa QtPrivate::QSlotObject<void (DialogProgressIndicator::*)(), void, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) + 202
15  QtCore                          0x0000000100bfdda2 QMetaObject::activate(QObject*, int, int, void**) + 1874
16  com.yourcompany.puls_connect    0x00000001000242db PulsTreeWidget::DisplayProgress() + 43

【问题讨论】:

【参考方案1】:

请记住,您只能在主线程中使用 GUI 类。用于并行任务 QFutureWatcher:

WaitDialog waitDlg(this);
connect(this, SIGNAL(progress(int)), &waitDlg, SLOT(setProgress(int)));
QFutureWatcher<void> watcher;
connect(&watcher, SIGNAL(finished()), &waitDlg, SLOT(close()));
connect(&watcher, SIGNAL(canceled()), &waitDlg, SLOT(close()));
QFuture<void> future = QtConcurrent::run([] () /*do parallel task here*/);
watcher.setFuture(future);
waitDlg.exec();

【讨论】:

我不确定我必须在 run() 中运行什么?是 Showdlg 吗? 没有。 run() 你可以做任何非 gui 任务。例如,删除文件。 当你尝试在非主线程中使用 gui 时,你会得到 undefined bihavour 我明白,但在我的情况下,它在执行 DisplayProgress 时崩溃,这是一个向对话框(在线程中)发出的信号并运行 show()。我还没有管理和更改或删除。只需设置线程,设置对话框并显示对话框。当应用程序在 Qt creator env 中运行时不会发生这种情况,但只有当您通过双击应用程序运行应用程序时才会发生这种情况。 但是你有DeleteProgress-&gt;moveToThread(&amp;ProgressThread); 行代码。 qt 会在应用程序输出窗口中写入一些东西吗?

以上是关于显示 QDialog 时出现 QT Thread 问题的主要内容,如果未能解决你的问题,请参考以下文章

尝试显示窗口时出现 Qt 错误分段错误

qt5:如何从 qthread 中的静态函数创建和显示自定义 qdialog

QT 设置QDialog显示与隐藏系统按钮(最大小化等)

QT 设置QDialog显示与隐藏系统按钮(最大小化等)

QT 设置QDialog显示与隐藏系统按钮(最大小化等)

运行 Qt Creator 时出现并排错误