Qt 窗口与对话框 #

窗口类型概览 #

Qt 提供了多种窗口类型,用于构建不同的用户界面:

text
┌─────────────────────────────────────────────────────────────┐
│                    Qt 窗口类型                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  QWidget                                                    │
│  ├── 所有窗口和控件的基类                                    │
│  ├── 可以作为独立窗口使用                                    │
│  └── 可以作为其他控件的容器                                  │
│                                                             │
│  QMainWindow                                                │
│  ├── 主窗口类                                               │
│  ├── 包含菜单栏、工具栏、状态栏                              │
│  └── 适合作为应用程序主窗口                                  │
│                                                             │
│  QDialog                                                    │
│  ├── 对话框基类                                             │
│  ├── 模态或非模态显示                                       │
│  └── 用于临时交互                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

QMainWindow 主窗口 #

基本结构 #

text
┌─────────────────────────────────────────────────────────────┐
│  菜单栏 (QMenuBar)                                          │
├─────────────────────────────────────────────────────────────┤
│  工具栏 (QToolBar)                                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                                                             │
│                    中央控件 (Central Widget)                 │
│                                                             │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│  状态栏 (QStatusBar)                                        │
└─────────────────────────────────────────────────────────────┘
│  停靠窗口 (QDockWidget)                                     │
└─────────────────────────────────────────────────────────────┘

创建主窗口 #

cpp
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMenuBar>
#include <QToolBar>
#include <QStatusBar>
#include <QTextEdit>

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void onNewFile();
    void onOpenFile();
    void onSaveFile();
    void onAbout();

private:
    void createMenuBar();
    void createToolBar();
    void createStatusBar();
    void createDockWidgets();

    QTextEdit *textEdit;
};

#endif // MAINWINDOW_H
cpp
// mainwindow.cpp
#include "mainwindow.h"
#include <QMenu>
#include <QAction>
#include <QFileDialog>
#include <QMessageBox>
#include <QDockWidget>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle("My Application");
    resize(800, 600);

    // 创建中央控件
    textEdit = new QTextEdit(this);
    setCentralWidget(textEdit);

    createMenuBar();
    createToolBar();
    createStatusBar();
    createDockWidgets();
}

MainWindow::~MainWindow()
{
}

void MainWindow::createMenuBar()
{
    // 文件菜单
    QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
    
    QAction *newAction = fileMenu->addAction(tr("&New"));
    newAction->setShortcut(QKeySequence::New);
    connect(newAction, &QAction::triggered, this, &MainWindow::onNewFile);

    QAction *openAction = fileMenu->addAction(tr("&Open"));
    openAction->setShortcut(QKeySequence::Open);
    connect(openAction, &QAction::triggered, this, &MainWindow::onOpenFile);

    QAction *saveAction = fileMenu->addAction(tr("&Save"));
    saveAction->setShortcut(QKeySequence::Save);
    connect(saveAction, &QAction::triggered, this, &MainWindow::onSaveFile);

    fileMenu->addSeparator();

    QAction *exitAction = fileMenu->addAction(tr("E&xit"));
    exitAction->setShortcut(QKeySequence::Quit);
    connect(exitAction, &QAction::triggered, this, &QWidget::close);

    // 帮助菜单
    QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
    QAction *aboutAction = helpMenu->addAction(tr("&About"));
    connect(aboutAction, &QAction::triggered, this, &MainWindow::onAbout);
}

void MainWindow::createToolBar()
{
    QToolBar *toolbar = addToolBar(tr("Main Toolbar"));
    
    toolbar->addAction(QIcon(":/icons/new.png"), tr("New"));
    toolbar->addAction(QIcon(":/icons/open.png"), tr("Open"));
    toolbar->addAction(QIcon(":/icons/save.png"), tr("Save"));
    toolbar->addSeparator();
    toolbar->addAction(QIcon(":/icons/cut.png"), tr("Cut"));
    toolbar->addAction(QIcon(":/icons/copy.png"), tr("Copy"));
    toolbar->addAction(QIcon(":/icons/paste.png"), tr("Paste"));
}

