qt使用笔记四之 一文畅览 Qt 控件类

Qt控件类详解与应用

【投稿赢 iPhone 17】「我的第一个开源项目」故事征集:用代码换C位出道! 10w+人浏览 1.7k人参与

一文畅览 Qt 控件类

  • 总结 Qt 基础控件类

    • QAction
    • QSlider
    • QTabWidget
    • Layout
  • 长期更新中

1. QAction

  • 是 Qt 框架中用于表示用户界面动作的核心类,它允许你将操作(如菜单项、工具栏按钮、快捷键)抽象为独立对象。
  • 核心功能
    • 统一管理:一个动作可同时添加到菜单、工具栏、上下文菜单
    • 状态同步:所有关联组件自动同步状态(启用/禁用、选中状态)
    • 事件处理:通过信号-槽机制响应操作
    • 属性丰富:支持文本、图标、快捷键、工具提示等

1. 基本使用:

// 简单创建
QAction *newAction = new QAction("&New", this);  // & 定义快捷键(Alt+N)

// 带图标创建
QAction *openAction = new QAction(QIcon(":/icons/open.png"), "&Open", this);

// 设置属性
saveAction = new QAction("Save", this);
saveAction->setShortcut(QKeySequence::Save);      // 快捷键(Ctrl+S)
saveAction->setStatusTip("Save current document");// 状态栏提示
saveAction->setToolTip("Save document");          // 悬浮提示
  • 添加到页面组件
// 添加到菜单
QMenu *fileMenu = menuBar()->addMenu("&File");
fileMenu->addAction(newAction);
fileMenu->addAction(openAction);

// 添加到工具栏
QToolBar *fileToolBar = addToolBar("File");
fileToolBar->addAction(saveAction);

// 添加到按钮
QPushButton *btn = new QPushButton("Save");
btn->addAction(saveAction);  // 支持右键菜单/快捷键

2. 关键特性

  • 状态控制
// 启用/禁用
saveAction->setEnabled(false); 

// 可选中动作(切换状态)
QAction *boldAction = new QAction("Bold", this);
boldAction->setCheckable(true);     // 设置为可选中
boldAction->setChecked(false);      // 初始状态
  • 信号处理
// 连接点击信号
connect(newAction, &QAction::triggered, this, &MainWindow::createNewFile);

// 可选中动作的状态变化
connect(boldAction, &QAction::toggled, this, &MainWindow::setTextBold);
  • 动作分组
// 创建互斥动作组(如对齐方式)
QActionGroup *alignGroup = new QActionGroup(this);
alignGroup->setExclusive(true);  // 互斥选择

QAction *leftAlign = new QAction("Left", alignGroup);
leftAlign->setCheckable(true);
QAction *centerAlign = new QAction("Center", alignGroup);
centerAlign->setCheckable(true);

// 添加分组到菜单
formatMenu->addActions(alignGroup->actions());

3. 高级用法

  • 自定义数据
// 存储关联数据
QAction *colorAction = new QAction("Red", this);
colorAction->setData(QColor(Qt::red)); 

// 使用时获取数据
void MainWindow::changeColor() {
    QAction *act = qobject_cast<QAction*>(sender());
    QColor color = act->data().value<QColor>();
}
  • 动态更新菜单
// 更新动作属性
void updateActions() {
    bool hasSelection = textEdit->textCursor().hasSelection();
    copyAction->setEnabled(hasSelection);
    cutAction->setEnabled(hasSelection);
}

// 连接文本选择变化信号
connect(textEdit, &QTextEdit::selectionChanged, this, &updateActions);
  • 分离动作
// 创建无父对象的动作(需手动管理内存)
QAction *globalAction = new QAction("Global Action");
connect(globalAction, &QAction::triggered, [](){
    qDebug() << "Global action triggered";
});

// 添加到系统托盘等
trayIcon->contextMenu()->addAction(globalAction);

2. QSlider

  • QSlider 是 Qt 框架中用于提供数值范围选择的滑动条控件,支持水平和垂直两种方向。下面我将全面介绍其成员函数和使用方法。

1.核心功能概述

数值选择:在设定范围内选择整数值

方向支持:水平 (Qt::Horizontal) 或垂直 (Qt::Vertical)

视觉反馈:显示刻度、当前值和范围

