如何在Qt C++中实现类似Blender的叠加式小部件
如何在Qt C++中实现类似Blender的叠加式小部件
嘿,我完全懂你想要的效果——就像Blender里那种悬浮在视图上方、不占用场景显示空间的工具栏对吧?其实在Qt里实现这个并不复杂,我给你分享两种靠谱的方案,你可以根据需求选:
方案一:直接将工具栏作为QGraphicsView的子控件(推荐)
这种方式能让工具栏固定在视图的某个位置,完全叠加在场景视图上方,不会影响场景的显示和操作,最贴近Blender的效果。
具体步骤和代码示例:
- 自定义你的
QGraphicsView子类,在构造函数里创建工具栏并设置初始位置:
#include <QGraphicsView> #include <QToolBar> #include <QResizeEvent> class MyGraphicsView : public QGraphicsView { Q_OBJECT public: MyGraphicsView(QWidget *parent = nullptr) : QGraphicsView(parent) { // 创建工具栏并添加操作按钮 QToolBar* overlayToolBar = new QToolBar(this); overlayToolBar->addAction("自由画笔"); overlayToolBar->addAction("矩形工具"); overlayToolBar->addAction("圆形工具"); // 给工具栏设置半透明样式,更贴近Blender的风格 overlayToolBar->setStyleSheet(R"( QToolBar { background-color: rgba(40, 40, 40, 0.8); border-radius: 4px; padding: 4px; } QToolButton { color: white; border: none; padding: 6px; } QToolButton:hover { background-color: rgba(60, 60, 60, 0.9); border-radius: 3px; } )"); // 设置初始位置:左上角偏移20像素 overlayToolBar->move(20, 20); // 禁止工具栏浮动和移动,固定在当前位置 overlayToolBar->setFloatable(false); overlayToolBar->setMovable(false); // 确保工具栏在视图的viewport上方(避免被场景遮挡) overlayToolBar->raise(); } protected: // 重写resizeEvent,窗口大小变化时保持工具栏位置不变 void resizeEvent(QResizeEvent *event) override { QGraphicsView::resizeEvent(event); // 找到我们创建的工具栏(如果保存指针的话更高效,这里用findChild示例) QToolBar* toolBar = findChild<QToolBar*>(); if (toolBar) { toolBar->move(20, 20); } } };
为什么推荐这个方案?
- 工具栏完全独立于场景,不会随场景的缩放、平移而移动或变形
- 不占用场景的显示空间,用户操作场景时不会被工具栏挤压视图
- 样式自定义自由度高,很容易调出Blender那种深色半透明的质感
方案二:用QGraphicsProxyWidget嵌入场景(适合需要随场景联动的情况)
如果你希望工具栏能跟着场景一起缩放、平移(比如某些特殊绘图场景),可以把工具栏包装成QGraphicsProxyWidget加入到QGraphicsScene中:
// 在你的场景初始化代码里 QToolBar* toolBar = new QToolBar(); toolBar->addAction("画笔"); toolBar->addAction("矩形"); QGraphicsProxyWidget* proxyWidget = scene->addWidget(toolBar); // 设置初始位置:对应视图左上角偏移20像素(这里要注意坐标转换) proxyWidget->setPos(mapToScene(20, 20)); // 禁止代理部件随场景缩放而变形 proxyWidget->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
不过这个方案的缺点是,工具栏会成为场景的一部分,如果你不需要和场景联动,还是方案一更合适。
最后提个小技巧:如果工具栏遮挡了场景的操作区域,你可以给工具栏设置setAttribute(Qt::WA_TransparentForMouseEvents, true),但这样工具栏就接收不到点击事件了,所以只适合纯展示的叠加部件。
备注:内容来源于stack exchange,提问作者bbdd
相关产品推荐
相关产品推荐

