一个 QGraphicsDropShadowEffect 实例只能作为一个控件当前安装的图形效果。把同一个效果先交给 filemanager_memeryArea、再交给 workspaceWidget,第二次调用会把效果从前一个控件移走。要让两个区域同时显示阴影,应创建两个实例,并复用创建和配置它们的函数。
本文使用 Qt 6 Widgets、C++17。原例的参数是偏移 (5, 5)、颜色 QColor(43, 43, 43)、模糊半径 8;下面完整保留这些值和两个区域名称。
安装效果会转移所有权
跳转到“安装效果会转移所有权”QWidget::setGraphicsEffect() 有三个需要一起理解的行为:控件接管效果;从其他控件传入同一效果时会迁移效果;给已有不同效果的控件安装新效果时,会删除旧效果。不能继续使用指向被替换效果的普通指针。setGraphicsEffect
工厂每次 new 一个效果,返回供本次安装使用的独立对象。这减少了重复配置代码,但不会把多个控件的绘制成本合并成一次,也不是已经测得的性能优化。不要让工厂缓存一个共享效果实例。
#include <QApplication>#include <QColor>#include <QFrame>#include <QGraphicsDropShadowEffect>#include <QHBoxLayout>#include <QLabel>#include <QVBoxLayout>#include <QWidget>
QGraphicsDropShadowEffect* createShadowEffect() { auto* shadow = new QGraphicsDropShadowEffect; shadow->setOffset(5, 5); shadow->setColor(QColor(43, 43, 43)); shadow->setBlurRadius(8); return shadow;}
class ShadowWindow : public QWidget {public: explicit ShadowWindow(QWidget* parent = nullptr) : QWidget(parent) { auto* layout = new QHBoxLayout(this); layout->setContentsMargins(24, 24, 24, 24); layout->setSpacing(24); filemanager_memeryArea = createPanel("Memory area", this); filemanager_memeryArea->setObjectName("filemanager_memeryArea"); workspaceWidget = createPanel("Workspace", this); workspaceWidget->setObjectName("workspaceWidget"); layout->addWidget(filemanager_memeryArea); layout->addWidget(workspaceWidget); filemanager_memeryArea->setGraphicsEffect(createShadowEffect()); workspaceWidget->setGraphicsEffect(createShadowEffect()); }
QFrame* filemanager_memeryArea; QFrame* workspaceWidget;
private: static QFrame* createPanel(const QString& text, QWidget* parent) { auto* panel = new QFrame(parent); panel->setMinimumSize(160, 100); panel->setStyleSheet("QFrame { background: white; border: 1px solid #999; }"); auto* layout = new QVBoxLayout(panel); auto* label = new QLabel(text, panel); label->setAlignment(Qt::AlignCenter); label->setStyleSheet("border: none; background: transparent;"); layout->addWidget(label); return panel; }};
int main(int argc, char* argv[]) { QApplication app(argc, argv); ShadowWindow window; window.setWindowTitle("Independent widget shadows"); window.resize(460, 180); window.show(); return app.exec();}cmake_minimum_required(VERSION 3.16)project(widget_shadows LANGUAGES CXX)set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)set(CMAKE_CXX_EXTENSIONS OFF)find_package(Qt6 REQUIRED COMPONENTS Widgets)add_executable(shadow-example main.cpp)target_link_libraries(shadow-example PRIVATE Qt6::Widgets)保存两个文件到同一目录后构建运行,会显示两个分别带阴影的区域。效果创建时暂不指定 QObject 父对象,随即交给目标控件接管,避免把“创建它的窗口”和“安装它的控件”混为同一份释放责任。父窗口销毁两个区域时,已安装的效果也会释放。
效果范围和显示边界
跳转到“效果范围和显示边界”控件的图形效果作用于它自身以及子控件的合成结果。给整个容器加阴影,与分别给每个子控件加阴影,得到的形状不同。如果需要多种效果,单个控件的 setGraphicsEffect() 也不是一个可以反复追加的效果列表。
阴影会扩展到控件本体外侧,布局不会自动为全部阴影预留空间。示例用内容边距和间距留出绘制余量;嵌入狭窄容器、滚动视口或截图时,还要检查裁剪边界。模糊半径和面积越大,通常需要更多绘制工作,具体性能应在目标环境测量。QGraphicsDropShadowEffect
该机制有平台与渲染路径边界,官方文档明确列出 QOpenGLWidget、QQuickWidget 等控件不支持这种 Widgets 图形效果,不应靠给这些控件重复安装效果解决问题。普通背景和边框样式见QSS 自定义背景。