交互方式:鼠标拖动、键盘控制、点击槽道

状态控制:启用/禁用、反转方向、自定义样式

2.构造函数与基本设置

    1. 创建滑块
// 创建水平滑块
QSlider *horizontalSlider = new QSlider(Qt::Horizontal, parentWidget);

// 创建垂直滑块
QSlider *verticalSlider = new QSlider(Qt::Vertical, parentWidget);
  • -2. 范围与初始值设置
// 设置数值范围 (默认0-99)
slider->setRange(0, 100);

// 设置最小值
slider->setMinimum(0);

// 设置最大值
slider->setMaximum(100);

// 设置当前值
slider->setValue(50);

// 获取当前值
int value = slider->value();

3. 关键成员函数详解

    1. 步长控制
// 设置单步增量 (键盘方向键改变量)
slider->setSingleStep(5);

// 设置页步增量 (点击槽道改变量)
slider->setPageStep(20);

// 设置刻度间隔
slider->setTickInterval(10);
    1. 刻度显示
// 设置刻度位置
slider->setTickPosition(QSlider::NoTicks);          // 无刻度
slider->setTickPosition(QSlider::TicksAbove);       // 上方/左侧刻度
slider->setTickPosition(QSlider::TicksBelow);       // 下方/右侧刻度
slider->setTickPosition(QSlider::TicksBothSides);   // 两侧刻度
    1. 方向控制
// 设置方向
slider->setOrientation(Qt::Horizontal);  // 水平方向
slider->setOrientation(Qt::Vertical);    // 垂直方向

// 反转显示 (最大值在左/下)
slider->setInvertedAppearance(true);

// 反转键盘控制方向
slider->setInvertedControls(true);
    1. 状态控制
// 启用/禁用滑块
slider->setEnabled(false);

// 设置滑块是否可拖动
slider->setSliderDown(true);  // 手动设置拖动状态

// 检查滑块是否被按下
bool isPressed = slider->isSliderDown();

// 设置滑块位置 (不改变实际值)
slider->setSliderPosition(75);
    1. 跟踪模式
// 启用跟踪 (值改变时实时触发信号,默认开启)
slider->setTracking(true);

// 禁用跟踪 (只在用户释放滑块时触发信号)
slider->setTracking(false);

4.信号系统

在这里插入图片描述

  • 信号使用示例
// 连接值改变信号
connect(slider, &QSlider::valueChanged, [](int value) {
    qDebug() << "当前值:" << value;
});

// 连接拖动信号
connect(slider, &QSlider::sliderPressed, []() {
    qDebug() << "开始拖动滑块";
});

// 连接释放信号
connect(slider, &QSlider::sliderReleased, []() {
    qDebug() << "滑块已释放";
});

3. QTabWidget

1. QTabWidget 概述

  • QTabWidget 是 Qt 中用于创建选项卡式界面的容器控件,它允许用户通过点击标签在不同的页面之间切换。每个选项卡包含一个页面(通常是一个 QWidget),用户可以轻松地在不同功能模块间导航。

2. 核心 API 详解

  • 2.1 构造函数和基本设置
#include <QTabWidget>
#include <QWidget>
#include <QLabel>

// 创建 QTabWidget
QTabWidget *tabWidget = new QTabWidget(parent);

// 基本设置方法
tabWidget->setTabPosition(QTabWidget::North);  // 设置标签位置
tabWidget->setMovable(true);                   // 允许用户拖动重新排序标签
tabWidget->setTabsClosable(true);              // 在标签上显示关闭按钮
tabWidget->setDocumentMode(true);              // 文档模式(更简洁的外观)
tabWidget->setTabShape(QTabWidget::Rounded);   // 标签形状
  • 2.2 添加和移除选项卡
// 添加选项卡的多种方式
int index = tabWidget->addTab(widget, "Tab Name");
int index = tabWidget->addTab(widget, QIcon("icon.png"), "Tab Name");

// 在指定位置插入选项卡
int index = tabWidget->insertTab(position, widget, "Tab Name");
int index = tabWidget->insertTab(position, widget, QIcon("icon.png"), "Tab Name");

// 移除选项卡
tabWidget->removeTab(index);           // 移除但不删除widget
QWidget* widget = tabWidget->widget(index);  // 获取对应widget
delete widget;                         // 手动删除widget
  • 2.3 标签相关操作
