一个layout内的边缘和子widget之间的空格由当前widget的style决定. 也可以使用QLayout::setContentsMargins()和QLayout::setSpacing()来改变
QGridLayout的语法: layout->addWidget(widget, row, column, rowSpan, columnSpan);
addStretch() 用来告知layout 管理器填充该处的空白.
layout 管理器的优点:
添加或者移除一个widget, layout会自动修正以适应新的情况, 对hide()和show()也有同样的效果.
当子widget的size hint发生改变时, layout 管理器会自动修改以适应新的size hint
根据子widget的size hint和最小值来设置layout的最小值
有时我们需要修改size policy和widget的size hint来实现我们需要的layout
size policy的值:
Fixed --- 固定的layout, 不能拉伸和收缩. 使用size hint的大小
Minimum --- 表示该widget的最小值就是size hint. 不能够收缩至比该值更小的值. 可以填充可用的空间给widget
Maximum --- 表示该widget的最大值就是size hint, 该widget可以收缩至其最小值 minimum size hint
Preferred --- 该widget的preferred值就是size hint, 在需要的时候可以收缩和拉伸
Expanding --- 表示该widget可以收缩和拉伸, 但其最好选择拉伸
Expanding 和 Preferred的区别: 当一个form包含两者的widget, 该form大小变化时, 额外的空白处则给予Expanding widget, 而Preferred widget保持为其size hint的大小
Minimum, Expanding 和 Ignored这两个Size Policy不再经常使用, 后者忽略widget的size hint和最小值hint
为了补充水平和垂直部分的size policy, 我们还设定了拉伸因子(strectch factor), 可以设置widget在水平或垂直方向的拉伸
如果对一个widget不满意, 我们还可以派生该widget类, 重写其sizeHint()函数
listWidget = new QListWidget;
listWidget->addItem(tr("Appearance"));
listWidget->addItem(tr("Web Browser"));
listWidget->addItem(tr("Mail & News"));
listWidget->addItem(tr("Advanced"));
stackedLayout = new QStackedLayout;
stackedLayout->addWidget(appearancePage);
stackedLayout->addWidget(webBrowserPage);
stackedLayout->addWidget(mailAndNewsPage);
stackedLayout->addWidget(advancedPage);
connect(listWidget, SIGNAL(currentRowChanged(int)),
stackedLayout, SLOT(setCurrentIndex(int)));
listWidget->setCurrentRow(0);
QSplitter的子widget根据创建的顺序自动排列在一起. 相邻的widget之间有splitter bar. 下面是创建的代码
int main(int argc, char *argv[])
QApplication app(argc, argv);
QTextEdit *editor1 = new QTextEdit;
QTextEdit *editor2 = new QTextEdit;
QTextEdit *editor3 = new QTextEdit;
QSplitter splitter(Qt::Horizontal);
splitter.addWidget(editor1);
splitter.addWidget(editor2);
splitter.addWidget(editor3);
splitter.show();
return app.exec();
QSplitter 派生自QWidget, 像其他的widget一样使用.
MailClient的例子
MailClient::MailClient()
rightSplitter = new QSplitter(Qt::Vertical);
rightSplitter->addWidget(messagesTreeWidget);
rightSplitter->addWidget(textEdit);
rightSplitter->setStretchFactor(1, 1);
mainSplitter = new QSplitter(Qt::Horizontal);
mainSplitter->addWidget(foldersTreeWidget);
mainSplitter->addWidget(rightSplitter);
mainSplitter->setStretchFactor(1, 1);
setCentralWidget(mainSplitter);
setWindowTitle(tr("Mail Client"));
readSettings();
QSettings settings("Software Inc.", "Mail Client");
settings.beginGroup("mainWindow");
settings.setValue("geometry", saveGeometry());
settings.setValue("mainSplitter", mainSplitter->saveState());
settings.setValue("rightSplitter", rightSplitter->saveState());
settings.endGroup();
// 读取设置
QSettings settings("Software Inc.", "Mail Client");
settings.beginGroup("mainWindow");
restoreGeometry(settings.value("geometry").toByteArray());
mainSplitter->restoreState(
settings.value("mainSplitter").toByteArray());
rightSplitter->restoreState(
settings.value("rightSplitter").toByteArray());
settings.endGroup();
6.4 Scrolling Areas
如果需要使用滚动条, 最好使用QScrollArea而不是自己实现QScrollBar和滚动功能, 因为这样太复杂
使用QScrollArea的方法是调用setWidget使得该widget成为QScrolllArea视口的子类. 访问视口, QScrollArea::viewport()
QScrollArea scrollArea;
scrollArea.setWidget(iconEditor);
scrollArea.viewport()->setBackgroundRole(QPalette::Dark);
scrollArea.viewport()->setAutoFillBackground(true);
scrollArea.setWindowTitle(QObject::tr("Icon Editor"));
缺省情况是当视口比widget更小的时候才显示滚动条, 如果想滚动条永远显示, 则使用以下代码:
scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
QScrollArea派生自QAbstractScrollArea, QTextEdit和QAbstractItemView的基类为QAbstractScrollBar.
6.5 Dock Windows and Toolbars
Dock Window表示那些可以在QMainWindow Dock的窗口以及可以独立出来的窗口.
QMainWindow 提供了四个浮动区域, 上,下, 左, 右.
每个dock window都有其标题条, 可通过QDockWidget::setFeatures() 设置其属性
QMainWindow::setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); // 上面的函数设置左上角区域属于左边的dock widget区域
如何在一个QDockWidget包装一已存widget, 且插入右边的dock区域
QDockWidget *shapesDockWidget = new QDockWidget(tr("Shapes"));
shapesDockWidget->setObjectName("shapesDockWidget");
shapesDockWidget->setWidget(treeWidget);
shapesDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea
| Qt::RightDockWidgetArea);
addDockWidget(Qt::RightDockWidgetArea, shapesDockWidget);
QToolBar *fontToolBar = new QToolBar(tr("Font"));
fontToolBar->setObjectName("fontToolBar");
fontToolBar->addWidget(familyComboBox);
fontToolBar->addWidget(sizeSpinBox);
fontToolBar->addAction(boldAction);
fontToolBar->addAction(italicAction);
fontToolBar->addAction(underlineAction);
fontToolBar->setAllowedAreas(Qt::TopToolBarArea
| Qt::BottomToolBarArea);
addToolBar(fontToolBar);
保存和回复设置
// 保存
QSettings settings("Software Inc.", "Icon Editor");
settings.beginGroup("mainWindow");
settings.setValue("geometry", saveGeometry());
settings.setValue("state", saveState());
settings.endGroup();
// 恢复
QSettings settings("Software Inc.", "Icon Editor");
settings.beginGroup("mainWindow");
restoreGeometry(settings.value("geometry").toByteArray());
restoreState(settings.value("state").toByteArray());
settings.endGroup();
QMainWindow还给dock window和Toolbar提供了右键菜单
6.6 多文档接口
一个MDI应用程序通过使用QMdiArea类作为中心widget以及让每个文档窗口为一个QMdiArea的子窗口
子窗口菜单-MDI应用程序提供了一系列菜单选项表示所有的文档窗口, 当前的文档窗口会有选中标志
在构造函数中, 创建一个QMdiArea对象并设置为中心widget, 并将subWindowActivated()信号发送给一个slot, 实现菜单的更新
在构造函数的结尾部分有一行代码: QTimer::singleShot(0, this, SLOT(loadFiles()));
表示0秒的间隔之后调用loadFiles(). 在事件循环为空闲时, 计时器运行完时间, 事实上表示当构造函数完成之后, 主窗口显示之时, 调用loadFiles()函数
如果不这样做, 当有大量的文件之时, 直到文件加载完毕之后构造函数还未必完成时, 用户也许会在屏幕上看不到任何东西. 而认为程序失败且重启程序
void MainWindow::loadFiles()
QStringList args = QApplication::arguments();
args.removeFirst();
if (!args.isEmpty()) {
foreach (QString arg, args)
openFile(arg);
mdiArea->cascadeSubWindows();
} else {
newFile();
mdiArea->activateNextSubWindow();
connect(editor, SIGNAL(copyAvailable(bool)),
cutAction, SLOT(setEnabled(bool)));
connect(editor, SIGNAL(copyAvailable(bool)),
copyAction, SLOT(setEnabled(bool)));
QMdiArea的addSubWindow() 函数可以创建一个新的QMdiSubWindow: QMdiSubWindow *subWindow = mdiArea->addSubWindow(editor);
QActionGroup 确保只有一个窗口菜单选项被选中.
QMdiArea::activeSubWindow() --- 返回其活跃窗口
qobject_cast<Editor *> --- 用于强制转换.
QTextCursor::hasSelection () --- 返回当前文本光标是否选择了文本
QAction::setChecked() --- 设置选中该Action
QScintilla --- 代码编辑的widget
每个子窗口设置 Qt::WA_DeleteOnClose 属性, 当关闭的时候删除该窗口, 以免内存泄漏