void MainWindow::createStatusBar()
{
    statusBar()->showMessage(tr("Ready"));
}

void MainWindow::createDockWidgets()
{
    QDockWidget *dock = new QDockWidget(tr("Explorer"), this);
    dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    
    QWidget *dockContent = new QWidget;
    dock->setWidget(dockContent);
    
    addDockWidget(Qt::LeftDockWidgetArea, dock);
}

void MainWindow::onNewFile()
{
    textEdit->clear();
    statusBar()->showMessage(tr("New file created"));
}

void MainWindow::onOpenFile()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"));
    if (!fileName.isEmpty()) {
        // 打开文件
        statusBar()->showMessage(tr("File opened: %1").arg(fileName));
    }
}

void MainWindow::onSaveFile()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"));
    if (!fileName.isEmpty()) {
        // 保存文件
        statusBar()->showMessage(tr("File saved: %1").arg(fileName));
    }
}

void MainWindow::onAbout()
{
    QMessageBox::about(this, tr("About"), tr("My Application v1.0"));
}

QDialog 对话框 #

模态与非模态 #

cpp
// 模态对话框 - 阻塞父窗口
QDialog dialog(this);
dialog.setWindowTitle("Modal Dialog");
dialog.exec();  // 阻塞直到对话框关闭

// 非模态对话框 - 不阻塞父窗口
QDialog *dialog = new QDialog(this);
dialog->setWindowTitle("Modeless Dialog");
dialog->setAttribute(Qt::WA_DeleteOnClose);  // 关闭时自动删除
dialog->show();  // 非阻塞显示

标准对话框 #

cpp
// 消息框
QMessageBox::information(this, "Title", "Information message");
QMessageBox::warning(this, "Title", "Warning message");
QMessageBox::critical(this, "Title", "Critical message");
QMessageBox::question(this, "Title", "Question?");

// 带按钮的消息框
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "Confirm", "Are you sure?",
                              QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
    // 用户点击了 Yes
}

// 文件对话框
QString fileName = QFileDialog::getOpenFileName(this, "Open File",
    "/home", "Images (*.png *.jpg);;All Files (*)");

QString fileName = QFileDialog::getSaveFileName(this, "Save File",
    "/home", "Documents (*.txt)");

QStringList fileNames = QFileDialog::getOpenFileNames(this, "Open Files",
    "/home", "Images (*.png *.jpg)");

// 颜色对话框
QColor color = QColorDialog::getColor(Qt::red, this, "Select Color");

// 字体对话框
bool ok;
QFont font = QFontDialog::getFont(&ok, QFont("Arial", 12), this);
if (ok) {
    // 用户选择了字体
}

// 输入对话框
QString text = QInputDialog::getText(this, "Input", "Enter name:");
int value = QInputDialog::getInt(this, "Input", "Enter age:", 0, 0, 150);
double dvalue = QInputDialog::getDouble(this, "Input", "Enter value:");
QString item = QInputDialog::getItem(this, "Select", "Choose:",
                                     QStringList() << "A" << "B" << "C", 0, false);

自定义对话框 #

cpp
// customdialog.h
#ifndef CUSTOMDIALOG_H
#define CUSTOMDIALOG_H

#include <QDialog>
#include <QLineEdit>
#include <QSpinBox>
#include <QDialogButtonBox>

class CustomDialog : public QDialog
{
    Q_OBJECT

public:
    explicit CustomDialog(QWidget *parent = nullptr);

    QString getName() const;
    int getAge() const;

private:
    QLineEdit *nameEdit;
    QSpinBox *ageSpinBox;
    QDialogButtonBox *buttonBox;
};

#endif // CUSTOMDIALOG_H
cpp
// customdialog.cpp
#include "customdialog.h"
#include <QVBoxLayout>
#include <QFormLayout>

