Qt Advanced Docking System:如何将浮动停靠窗锁定在主窗口边界内
Qt Advanced Docking System:如何将浮动停靠窗锁定在主窗口边界内
嘿,刚好我对这个 docking 库挺熟悉的,咱们来一步步解决这个问题!你想要的这种“把浮动dock锁在主窗口里”的效果,其实不需要修改库的源码,在咱们自己的代码里就能实现。
核心思路是:Qt Advanced Docking System 的浮动dock其实是被包装在 CFloatingDockContainer 这个容器里的,我们可以通过监听dock的浮动状态变化,给对应的浮动容器加上位置限制,确保它不会跑出主窗口的边界。
接下来给你具体的代码修改方案,直接在你现有的 MainWin 类上扩展就行:
第一步:更新类声明
先在 MainWin 类里添加需要的槽函数、事件过滤器和重写的窗口事件声明:
#include <QMainWindow> #include <DockManager.h> #include <QToolBar> #include <QMdiArea> #include <CFloatingDockContainer.h> // 别忘了加这个头文件 using namespace ads; class MainWin: public QMainWindow { Q_OBJECT public: MainWin(QWidget *parent = nullptr); ~MainWin(); private slots: // 监听dock浮动状态变化的槽函数 void onDockWidgetFloatingChanged(CDockWidget* dockWidget, bool floating); protected: // 事件过滤器,用来限制浮动容器的位置 bool eventFilter(QObject* watched, QEvent* event) override; // 主窗口大小变化时,同步调整浮动容器位置 void resizeEvent(QResizeEvent* event) override; private: CDockManager mDockManager; };
第二步:连接信号与实现槽函数
在 MainWin 的构造函数里,把dock管理器的浮动状态变化信号和咱们的槽函数连起来:
MainWin::MainWin(QWidget *parent) : QMainWindow(parent),mDockManager(this) { setCentralWidget(&mDockManager); CDockWidget *dock=new CDockWidget("New Dock",&mDockManager); // 这里可以给dock加个测试用的中心部件,比如QTextEdit dock->setWidget(new QTextEdit); mDockManager.addDockWidget(LeftDockWidgetArea, dock); // 关键:连接浮动状态变化信号 connect(&mDockManager, &CDockManager::dockWidgetFloatingChanged, this, &MainWin::onDockWidgetFloatingChanged); }
然后实现槽函数,当dock变为浮动状态时,给它的浮动容器安装事件过滤器:
void MainWin::onDockWidgetFloatingChanged(CDockWidget* dockWidget, bool floating) { if (floating) { // 获取当前dock对应的浮动容器 CFloatingDockContainer* container = dockWidget->floatingWidget(); if (container) { // 给容器装事件过滤器,用来监控它的移动 container->installEventFilter(this); } } else { // 当dock变回非浮动状态时,移除事件过滤器(可选,清理资源) CFloatingDockContainer* container = dockWidget->floatingWidget(); if (container) { container->removeEventFilter(this); } } }
第三步:实现事件过滤器,限制容器位置
这部分是核心,每次浮动容器移动时,我们检查它的位置,如果跑出主窗口边界,就把它拉回来:
bool MainWin::eventFilter(QObject* watched, QEvent* event) { // 只处理移动事件 if (event->type() == QEvent::Move) { CFloatingDockContainer* container = qobject_cast<CFloatingDockContainer*>(watched); if (container) { // 获取主窗口的全局坐标矩形(包括边框) QRect mainWindowRect = this->frameGeometry(); // 获取浮动容器的当前全局坐标矩形 QRect containerRect = container->frameGeometry(); // 计算新的位置,确保容器完全在主窗口内 QPoint newPos = containerRect.topLeft(); // 限制左边界:不能比主窗口左边界更靠左 if (newPos.x() < mainWindowRect.left()) { newPos.setX(mainWindowRect.left()); } // 限制右边界:容器右边缘不能超出主窗口右边界 if (newPos.x() + containerRect.width() > mainWindowRect.right()) { newPos.setX(mainWindowRect.right() - containerRect.width()); } // 限制上边界 if (newPos.y() < mainWindowRect.top()) { newPos.setY(mainWindowRect.top()); } // 限制下边界:容器下边缘不能超出主窗口下边界 if (newPos.y() + containerRect.height() > mainWindowRect.bottom()) { newPos.setY(mainWindowRect.bottom() - containerRect.height()); } // 如果位置需要调整,就设置新位置 if (newPos != containerRect.topLeft()) { container->move(newPos); } } } // 别忘了把事件传给父类处理 return QMainWindow::eventFilter(watched, event); }
第四步:处理主窗口大小变化
当主窗口被拉大或缩小时,我们得同步调整所有浮动容器的位置,避免它们被“卡”在原来的位置超出新的窗口边界:
void MainWin::resizeEvent(QResizeEvent* event) { QMainWindow::resizeEvent(event); // 遍历所有当前处于浮动状态的容器 QList<CFloatingDockContainer*> floatingContainers = mDockManager.floatingContainers(); for (CFloatingDockContainer* container : floatingContainers) { // 手动触发一次移动事件,让事件过滤器重新调整位置 QEvent moveEvent(QEvent::Move); QApplication::sendEvent(container, &moveEvent); } }
这样改完之后,你再拖动dock变成浮动状态时,它就只能在主窗口的边界内移动了,完全符合你要的MDI风格锁定效果!
备注:内容来源于stack exchange,提问作者FSat
相关产品推荐
相关产品推荐