// 设置标签文本和图标
tabWidget->setTabText(index, "New Text");
tabWidget->setTabIcon(index, QIcon("new_icon.png"));
tabWidget->setTabToolTip(index, "Tooltip text");
tabWidget->setTabWhatsThis(index, "What's this text");

// 获取标签信息
QString text = tabWidget->tabText(index);
QIcon icon = tabWidget->tabIcon(index);
QString toolTip = tabWidget->tabToolTip(index);

// 启用/禁用标签
tabWidget->setTabEnabled(index, false);  // 禁用特定标签
  • 2.4 当前选项卡控制
// 设置和获取当前选项卡
tabWidget->setCurrentIndex(index);
tabWidget->setCurrentWidget(widget);

int currentIndex = tabWidget->currentIndex();
QWidget* currentWidget = tabWidget->currentWidget();

// 获取选项卡数量
int count = tabWidget->count();

3. 完整示例程序

#include <QApplication>
#include <QTabWidget>
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include <QListWidget>
#include <QLineEdit>
#include <QMessageBox>
#include <QIcon>

class Tab1 : public QWidget {
public:
    Tab1(QWidget *parent = nullptr) : QWidget(parent) {
        QVBoxLayout *layout = new QVBoxLayout(this);
        
        QLabel *label = new QLabel("这是第一个选项卡");
        QTextEdit *textEdit = new QTextEdit();
        textEdit->setPlaceholderText("在这里输入文本...");
        
        layout->addWidget(label);
        layout->addWidget(textEdit);
    }
};

class Tab2 : public QWidget {
public:
    Tab2(QTabWidget *tabWidget, QWidget *parent = nullptr) 
        : QWidget(parent), tabWidget(tabWidget) {
        QVBoxLayout *layout = new QVBoxLayout(this);
        
        QLabel *label = new QLabel("列表选项卡");
        listWidget = new QListWidget();
        
        // 添加一些示例项
        listWidget->addItems({"项目1", "项目2", "项目3", "项目4"});
        
        QPushButton *addButton = new QPushButton("添加新项目");
        connect(addButton, &QPushButton::clicked, this, &Tab2::addNewItem);
        
        layout->addWidget(label);
        layout->addWidget(listWidget);
        layout->addWidget(addButton);
    }

private slots:
    void addNewItem() {
        bool ok;
        QString text = QInputDialog::getText(this, "添加项目", 
                                           "输入新项目名称:", 
                                           QLineEdit::Normal, 
                                           "", &ok);
        if (ok && !text.isEmpty()) {
            listWidget->addItem(text);
        }
    }

private:
    QTabWidget *tabWidget;
    QListWidget *listWidget;
};

class Tab3 : public QWidget {
public:
    Tab3(QWidget *parent = nullptr) : QWidget(parent) {
        QVBoxLayout *layout = new QVBoxLayout(this);
        
        QLabel *label = new QLabel("设置选项卡");
        
        QLineEdit *nameEdit = new QLineEdit();
        nameEdit->setPlaceholderText("输入姓名");
        
        QLineEdit *emailEdit = new QLineEdit();
        emailEdit->setPlaceholderText("输入邮箱");
        
        QPushButton *saveButton = new QPushButton("保存设置");
        connect(saveButton, &QPushButton::clicked, this, &Tab3::saveSettings);
        
        layout->addWidget(label);
        layout->addWidget(new QLabel("姓名:"));
        layout->addWidget(nameEdit);
        layout->addWidget(new QLabel("邮箱:"));
        layout->addWidget(emailEdit);
        layout->addWidget(saveButton);
        layout->addStretch(); // 添加弹性空间
    }

private slots:
    void saveSettings() {
        QMessageBox::information(this, "保存", "设置已保存!");
    }
};