CustomDialog::CustomDialog(QWidget *parent)
    : QDialog(parent)
{
    setWindowTitle("Custom Dialog");

    nameEdit = new QLineEdit;
    ageSpinBox = new QSpinBox;
    ageSpinBox->setRange(0, 150);

    buttonBox = new QDialogButtonBox(
        QDialogButtonBox::Ok | QDialogButtonBox::Cancel);

    connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
    connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);

    QFormLayout *formLayout = new QFormLayout;
    formLayout->addRow(tr("Name:"), nameEdit);
    formLayout->addRow(tr("Age:"), ageSpinBox);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addLayout(formLayout);
    mainLayout->addWidget(buttonBox);
}

QString CustomDialog::getName() const
{
    return nameEdit->text();
}

int CustomDialog::getAge() const
{
    return ageSpinBox->value();
}
cpp
// 使用自定义对话框
CustomDialog dialog(this);
if (dialog.exec() == QDialog::Accepted) {
    QString name = dialog.getName();
    int age = dialog.getAge();
    qDebug() << name << age;
}

QWidget 基础窗口 #

作为独立窗口 #

cpp
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget window;
    window.setWindowTitle("QWidget Window");
    window.resize(300, 200);

    QVBoxLayout *layout = new QVBoxLayout(&window);

    QLabel *label = new QLabel("Hello QWidget!");
    layout->addWidget(label);

    QPushButton *button = new QPushButton("Click Me");
    layout->addWidget(button);

    window.show();

    return app.exec();
}

窗口属性 #

cpp
QWidget *widget = new QWidget;

// 窗口标题
widget->setWindowTitle("My Window");

// 窗口大小
widget->resize(400, 300);
widget->setMinimumSize(200, 150);
widget->setMaximumSize(800, 600);
widget->setFixedSize(400, 300);  // 固定大小

// 窗口位置
widget->move(100, 100);
widget->setGeometry(100, 100, 400, 300);  // x, y, width, height

// 窗口状态
widget->show();
widget->hide();
widget->showMaximized();
widget->showMinimized();
widget->showFullScreen();
widget->showNormal();

// 窗口标志
widget->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);

// 窗口模态
widget->setWindowModality(Qt::ApplicationModal);  // 应用级模态
widget->setWindowModality(Qt::WindowModal);       // 窗口级模态
widget->setWindowModality(Qt::NonModal);          // 非模态

// 窗口透明度
widget->setWindowOpacity(0.8);  // 80% 不透明度

// 窗口图标
widget->setWindowIcon(QIcon(":/icons/app.png"));

窗口标志 #

cpp
// 常用窗口标志
Qt::Window              // 普通窗口
Qt::Dialog              // 对话框
Qt::Tool                // 工具窗口
Qt::SplashScreen        // 启动画面
Qt::FramelessWindowHint // 无边框窗口
Qt::WindowStaysOnTopHint // 始终置顶
Qt::WindowMinMaxButtonsHint // 最小化最大化按钮
Qt::WindowCloseButtonHint   // 关闭按钮

// 组合使用
widget->setWindowFlags(
    Qt::Window |
    Qt::WindowTitleHint |
    Qt::WindowCloseButtonHint |
    Qt::WindowStaysOnTopHint
);

窗口关闭事件 #

cpp
// 重写 closeEvent
void MainWindow::closeEvent(QCloseEvent *event)
{
    QMessageBox::StandardButton reply;
    reply = QMessageBox::question(this, "Confirm",
        "Are you sure you want to quit?",
        QMessageBox::Yes | QMessageBox::No);

    if (reply == QMessageBox::Yes) {
        // 保存设置等清理工作
        event->accept();
    } else {
        event->ignore();
    }
}

多窗口管理 #

cpp
// 主窗口管理多个子窗口
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    void openChildWindow()
    {
        ChildWindow *child = new ChildWindow(this);
        child->setAttribute(Qt::WA_DeleteOnClose);
        child->show();
        
        m_childWindows.append(child);
    }

private:
    QList<QWidget*> m_childWindows;
};

下一步 #

现在你已经掌握了窗口和对话框的使用,接下来学习 基础控件,了解 Qt 提供的各种常用控件!

最后更新:2026-03-29