在上一篇文章中,我们全面讲解了Qt5框架下丰富的基础控件和数据视图控件。但谈何容易,如果只是简单摆放这些控件,想要打造优雅的UI界面可就难了。今天我们就来探索Qt5强大的布局和容器管理机制,学习如何通过灵活组合,将控件们统统服务帖帖地安排妥当。
一、布局的艺术: 控件们的"教头"
布局无疑是Qt5 GUI开发中最基础也最关键的部分。通过布局,我们能够精准地控制窗口部件们的位置和大小,使整个界面井然有序。而Qt5为此提供了多种灵活强大的布局类,每一种都是控件们的"教头":
1、QHBoxLayout: 横向带班
QWidget *window = new QWidget;
QPushButton *btn1 = new QPushButton("Button 1");
QPushButton *btn2 = new QPushButton("Button 2");
QPushButton *btn3 = new QPushButton("Button 3");
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(btn1);
layout->addWidget(btn2);
layout->addWidget(btn3);
window->setLayout(layout);
QHBoxLayout将子控件水平放置,极其常用。但需要注意,即使是横向布局,子控件的高度也是会被拉伸以适应布局高度的。通过设置stretch因子,我们还可以控制各个子控件的拉伸比例。
2、QVBoxLayout: 垂直排布子控件
QVBoxLayout会将子控件垂直排列,这在界面中显示一系列选项或构建工具条时非常管用:
QWidget *window = new QWidget;
QVBoxLayout *layout = new QVBoxLayout;
QPushButton *btn1 = new QPushButton("Button 1");
QPushButton *btn2 = new QPushButton("Button 2");
QPushButton *btn3 = new QPushButton("Button 3");
layout->addWidget(btn1);
layout->addWidget(btn2);
layout->addWidget(btn3);
// 添加一些间隙
layout->addSpacing(20);
// 添加一个展开按钮 占用所有剩余空间
QCheckBox *expandBox = new QCheckBox("Expand");
layout->addWidget(expandBox, 1, Qt::AlignTop);
window->setLayout(layout);
3、QGridLayout: 网格陈列
QWidget *window = new QWidget;
QGridLayout *layout = new QGridLayout;
QPushButton *btn1 = new QPushButton("Button (0, 0)");
QPushButton *btn2 = new QPushButton("Button (0, 1)");
QPushButton *btn3 = new QPushButton("Button (1, 0)");
QPushButton *btn4 = new QPushButton("Button (1, 1)");
layout->addWidget(btn1, 0, 0);
layout->addWidget(btn2, 0, 1);
layout->addWidget(btn3, 1, 0);
layout->addWidget(btn4, 1, 1);
window->setLayout(layout);
QGridLayout以网格的形式排列子控件,类似于HTML中的表格。我们可以通过addWidget指定子控件应该放在哪个网格单元,实现最自由的布局方式。
在这个例子中,三个按钮被垂直排列,之后还添加了一些间隙,最后一个QCheckBox则占据了所有剩余的垂直空间。通过给addWidget传递不同的stretch因子,我们可以控制各个子控件的拉伸程度。
4、其他常用布局
除了上面这几种,Qt5还为我们准备了更多常用的布局类:
- QFormLayout: 表单布局,方便构建类似"标签-控件"形式的配置界面
- QStackedLayout: 层叠布局,一次只显示一个子控件,用于实现Tab分页等
通过不同布局类的组合使用,我们能打造出任何复杂的UI布局。如果这还不够,Qt5甚至允许我们自定义布局类,以满足最特殊的定制化需求。
二、容器统领一方: 控件世界的"王爷"
当然,除了灵活运用布局之外,Qt5还为我们准备了多种容器控件,让整个UI界面组织更有条不紊。这些控件就像是控件世界的"王爷",撑腰祖上:
1、QGroupBox: 圈地自己人
QGroupBox *groupBox = new QGroupBox(tr("Options"));
QRadioButton *radio1 = new QRadioButton(tr("Option 1"));
QRadioButton *radio2 = new QRadioButton(tr("Option 2"));
QRadioButton *radio3 = new QRadioButton(tr("Option 3"));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(radio1);
layout->addWidget(radio2);
layout->addWidget(radio3);
groupBox->setLayout(layout);
QGroupBox用一个框将多个相关控件组合在一起,配合标题和布局,显得井井有条。通常我们会把一组选项或配置项放到GroupBox中,使界面结构清晰。
2、QTabWidget: 分页应有尽有
QTabWidget *tabWidget = new QTabWidget;
QWidget *tab1 = new QWidget;
QWidget *tab2 = new QWidget;
QVBoxLayout *layout1 = new QVBoxLayout;
layout1->addWidget(new QRadioButton(tr("Option 1")));
tab1->setLayout(layout1);
QVBoxLayout *layout2 = new QVBoxLayout;
layout2->addWidget(new QCheckBox(tr("Option 2")));
tab2->setLayout(layout2);
tabWidget->addTab(tab1, tr("Tab 1"));
tabWidget->addTab(tab2, tr("Tab 2"));
QTabWidget是最常用的分页容器,能将一个界面划分为多个Tab页,每个页面可以拥有独立的布局。通过选择不同的Tab,就能切换显示的内容,从而合理地组织复杂的界面结构。
3、QStackedLayout: 层叠切换子控件
QStackedLayout将子控件以层叠的方式管理,一次只显示其中一个控件,通常用于分页场景:
QWidget *window = new QWidget;
QStackedLayout *layout = new QStackedLayout;
QLabel *label1 = new QLabel("Page 1");
QLabel *label2 = new QLabel("Page 2");
layout->addWidget(label1);
layout->addWidget(label2);
window->setLayout(layout);
// 切换当前显示的控件
QPushButton *btn1 = new QPushButton("Show Page 1");
QPushButton *btn2 = new QPushButton("Show Page 2");
connect(btn1, &QPushButton::clicked, [layout]{ layout->setCurrentIndex(0); });
connect(btn2, &QPushButton::clicked, [layout]{ layout->setCurrentIndex(1); });
这里我们创建了两个QLabel作为两个不同的页面,通过QPushButton切换QStackedLayout当前显示的控件索引。除了手动切换,QStackedLayout也可以根据其他控件的状态自动切换当前页,比如QTabWidget就是利用它实现分页的。
4、QFormLayout: 构建表单配置界面
QFormLayout的目标就是构建标准的"标签-控件"形式的表单界面:
QWidget *window = new QWidget;
QFormLayout *layout = new QFormLayout;
QLineEdit *nameEdit = new QLineEdit;
QLineEdit *ageEdit = new QLineEdit;
QComboBox *countryCombo = new QComboBox;
countryCombo->addItems({"China", "USA", "Russia"});
layout->addRow("Name", nameEdit);
layout->addRow("Age", ageEdit);
layout->addRow("Country", countryCombo);
// 添加一个占位行 插入垂直间隙
layout->addRow(QWidget());
QCheckBox *rememberMe = new QCheckBox("Remember Me");
layout->addRow(rememberMe);
window->setLayout(layout);
QFormLayout会自动将addRow中的第一个元素作为标签项,其余元素作为实际的控件项。我们可以轻松添加文本框、下拉框等各种配置项,最后还插入了一个占位行作为分隔。
5、QMenu & QToolBar: 快捷操作的大本营
QMainWindow *mainWin = new QMainWindow;
QMenu *fileMenu = mainWin->menuBar()->addMenu(tr("&File"));
fileMenu->addAction(tr("&New"));
fileMenu->addAction(tr("&Open"));
QToolBar *toolBar = mainWin->addToolBar(tr("File Actions"));
toolBar->addAction(QIcon(":/new.png"), tr("New File"));
toolBar->addAction(QIcon(":/open.png"), tr("Open File"));
QMenu和QToolBar都是收纳应用程序常用操作的好去处。前者一般作为菜单栏使用,后者则显示为工具条。结合快捷键、图标等,它们给用户以高效便捷的操作体验。
三、总有办法满足你
通过灵活运用Qt5提供的各种布局与容器控件,再辅之以嵌套组合,我们就能打造出任何复杂的UI界面。不论你有怎样的设计需求,Qt5的布局容器体系都能圆满满足。
但可别小瞧了这些控件哦,它们虽然"权力"不及核心控件那么大,但也拥有强大的自定义能力。比如QGroupBox和QTabWidget都支持多种内置样式,QMenu更是允许我们自己实现子菜单代理,实现独具特色的菜单视图。
未来,QML这种全新的UI开发范式或将颠覆性地改变Qt界面的构建方式。但就算届时,布局和容器控件这些"传统存在"也必将与时俱进,在新时代绽放更强大的能力。
QML固然吸引人,但相比之下你是否更钟情于Qt5经典的C++控件编程呢?又或者两者你通吃都了解?快在评论区留言,分享你的见解和心得!无论你是Qt5的资深玩家,还是仅仅是个入门新手,这里都有属于你的学习乐园。