class MainWindow : public QWidget {
public:
    MainWindow(QWidget *parent = nullptr) : QWidget(parent) {
        // 创建主布局
        QVBoxLayout *mainLayout = new QVBoxLayout(this);
        
        // 创建 QTabWidget
        tabWidget = new QTabWidget();
        
        // 配置 QTabWidget
        tabWidget->setTabPosition(QTabWidget::North);
        tabWidget->setMovable(true);
        tabWidget->setTabsClosable(true);
        tabWidget->setDocumentMode(false);
        
        // 创建各个选项卡
        Tab1 *tab1 = new Tab1();
        Tab2 *tab2 = new Tab2(tabWidget);
        Tab3 *tab3 = new Tab3();
        
        // 添加选项卡(使用图标和文本)
        tabWidget->addTab(tab1, QIcon(":/icons/text.png"), "文本编辑");
        tabWidget->addTab(tab2, QIcon(":/icons/list.png"), "列表管理");
        tabWidget->addTab(tab3, QIcon(":/icons/settings.png"), "设置");
        
        // 创建控制按钮
        QHBoxLayout *buttonLayout = new QHBoxLayout();
        QPushButton *addTabButton = new QPushButton("添加新选项卡");
        QPushButton *removeTabButton = new QPushButton("移除当前选项卡");
        
        buttonLayout->addWidget(addTabButton);
        buttonLayout->addWidget(removeTabButton);
        buttonLayout->addStretch();
        
        // 连接信号槽
        connect(addTabButton, &QPushButton::clicked, this, &MainWindow::addNewTab);
        connect(removeTabButton, &QPushButton::clicked, this, &MainWindow::removeCurrentTab);
        connect(tabWidget, &QTabWidget::tabCloseRequested, this, &MainWindow::onTabCloseRequested);
        connect(tabWidget, &QTabWidget::currentChanged, this, &MainWindow::onCurrentTabChanged);
        
        // 组装界面
        mainLayout->addWidget(tabWidget);
        mainLayout->addLayout(buttonLayout);
        
        setWindowTitle("QTabWidget 示例");
        resize(600, 400);
    }

private slots:
    void addNewTab() {
        static int counter = 1;
        QWidget *newTab = new QWidget();
        QVBoxLayout *layout = new QVBoxLayout(newTab);
        
        QLabel *label = new QLabel(QString("动态添加的选项卡 %1").arg(counter++));
        QTextEdit *textEdit = new QTextEdit();
        textEdit->setPlaceholderText("这个选项卡是动态添加的...");
        
        layout->addWidget(label);
        layout->addWidget(textEdit);
        
        int index = tabWidget->addTab(newTab, QString("动态标签 %1").arg(counter));
        tabWidget->setCurrentIndex(index);
    }
    
    void removeCurrentTab() {
        int index = tabWidget->currentIndex();
        if (index >= 0) {
            QWidget *widget = tabWidget->widget(index);
            tabWidget->removeTab(index);
            delete widget;
        }
    }
    
    void onTabCloseRequested(int index) {
        if (index >= 0) {
            QWidget *widget = tabWidget->widget(index);
            tabWidget->removeTab(index);
            delete widget;
        }
    }
    
    void onCurrentTabChanged(int index) {
        if (index >= 0) {
            QString tabName = tabWidget->tabText(index);
            setWindowTitle(QString("QTabWidget 示例 - %1").arg(tabName));
        }
    }

private:
    QTabWidget *tabWidget;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    MainWindow window;
    window.show();
    
    return app.exec();
}

4. 高级功能和自定义

  • 4.1 自定义标签栏
#include <QTabBar>

// 获取标签栏并进行自定义
QTabBar *tabBar = tabWidget->tabBar();
tabBar->setExpanding(false);                    // 禁止标签平均扩展
tabBar->setDrawBase(false);                     // 不绘制基線
tabBar->setElideMode(Qt::ElideRight);           // 文本过长时显示省略号

// 完全自定义标签栏
class CustomTabBar : public QTabBar {
protected:
    QSize tabSizeHint(int index) const override {
        QSize size = QTabBar::tabSizeHint(index);
        size.setWidth(120);  // 固定宽度
        return size;
    }
    
    void paintEvent(QPaintEvent *event) override {
        // 自定义绘制代码
        QTabBar::paintEvent(event);
    }
};

// 使用自定义标签栏
CustomTabBar *customBar = new CustomTabBar();
tabWidget->setTabBar(customBar);
  • 4.2 样式表定制
