在Qt中,如果没有父窗口创建一个新的Qt窗口,是否也会创建一个新线程?

4

我的问题有两个部分:

  1. mainWindow 是在运行 main() 的线程之外开辟的吗?
  2. mainWindowmain() 返回后不会立即超出范围,这是为什么?

在下面的示例中,创建了一个窗口,显示了该窗口,并且 main 函数几乎立即返回。

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

MainWindowExample.pro

#-------------------------------------------------
#
# Project created by QtCreator 2016-05-23T10:55:03
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = MainWindowExample
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

这不是记录在案的合同的一部分。如果您需要了解实现细节,您必须添加您正在使用的特定Qt版本和指定平台。 - IInspectable
3
  1. 通常只有一个GUI线程。
  2. 它确实会,但是a.exec()方法只有在主窗口关闭后才会返回。
- Karsten Koop
@KarstenKoop 1. 这并没有完全回答问题,但是2. 是很好知道的。让我举个例子:如果MainWindow线程创建了一个新窗口,但没有给该窗口父级(parent=0),那么它会生成一个新线程还是两者都在同一线程上运行? - Daniel Arnett
这取决于你的实现方式。同样,这并没有被记录下来。如果你需要了解你所使用的Qt版本和指定的目标平台,只需逐步执行代码即可。你不会得到比“通常你只有一个单独的GUI线程”更简洁的答案。 - IInspectable
2个回答

6
  1. 没有为mainWindow创建新的线程。
  2. mainWindow事件循环在a.exec()的范围内执行-它会阻塞,直到应用程序退出(例如-最后一个顶层窗口关闭)。

因此,mainWindow不会超出作用域,因为是main执行所有操作。

可以使用以下代码进行检查:

std::cout << "starting application event loop" << std::endl;
const int ret = a.exec();
std::cout << "after exec" << std::endl; // or any other code here
return ret;

来自QApplication文档:

进入主事件循环并等待直到调用exit(),然后返回设置给exit()的值(如果通过quit()调用exit()则返回0)。


在这个编程示例中,创建了一个窗口并显示出来,主函数几乎立即返回。你的回答完全没有涉及到这一点。此外,除了给人留下未记录的实现细节是合同约定的印象外,这并不是事实。 - IInspectable
2
OP可能误解了main函数会立即返回的情况,因为这将破坏MainWindow并关闭整个应用程序或导致崩溃。QApplication :: exec是一个阻塞方法,已经有很好的文档说明了... - Hcorg
@Hcorg是正确的,我关于立即返回的想法是错误的。感谢你提供反例并向我展示如何检查这个问题。 - Daniel Arnett

1

主窗口是在除运行main()的线程之外的线程中生成的吗?

不是。事实上,这样做会导致未定义的行为。您只能在主线程中构造QWidget的子类。

线程和对象文档主题涵盖了这一点:

虽然QObject是可重入的,但GUI类,特别是QWidget及其所有子类,不是可重入的。它们只能从主线程中使用。如前所述,QCoreApplication::exec()也必须从该线程中调用。

main()返回时,主窗口如何不立即超出范围?

但确实会超出范围!

main()a.exec()返回时返回,而这仅在退出应用程序时发生。默认情况下,当关闭最后一个可见窗口时,应用程序会自动退出。


不行。实际上,这样做会导致未定义的行为。你只能在主线程中构造QWidget的子类。有官方文档的参考吗? - IInspectable
@IInspectable 真的吗?当你搜索“qwidget thread site:doc.qt.io”时,第三个谷歌搜索结果就是这个。你可能不希望其余的反对意见都以你期望的方式明确记录下来,但除了使所有内容同步到其他线程无关紧要(但当然会像糖浆一样表现)之外,没有其他实现方式了。此外,由于 QWidgetQObject 的子类,它的 thread() 具有良好理解的语义。Qt 不能自己更改 thread() - Kuba hasn't forgotten Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接