【Qt笔记】QDockWidget控件详解
目录
引言
一、基本概念
二、功能特性
三、常用方法
3.1 构造函数
3.2 设置和获取部件
3.3 设置停靠区域
3.4 设置标题栏文本
3.5 设置功能特性
3.6 显示或隐藏窗口
3.7 设置或获取自定义标题栏
四、常用信号
4.1 allowedAreasChanged
4.2 featuresChanged
4.3 topLevelChanged
4.4 dockLocationChanged
4.5 visibilityChanged
五、应用示例
5.1 头文件(mainwindow.h)
5.2 源文件(mainwindow.cpp)
5.3 主函数文件(main.cpp)
5.4 代码解析
5.5 运行效果展示
结语
引言
QDockWidget是Qt框架中的一个控件类,它提供了一个可停靠的面板,该面板可用于显示和编辑各种内容。本文是对QDockWidget控件的详细解析,内容涵盖了QDockWidget的基本概念、功能特性、使用方法和注意事项等方面。
一、基本概念
QDockWidget是Qt框架中的一个窗口部件,它实现了可停靠的窗口功能。在QMainWindow中,QDockWidget可以作为辅助窗口停靠在主窗口的四周(左侧、右侧、顶部或底部),也可以作为独立的浮动窗口出现在主窗口之外。QDockWidget提供了灵活的布局管理和标题栏定制,允许用户根据需要调整窗口的位置和大小,以及显示或隐藏窗口。
二、功能特性
- 停靠功能:
- QDockWidget允许用户将窗口部件停靠在主窗口的各个位置,如左侧、右侧、上方或下方。
- 用户可以通过拖动和放置的方式改变QDockWidget的停靠位置,将其移动到新的区域。
- 浮动窗口:
- QDockWidget具备浮动功能,用户可以将其拖动到主窗口之外,使其成为一个独立的浮动窗口。
- 浮动窗口可以调整位置和大小,并可以重新停靠在主窗口的任意位置。
- 可关闭:
- QDockWidget可以关闭,允许用户根据需要隐藏或显示它。
- 关闭QDockWidget后,它不会从内存中删除,只是从界面上隐藏起来,用户可以通过调用相关方法将其重新显示。
- 自定义部件:
- 用户可以将自定义的部件放在QDockWidget中,以构建自定义的界面元素。
- 通过设置QWidget对象作为QDockWidget的子部件,可以显示各种内容,如表单、文本编辑器、按钮等。
- 标题栏定制:
- QDockWidget提供了标题栏定制功能,用户可以通过设置自定义的标题栏控件来替换默认的标题栏。
- 自定义标题栏控件可以包含各种控件元素,如按钮、文本框等,以实现更丰富的界面交互。
三、常用方法
QDockWidget类提供了一系列函数,用于配置和管理停靠式窗口的行为和外观。以下是一些常用的QDockWidget方法的介绍和使用方法:
3.1 构造函数
QDockWidget 有多个构造函数,其中最常用的形式如下:
QDockWidget::QDockWidget(const QString &title, QWidget *parent = nullptr);
- title 参数指定了QDockWidget 的标题栏显示的文本。
- parent 参数指定了QDockWidget 的父部件,通常是QMainWindow。例如:
QDockWidget *dockWidget = new QDockWidget(tr("My DockWidget"), this);
3.2 设置和获取部件
- setWidget(QWidget *widget):将一个 QWidget 设置为 QDockWidget 的内容部件。例如,如果有一个自定义的 QWidget 派生类 MyWidget,可以这样设置:
MyWidget *myWidget = new MyWidget;
dockWidget->setWidget(myWidget);
- QWidget *widget() const:获取当前 QDockWidget 所包含的部件。
3.3 设置停靠区域
setAllowedAreas(Qt::DockWidgetAreas areas):指定QDockWidget可以停靠的区域。
Qt::DockWidgetAreas是一个枚举类型,包括 Qt::LeftDockWidgetArea(左侧)、Qt::RightDockWidgetArea(右侧)、Qt::TopDockWidgetArea(顶部)、Qt::BottomDockWidgetArea(底部)以及它们的组合。
例如,允许在左侧和顶部停靠:
dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::TopDockWidgetArea);
3.4 设置标题栏文本
setWindowTitle(const QString &title):可以动态地改变QDockWidget标题栏的文本。
dockWidget->setWindowTitle("这是新标题");
3.5 设置功能特性
void setFeatures(QDockWidget::DockWidgetFeatures features):设置QDockWidget的功能特性,如关闭按钮、可移动、可浮动等。
QDockWidget::DockWidgetFeatures 枚举中一些常用特性标志的详细介绍:
QDockWidget::DockWidgetClosable:如果设置了此标志,QDockWidget 将显示一个关闭按钮,用户可以通过点击它来关闭(隐藏)QDockWidget 。
QDockWidget::DockWidgetMovable:如果设置了此标志,QDockWidget 可以在其允许的停靠区域内被拖动和重新定位。
QDockWidget::DockWidgetFloatable:如果设置了此标志,QDockWidget 可以被拖出停靠区域并浮动为一个独立的窗口。
QDockWidget::DockWidgetVerticalTitleBar:(在Qt 6中已弃用):如果设置了此标志(注意,这个标志在Qt 6中已经被移除,因为Qt 6中的 QDockWidget 默认总是使用垂直标题栏),QDockWidget 的标题栏将垂直显示(通常这是不必要的,因为默认行为就是垂直的)。
QDockWidget::AllDockWidgetFeatures:这是一个方便的标志,它包含了上述所有特性标志(除了已弃用的 DockWidgetVerticalTitleBar)。
// 创建一个QDockWidget
QDockWidget *dockWidget = new QDockWidget("Dockable with Features", &mainWindow);
// 设置QDockWidget的功能特性:可关闭、可移动、可浮动
dockWidget->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
3.6 显示或隐藏窗口
- void setVisible(bool visible):显示或隐藏QDockWidget。如果设置为true,则显示窗口;如果设置为false,则隐藏窗口。
- bool isVisible() const:返回窗口是否可见。如果窗口可见,则返回true;否则返回false。
例:下方代码设置窗口是否可见,如果当前窗口是可见的,则将其设置为不可见;如果当前窗口是不可见的,则将其设置为可见。
dockWidget->setVisible(!dockWidget->isVisible());
3.7 设置或获取自定义标题栏
- void setTitleBarWidget(QWidget *widget):设置自定义的标题栏控件,替换掉默认的标题栏。
- QWidget *titleBarWidget():返回自定义的标题栏控件。
// 创建自定义标题栏实例
CustomTitleBar *customTitleBar = new CustomTitleBar(dockWidget);
// 设置自定义标题栏到QDockWidget
dockWidget->setTitleBarWidget(customTitleBar);
// 获取自定义标题栏控件(这里简单打印其指针地址验证获取功能,实际可做更多操作)
QWidget *retrievedWidget = dockWidget->titleBarWidget();
qDebug() << "Retrieved custom title bar widget address: " << retrievedWidget;
四、常用信号
QDockWidget在状态发生变化时会发出一些信号,这些信号可以用于连接槽函数,以实现相应的处理逻辑。以下是一些常用的QDockWidget信号:
4.1 allowedAreasChanged
allowedAreasChanged(Qt::DockWidgetAreas allowedAreas): 当QDockWidget的允许停靠区域发生变化时发出。
#include <QMainWindow>
#include <QDockWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void handleAllowedAreasChanged(Qt::DockWidgetAreas allowedAreas);
private:
QDockWidget *dockWidget;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 创建 QDockWidget
dockWidget = new QDockWidget(tr("My DockWidget"), this);
// 创建一个简单的内部部件(这里仅放置一个按钮用于示意)
QWidget *widget = new QWidget;
QVBoxLayout *layout = new QVBoxLayout;
QPushButton *button = new QPushButton(tr("Click Me"));
layout->addWidget(button);
widget->setLayout(layout);
dockWidget->setWidget(widget);
// 初始设置允许停靠的区域
dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
// 连接 allowedAreasChanged 信号到自定义的槽函数
connect(dockWidget, &QDockWidget::allowedAreasChanged, this, &MainWindow::handleAllowedAreasChanged);
// 将 QDockWidget 添加到主窗口
addDockWidget(Qt::RightDockWidgetArea, dockWidget);
// 模拟改变允许停靠区域(这里通过一个按钮点击来触发改变,实际应用中可以根据具体逻辑触发)
QPushButton *changeAreasButton = new QPushButton(tr("Change Allowed Areas"), this);
connect(changeAreasButton, &QPushButton::clicked, this, [this]() {
// 改变允许停靠区域为顶部和底部
dockWidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
});
this->layout()->addWidget(changeAreasButton);
}
void MainWindow::handleAllowedAreasChanged(Qt::DockWidgetAreas allowedAreas)
{
qDebug() << "Allowed areas have changed. New allowed areas: " << allowedAreas;
if (allowedAreas.testFlag(Qt::TopDockWidgetArea)) {
qDebug() << "Now allowed to dock at the top.";
}
if (allowedAreas.testFlag(Qt::BottomDockWidgetArea)) {
qDebug() << "Now allowed to dock at the bottom.";
}
if (allowedAreas.testFlag(Qt::LeftDockWidgetArea)) {
qDebug() << "Now allowed to dock at the left.";
}
if (allowedAreas.testFlag(Qt::RightDockWidgetArea)) {
qDebug() << "Now allowed to dock at the right.";
}
}
MainWindow::~MainWindow()
{
}
在这个示例中:
- 首先创建了一个 QDockWidget 并设置了初始的允许停靠区域,同时连接了 allowedAreasChanged 信号到 handleAllowedAreasChanged 槽函数。
- 然后添加了一个按钮用于模拟改变 QDockWidget 的允许停靠区域,当点击按钮改变区域后,handleAllowedAreasChanged 函数会被调用,在函数中可以根据新的允许停靠区域进行相应的逻辑处理,并打印相关信息。
4.2 featuresChanged
featuresChanged(QDockWidget::DockWidgetFeatures features): 当QDockWidget的功能标志发生变化时发出。
#include <QMainWindow>
#include <QDockWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void handleFeaturesChanged(QDockWidget::DockWidgetFeatures features);
private:
QDockWidget *dockWidget;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 创建 QDockWidget
dockWidget = new QDockWidget(tr("My DockWidget"), this);
// 创建内部部件
QWidget *widget = new QWidget;
QVBoxLayout *layout = new QVBoxLayout;
QPushButton *button = new QPushButton(tr("Click Me"));
layout->addWidget(button);
widget->setLayout(layout);
dockWidget->setWidget(widget);
// 设置初始的 DockWidgetFeatures(这里示例设置可关闭和可浮动)
dockWidget->setFeatures(QDockWidget::DockWidgetFeature::DockWidgetClosable | QDockWidget::DockWidgetFeature::DockWidgetFloatable);
// 连接 featuresChanged 信号到自定义槽函数
connect(dockWidget, &QDockWidget::featuresChanged, this, &MainWindow::handleFeaturesChanged);
// 将 QDockWidget 添加到主窗口
addDockWidget(Qt::RightDockWidgetArea, dockWidget);
// 模拟改变功能标志(通过按钮点击改变为不可关闭和可移动)
QPushButton *changeFeaturesButton = new QPushButton(tr("Change Features"), this);
connect(changeFeaturesButton, &QPushButton::clicked, this, [this]() {
dockWidget->setFeatures(QDockWidget::DockWidgetFeature::DockWidgetMovable);
});
this->layout()->addWidget(changeFeaturesButton);
}
void MainWindow::handleFeaturesChanged(QDockWidget::DockWidgetFeatures features)
{
qDebug() << "DockWidget features have changed. New features: ";
if (features.testFlag(QDockWidget::DockWidgetFeature::DockWidgetClosable)) {
qDebug() << "Closable";
}
if (features.testFlag(QDockWidget::DockWidgetFeature::DockWidgetFloatable)) {
qDebug() << "Floatable";
}
if (features.testFlag(QDockWidget::DockWidgetFeature::DockWidgetMovable)) {
qDebug() << "Movable";
}
}
MainWindow::~MainWindow()
{
}
在此示例中:
- 先创建 QDockWidget 并设置初始的功能标志,连接 featuresChanged 信号到对应的槽函数。
- 接着添加一个按钮来模拟改变功能标志,当点击按钮改变后,handleFeaturesChanged 槽函数会被调用,根据新的功能标志输出相应的信息,展示对功能变化的处理逻辑。
4.3 topLevelChanged
topLevelChanged(bool topLevel): 当QDockWidget的浮动状态发生变化时发出(即从停靠状态变为浮动状态,或从浮动状态变为停靠状态)。
#include <QMainWindow>
#include <QDockWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void handleTopLevelChanged(bool topLevel);
private:
QDockWidget *dockWidget;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 创建 QDockWidget
dockWidget = new QDockWidget(tr("My DockWidget"), this);
// 创建内部部件
QWidget *widget = new QWidget;
QVBoxLayout *layout = new QVBoxLayout;
QPushButton *button = new QPushButton(tr("Click Me"));
layout->addWidget(button);
widget->setLayout(layout);
dockWidget->setWidget(widget);
// 连接 topLevelChanged 信号到自定义槽函数
connect(dockWidget, &QDockWidget::topLevelChanged, this, &MainWindow::handleTopLevelChanged);
// 将 QDockWidget 添加到主窗口
addDockWidget(Qt::RightDockWidgetArea, dockWidget);
// 模拟将 QDockWidget 变为浮动状态(通过按钮点击)
QPushButton *toggleTopLevelButton = new QPushButton(tr("Toggle Top Level"), this);
connect(toggleTopLevelButton, &QPushButton::clicked, this, [this]() {
if (dockWidget->isFloating()) {
dockWidget->setFloating(false);
} else {
dockWidget->setFloating(true);
}
});
this->layout()->addWidget(toggleTopLevelButton);
}
void MainWindow::handleTopLevelChanged(bool topLevel)
{
if (topLevel) {
qDebug() << "QDockWidget is now floating.";
} else {
qDebug() << "QDockWidget is now docked.";
}
}
MainWindow::~MainWindow()
{
}
在这个例子里:
- 创建 QDockWidget 并连接 topLevelChanged 信号到相应槽函数后,添加到主窗口。
- 然后设置一个按钮用于模拟切换 QDockWidget 的浮动与停靠状态,每当状态改变时,handleTopLevelChanged 槽函数就会被触发,根据传入的 topLevel 参数判断并打印当前是浮动还是停靠状态。
4.4 dockLocationChanged
dockLocationChanged(Qt::DockWidgetArea area): 当QDockWidget的停靠位置因手工拖拽或代码执行导致停靠位置发生变化时发出。
#include <QMainWindow>
#include <QDockWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void handleDockLocationChanged(Qt::DockWidgetArea area);
private:
QDockWidget *dockWidget;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 创建 QDockWidget
dockWidget = new QDockWidget(tr("My DockWidget"), this);
// 创建内部部件
QWidget *widget = new QWidget;
QVBoxLayout *layout = new QVBoxLayout;
QPushButton *button = new QPushButton(tr("Click Me"));
layout->addWidget(button);
widget->setLayout(layout);
dockWidget->setWidget(widget);
// 连接 dockLocationChanged 信号到自定义槽函数
connect(dockWidget, &QDockWidget::dockLocationChanged, this, &MainWindow::handleDockLocationChanged);
// 将 QDockWidget 添加到主窗口
addDockWidget(Qt::RightDockWidgetArea, dockWidget);
// 模拟改变停靠位置(通过按钮点击将其移动到左侧停靠区域)
QPushButton *changeLocationButton = new QPushButton(tr("Change Dock Location"), this);
connect(changeLocationButton, &QPushButton::clicked, this, [this]() {
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
});
this->layout()->addWidget(changeLocationButton);
}
void MainWindow::handleDockLocationChanged(Qt::DockWidgetArea area)
{
qDebug() << "QDockWidget's dock location has changed. New location: " << area;
if (area == Qt::LeftDockWidgetArea) {
qDebug() << "Now docked at the left.";
}
if (area == Qt::RightDockWidgetArea) {
qDebug() << "Now docked at the right.";
}
if (area == Qt::TopDockWidgetArea) {
qDebug() << "Now docked at the top.";
}
if (area == Qt::BottomDockWidgetArea) {
qDebug() << "Now docked at the bottom.";
}
}
MainWindow::~MainWindow()
{
}
在此示例中:
- 先是创建 QDockWidget,连接 dockLocationChanged 信号到对应的槽函数,然后将其添加到主窗口的右侧停靠区域。
- 接着添加一个按钮用于模拟改变 QDockWidget 的停靠位置,当点击按钮移动 QDockWidget 后,handleDockLocationChanged 槽函数会被调用,根据新的停靠区域参数输出相应的提示信息。
4.5 visibilityChanged
visibilityChanged(bool visible): 当QDockWidget的可见状态发生变化时发出,包括显示或隐藏窗口。
#include <QMainWindow>
#include <QDockWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void handleVisibilityChanged(bool visible);
private:
QDockWidget *dockWidget;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 创建 QDockWidget
dockWidget = new QDockWidget(tr("My DockWidget"), this);
// 创建内部部件
QWidget *widget = new QWidget;
QVBoxLayout *layout = new QVBoxLayout;
QPushButton *button = new QPushButton(tr("Click Me"));
layout->addWidget(button);
widget->setLayout(layout);
dockWidget->setWidget(widget);
// 连接 visibilityChanged 信号到自定义槽函数
connect(dockWidget, &QDockWidget::visibilityChanged, this, &MainWindow::handleVisibilityChanged);
// 将 QDockWidget 添加到主窗口
addDockWidget(Qt::RightDockWidgetArea, dockWidget);
// 模拟隐藏和显示 QDockWidget(通过按钮点击)
QPushButton *toggleVisibilityButton = new QPushButton(tr("Toggle Visibility"), this);
connect(toggleVisibilityButton, &QPushButton::clicked, this, [this]() {
dockWidget->setVisible(!dockWidget->isVisible());
});
this->layout()->addWidget(toggleVisibilityButton);
}
void MainWindow::handleVisibilityChanged(bool visible)
{
if (visible) {
qDebug() << "QDockWidget is now visible.";
} else {
qDebug() << "QDockWidget is now hidden.";
}
}
MainWindow::~MainWindow()
{
}
在这个示例中:
- 首先创建 QDockWidget 并连接 visibilityChanged 信号到相应的槽函数,随后将其添加到主窗口。
- 接着添加一个按钮用于模拟切换 QDockWidget 的可见状态,每次状态改变时,handleVisibilityChanged 槽函数都会被触发,根据传入的 visible 参数判断并打印当前是显示还是隐藏状态。
五、应用示例
以下是一个使用QDockWidget控件的简单 Qt 示例代码,展示了如何创建一个主窗口,并添加可停靠的窗口部件(QDockWidget)。这个示例创建了一个简单的文本编辑界面,同时有一个可停靠的颜色选择器QDockWidget,用于改变文本编辑区域的背景颜色。
5.1 头文件(mainwindow.h)
#include <QMainWindow>
#include <QTextEdit>
#include <QDockWidget>
#include <QColorDialog>
#include <QPushButton>
#include <QVBoxLayout>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void changeBackgroundColor();
private:
QTextEdit *textEdit;
QDockWidget *dockWidget;
};
5.2 源文件(mainwindow.cpp)
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 创建文本编辑部件
textEdit = new QTextEdit(this);
setCentralWidget(textEdit);
// 创建QDockWidget
dockWidget = new QDockWidget(tr("Color Chooser"), this);
// 设置可移动、可浮动、可关闭功能
dockWidget->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
// 创建一个按钮用于触发颜色选择对话框
QPushButton *button = new QPushButton(tr("Change Background Color"), this);
connect(button, &QPushButton::clicked, this, &MainWindow::changeBackgroundColor);
// 将按钮添加到QDockWidget的布局中
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(button);
QWidget *widget = new QWidget;
widget->setLayout(layout);
dockWidget->setWidget(widget);
// 将QDockWidget添加到主窗口
addDockWidget(Qt::RightDockWidgetArea, dockWidget);
}
MainWindow::~MainWindow()
{
}
void MainWindow::changeBackgroundColor()
{
QColor color = QColorDialog::getColor(Qt::white, this);
if (color.isValid()) {
textEdit->setStyleSheet(QString("QTextEdit { background-color: %1 }").arg(color.name()));
}
}
5.3 主函数文件(main.cpp)
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
5.4 代码解析
首先创建了一个QTextEdit作为主窗口的中心部件,通过setCentralWidget设置。
接着创建QDockWidget,设置QDockWidget控件可移动、可浮动、可关闭的功能,之后设置了标题为 "Color Chooser"。然后在QDockWidget内部创建了一个按钮,并连接按钮的点击信号到自定义的槽函数changeBackgroundColor,这个槽函数用于弹出颜色选择对话框,并根据选择的颜色改变文本编辑区域的背景颜色。
最后将包含按钮的布局添加到QDockWidget中,并通过addDockWidget将QDockWidget添加到主窗口的右侧停靠区域(Qt::RightDockWidgetArea)。 changeBackgroundColor函数中,使用QColorDialog弹出颜色选择对话框获取用户选择的颜色,如果颜色有效,则通过设置样式表的方式改变QTextEdit的背景颜色。
5.5 运行效果展示
结语
在 Qt 应用程序开发中,用户界面的布局和交互性是至关重要的方面。QDockWidget 控件作为 Qt 框架中用于创建可停靠窗口的重要组件,为构建灵活、高效且具有良好用户体验的界面提供了强大的支持。它允许用户将特定的窗口部件(如工具面板、属性编辑器等)以可停靠、可浮动的方式放置在主窗口的不同区域,极大地提高了界面的可定制性和操作便利性。
如需更多信息,建议查阅Qt官方文档:
QDockWidget Class | Qt Widgets 6.8.1