// 基本的样式表定制
tabWidget->setStyleSheet(
    "QTabWidget::pane {"
    "    border: 1px solid #C2C7CB;"
    "    top: -1px;"
    "    background-color: #F0F0F0;"
    "}"
    "QTabWidget::tab-bar {"
    "    alignment: center;"
    "}"
    "QTabBar::tab {"
    "    background-color: #E1E1E1;"
    "    border: 1px solid #C4C4C3;"
    "    padding: 8px 20px;"
    "    margin-right: 2px;"
    "}"
    "QTabBar::tab:selected {"
    "    background-color: #FFFFFF;"
    "    border-bottom-color: #FFFFFF;"
    "}"
    "QTabBar::tab:!selected {"
    "    margin-top: 2px;"
    "}"
);
  • 4.3 信号和槽
// 连接各种信号
connect(tabWidget, &QTabWidget::currentChanged, [](int index) {
    qDebug() << "当前选项卡改变为:" << index;
});

connect(tabWidget, &QTabWidget::tabBarClicked, [](int index) {
    qDebug() << "点击了标签:" << index;
});

connect(tabWidget, &QTabWidget::tabBarDoubleClicked, [](int index) {
    qDebug() << "双击了标签:" << index;
});

connect(tabWidget, &QTabWidget::tabCloseRequested, [](int index) {
    qDebug() << "请求关闭标签:" << index;
});
  • 4.4 内存管理
// 正确的内存管理
class SafeTabWidget : public QTabWidget {
public:
    ~SafeTabWidget() {
        // 清理所有子控件
        for (int i = count() - 1; i >= 0; --i) {
            QWidget *widget = this->widget(i);
            removeTab(i);
            delete widget;
        }
    }
};

// 或者使用智能指针(C++11+)
#include <memory>
std::unique_ptr<QTabWidget> tabWidget = std::make_unique<QTabWidget>();

4. Layout

1.核心概念:为什么需要布局管理器?

  • 在传统GUI编程中,控件的位置和大小(几何属性)通常通过绝对坐标指定(setGeometry)。这种方式有巨大缺陷:

  • 无法自适应:窗口大小改变时,内部控件不会随之调整。

  • 平台差异:在不同操作系统或不同主题下,控件默认大小可能不同,导致UI错乱。

  • 开发繁琐:手动计算每个控件的位置极其麻烦,且难以维护。

  • Qt的布局管理器(Layout Managers)完美解决了这些问题。它们负责:

  • 自动定位和调整:根据用户定义的规则,自动安排子控件的位置和大小。

  • 自适应响应:当父窗口大小改变时,自动重新计算所有子控件的布局。

  • 内容适配:能根据子控件的“大小提示”(sizeHint、minimumSizeHint)进行合理分配。

2.三大基础布局

1. 水平布局(QHBoxLayout)
  • 设计理念:将子控件从左到右(默认)依次水平排列。

  • 核心API:

addWidget(QWidget *widget, int stretch = 0, Qt::Alignment alignment = 0):添加一个控件。

stretch: 拉伸因子。控制控件在多余空间中分配到的比例。0表示不拉伸。

alignment: 对齐方式(如 Qt::AlignTop, Qt::AlignVCenter)。注意:只有在控件未填满布局分配的空间时,对齐才有效。

addLayout(QLayout *layout, int stretch = 0):添加一个子布局,实现布局嵌套。

addStretch(int stretch = 0):添加一个可拉伸的空间(Spacer),用于将控件推到一边。

setSpacing(int spacing):设置控件之间的间距。
  • 多控件布局示例:假设我们需要创建一个包含三个按钮的水平栏,并且希望“确定”按钮在右侧,“取消”按钮在左侧,中间是弹簧。
QWidget *window = new QWidget;
QHBoxLayout *hLayout = new QHBoxLayout; // 1. 创建水平布局

QPushButton *btnOk = new QPushButton("OK");
QPushButton *btnCancel = new QPushButton("Cancel");
QPushButton *btnHelp = new QPushButton("Help");

hLayout->addWidget(btnCancel);    // 从左开始添加
hLayout->addStretch(1);           // 添加一个拉伸因子为1的弹簧,占据所有额外空间
hLayout->addWidget(btnHelp);
hLayout->addWidget(btnOk);

window->setLayout(hLayout); // 2. 将布局设置到父窗口上
window->show();
  • 效果:
    [ Cancel ]____________________[ Help ][ OK ]
  • 当窗口拉宽时,Cancel和Help之间的弹簧会变长,将Help和OK始终推向右端。
2. 垂直布局(QVBoxLayout)
  • 设计理念:将子控件从上到下依次垂直排列。其API与QHBoxLayout几乎完全相同。

  • 多控件布局示例: 创建一个常见的对话框右侧按钮栏。

QVBoxLayout *vLayout = new QVBoxLayout;

vLayout->addWidget(new QPushButton("OK"));
vLayout->addWidget(new QPushButton("Cancel"));
vLayout->addWidget(new QPushButton("Help"));
vLayout->addStretch(1); // 添加一个弹簧,将上面的按钮推到顶部
// 设置布局间距和对齐
vLayout->setSpacing(5); // 按钮间距5像素
// 默认情况下,按钮会拉伸填满宽度。如果我们不希望这样,可以设置对齐方式。
// 但通常需要结合大小策略或固定大小使用,或者放在另一个布局中。
  • 效果:
text
[  OK   ]
[ Cancel]
[ Help  ]
(剩余空间)
3. 栅格布局(QGridLayout)
  • 设计理念:将空间划分为行和列的网格,可以将控件放入特定的单元格中。这是最灵活、最常用的复杂布局工具。

  • 核心API:

addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = 0):将控件放入指定的row和column。

addWidget(QWidget *widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = 0):高级用法。让控件跨越多行多列。

rowSpan: 跨越的行数。

columnSpan: 跨越的列数。

setRowStretch(int row, int stretch):设置某一行的拉伸因子。

setColumnStretch(int column, int stretch):设置某一列的拉伸因子。

setRowMinimumHeight(int row, int minSize):设置某一行的最小高度。

setColumnMinimumWidth(int column, int minSize):设置某一列的最小宽度。
  • 多控件布局示例:创建一个典型的用户登录表单。
QGridLayout *gridLayout = new QGridLayout;

QLabel *labelUser = new QLabel("Username:");
QLabel *labelPass = new QLabel("Password:");
QLineEdit *lineEditUser = new QLineEdit;
QLineEdit *lineEditPass = new QLineEdit;
lineEditPass->setEchoMode(QLineEdit::Password);
QPushButton *btnLogin = new QPushButton("Login");
QPushButton *btnCancel = new QPushButton("Cancel");

// 添加控件到网格 (行, 列)
gridLayout->addWidget(labelUser, 0, 0);        // 第0行,第0列
gridLayout->addWidget(lineEditUser, 0, 1);     // 第0行,第1列
gridLayout->addWidget(labelPass, 1, 0);        // 第1行,第0列
gridLayout->addWidget(lineEditPass, 1, 1);     //第1行,第1列

// 按钮放在第2行,跨1行2列,并水平居中
gridLayout->addWidget(btnLogin, 2, 0, 1, 2, Qt::AlignHCenter); // (起始行,起始列,占1行,占2列)

// 设置列的拉伸因子,让第1列(输入框)比第0列(标签)更宽
gridLayout->setColumnStretch(1, 3); // 第1列的拉伸因子为3

// 也可以设置布局边距和间距
gridLayout->setContentsMargins(10, 10, 10, 10); // 设置布局的外边距(左,上,右,下)
gridLayout->setHorizontalSpacing(5); // 设置水平间距
gridLayout->setVerticalSpacing(10);  // 设置垂直间距

window->setLayout(gridLayout);
  • 效果:
text
Username: [__________________________]
Password: [__________________________]
          [        Login        ]
  • 当窗口变宽时,只有输入框所在的列会变宽,标签列宽度基本不变。

3. 高级技巧与实战

1. 布局嵌套(组合布局)
  • 没有任何一个布局可以单独解决所有问题。复杂的UI都是通过嵌套布局实现的。

  • 示例:创建一个经典的文本编辑器界面,有菜单、工具栏、状态栏和中央文本编辑区。

QWidget *mainWindow = new QWidget;
QVBoxLayout *mainLayout = new QVBoxLayout(mainWindow); // 主布局是垂直的

// 1. 添加菜单栏(假设是QMenuBar)
mainLayout->addWidget(menuBar);

// 2. 添加工具栏(假设是QToolBar)
mainLayout->addWidget(toolBar);

// 3. 中央部件
QTextEdit *textEdit = new QTextEdit;
mainLayout->addWidget(textEdit); // 中央文本编辑区占据大部分空间

// 4. 底部状态栏
QHBoxLayout *statusLayout = new QHBoxLayout; // 状态栏本身可能又是一个水平布局
statusLayout->addWidget(new QLabel("Ready"));
statusLayout->addStretch();
statusLayout->addWidget(new QLabel("Ln 1, Col 1"));
mainLayout->addLayout(statusLayout); // 将水平布局作为子布局加入主垂直布局

// 设置主布局的拉伸因子,确保中央文本编辑区会拉伸
mainLayout->setStretchFactor(textEdit, 1);
2. 拉伸因子(Stretch Factor)的深入理解
  • 拉伸因子决定了在父布局空间增长时,子控件或子布局如何分配额外的空间。

  • 默认值为0,意味着该控件不希望增长。

  • 如果所有控件的拉伸因子都是0,空间会根据大小策略平均分配。

  • 因子是比例值。如果一行有两个控件,拉伸因子分别为1和2,那么第一个控件获得1/3的额外空间,第二个获得2/3。

  • 当你在网格布局中有两个垂直布局,并且希望在窗口缩放时保持它们的比例不变,可以通过以下几种方法来实现:

方法一:设置拉伸因子(推荐)
这是最常用且最简单的方法,通过设置行列的拉伸因子来控制布局的比例。

#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QTextEdit>

class MainWindow : public QWidget {
public:
    MainWindow(QWidget *parent = nullptr) : QWidget(parent) {
        // 创建网格布局
        QGridLayout *gridLayout = new QGridLayout(this);
        
        // 创建第一个垂直布局
        QVBoxLayout *leftLayout = new QVBoxLayout();
        leftLayout->addWidget(new QLabel("左侧区域"));
        QTextEdit *leftTextEdit = new QTextEdit();
        leftTextEdit->setPlaceholderText("这是左侧文本框");
        leftLayout->addWidget(leftTextEdit);
        
        // 创建第二个垂直布局
        QVBoxLayout *rightLayout = new QVBoxLayout();
        rightLayout->addWidget(new QLabel("右侧区域"));
        QTextEdit *rightTextEdit = new QTextEdit();
        rightTextEdit->setPlaceholderText("这是右侧文本框");
        rightLayout->addWidget(rightTextEdit);
        
        // 将垂直布局添加到网格布局中
        gridLayout->addLayout(leftLayout, 0, 0);  // 第0行,第0列
        gridLayout->addLayout(rightLayout, 0, 1); // 第0行,第1列
        
        // 关键:设置列的拉伸因子来控制比例
        // 这里设置为1:2的比例,左侧占1/3,右侧占2/3
        gridLayout->setColumnStretch(0, 1);  // 第0列拉伸因子为1
        gridLayout->setColumnStretch(1, 2);  //第1列拉伸因子为2
        
        // 可选:设置行拉伸因子(如果有多行的话)
        // gridLayout->setRowStretch(0, 1);
        
        setWindowTitle("布局比例保持示例");
        resize(800, 600);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    MainWindow window;
    window.show();
    
    return app.exec();
}
3. 大小策略(QSizePolicy)
  • 这是Qt布局系统中另一个核心概念。它定义了控件在布局中如何水平或垂直调整大小。

  • 每个QWidget都有一个QSizePolicy。

  • 主要属性:

HorizontalPolicy / VerticalPolicy:常见值有:

Fixed: 大小不能改变,只使用sizeHint。

Minimum: sizeHint是最小大小,可以拉伸,但变大没用。

Maximum: sizeHint是最大大小,可以缩小,但不能变大。

Preferred: sizeHint是最佳大小,可以缩小到minimumSizeHint,也可以拉伸。

Expanding: 和Preferred类似,但非常乐意拉伸,会尽可能多地占用空间(如QTextEdit)。

Ignored: 忽略sizeHint,尽可能大(相当于0,1拉伸因子)。

设置方法:widget->setSizePolicy(QSizePolicy::Policy horizontal, QSizePolicy::Policy vertical);

4. 其他布局和辅助类
QFormLayout:专门为表单设计(标签-字段对),非常方便。它会自动在不同平台上采用该平台的标准表单样式(如macOS的标签右对齐)。

Spacer Item(弹簧):除了用addStretch(),还可以显式创建QSpacerItem并addItem(),提供更精确的控制。

QStackedLayout:同一时间只显示一个控件,类似于选项卡,但没有标签页头。常用于向导或配置界面。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值