首页/文章/ 详情

Qt桌面软件的多主题风格界面

5月前浏览1079

Qt 是全球最流行的跨平台 C++ 图形用户界面(GUI)应用程序开发框架之一。Qt 最强大的特性在于其跨平台能力。开发者编写一次代码,经过重新编译,即可在桌面端(Windows, macOS, Linux),移动端(iOS, Android),和嵌入式(QNX, VxWorks, 各种 RTOS)系统中运行。已经有大量的软件产品,尤其是大型工业软件,都是基于Qt的框架开发而成的。本文从实际开发的角度,讨论如何最优地实现Qt软件的多主题风格界面,尤其是暗色风格。

在开发大型 Qt 桌面程序(如 IDE、工业控制软件或生产力工具)时,界面(UI)不仅仅是“好看”,更关乎长时间操作的舒适度、信息层级的清晰度以及品牌专业感。因此现代大型可视化软件,都实现了多种界面风格,从色彩来区分,常见的有暗色和亮色主题两种风格。亮色通常是默认风格,而暗色风格需要开发人员专门增加相关的功能。虽然一个软件可以拥有无数个界面风格,但是从实用性角度,只需要两个风格:亮色和暗色。

实现方案

在 Qt 中实现多个主题风格,同时这些风格之间还可以动态切换,已经有一些成熟的方案。本文只讨论最常用的两种实现方式:源码和qss文件。

这两种主流方法细节如下:

1. 在C++或Python源代码中设置QStyle

这是最经典的做法。开发者直接在源码中定义不同主题,每个主题定义好颜色。然后通过setStyle和setPalette函数对QApplication进行设置主题即可。这种方法的好处是开发简单迅速,易于维护,开发者只需要和其他Qt代码一起管理风格。但是拓展性较弱,当用户想要自定义某种风格时,必须要有源代码才能实现。对于大型商业软件,尤其是工程类软件,用户很少会自定义界面风格,因此直接在源代码中设置QStyle是一个比较简单高效的方案。大型通用工程仿真软件WELSIM也选择了这种方式。

2. 通过QSS设置QStyleSheet

这是较为灵活且可扩展的做法。通过加载不同的 .qss 文件,配合变量替换(利用正则或 setProperty)实现。优点是与逻辑解耦,样式修改无需重新编译源码,最终用户也可以修改或添加qss文件来实现想要的风格。缺点是渲染性能在极复杂界面下略有损耗;维护与开发过程相对繁琐,需要熟悉qss文件的语法。

亮色vs暗色

亮色和暗色是开发多风格主题最主要的两个色系。浅色风格和操作系统的原生风格比较相似。因此,在开发多风格界面时,主要工作就是是增加暗色主题。这两种主题可以按照用户的需求随时切换,就好比车载大屏幕的地图系统,白天会显示亮色背景,而夜晚会以暗色背景显示。此外,深色 界面的桌面软件越来越多,主要是由于对于软件使用者的眼睛和视力保护较为友好,尤其是大型工程软件,用户会长时间的观看电脑屏幕,暗色 界面可以有效缓解用户眼睛的疲劳。

很多开发者误以为暗色模式就是简单的“反相”,其实不然。直接将白底黑字翻转为黑底白字会导致极高的对比度,产生“光晕效应”,导致视觉疲劳。这里给出合适的明暗两种风格的配色方案。

暗色主题 (Dark Theme)

  • 背景: 避免使用纯黑色(#000000),建议使用深灰色(如 #121212 或 #1E1E1E)。深灰色能通过阴影展现深度感。

  • 层级: 遵循“越靠前越亮”的原则。底层背景最暗,弹出窗口或浮动面板应稍微亮一点。

  • 文字: 避免纯白色文字(#FFFFFF),建议使用米白或浅灰(如 #E0E0E0),降低刺眼感。

亮色主题 (Light Theme)

  • 背景: 通常选择极浅的灰色(如 #F5F5F5)而非纯白,作为主背景色,将纯白留给编辑区或核心内容区。

  • 对比: 强调通过细腻的边框(Border)而非大面积阴影来区分模块。

  • 色彩平衡: 辅助色(如状态条、图标)应具备足够的饱和度,以免在强光下显得苍白。


值得一提的是,Qt自带的Fusion风格就是很好的主题,内含亮色和暗色两种主题,开发者可以直接以Fusion风格为模板进行开发。

图标

背景色改变后,之前的图标可能不太适用。如在浅色主题背景下设计的图标,在深色背景下就显得非常不明显。因此就需要对图标管理有一个很好的方式。Qt为多风格主题提供了图标的解决方案。常用的方式有三种。

1. 直接使用 QStyle 提供的标准图标,Fusion 风格下会自动适配明暗主题,这是最方便的方式,但是Qt自带的标准图标数量有限,可以满足小型软件的图标需求。对于大型软件,往往开发者还需要增加新的图标。

2. 使用SVG图片的动态变色功能,核心:将 SVG 图标内的固定颜色(如 fill="#000000")改为 fill="currentColor"。Qt 会自动将 currentColor 替换为控件的前景色(palette.color(QPalette::WindowText))。此方案只适用于单调颜色图标,当图标含有2种颜色以上时,难以实现理想颜色。

3. 使用双图标集,一套浅色,另一套深色。这是大型软件常用的方式,虽然需要建立并维护两套图标,但是方式简单,易于维护。且可以实现复杂且好看的图标集。也是WELSIM的亮暗两种风格的图标集方案。

在使用两套图标集时,判断应用当前的主题是否为深色,如果是深色就应用深色图标,反之则使用浅色图标。判断是否为深色主题的方法有多种,对于Qt6.5以上可以用如下方式:




bool isDark() {   return qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark}

动态加载图标的方式如下:





void updateIcon() {   QString path = isDark() ? ":/icons/icon_dark.svg" : ":/icons/icon_light.svg"  ui->button->setIcon(QIcon(path)); }

放置上述updateIcon()函数的位置常常是在信号槽接受函数changeEvent(QEvent *e)中。通过e->type() == QEvent::PaletteChange或e->type() == QEvent::StyleChange来捕捉系统的色彩主题变化。

OpenGL渲染窗口

在很多大型软件中,含有带OpenGL绘图的渲染窗口,此时Qt的默认对QWidget的配色主题,无法自动在OpenGL窗口展现。需要对渲染器进行手动的修改,同步色彩主题。需要对Renderer渲染器的背景色设置,与QWidget的背景色一致。同时对画布的背景和绘画颜色进行设置。

下图所示,前后两个图标在不同颜色下的表现。

以一个VTK实现的图表为例。在同步2维绘图区域时,需要设置Renderer的背景,表格的背景,轴线相关的颜色。最后需要更新渲染器来显示新的主题风格。

给出同步颜色主题的代码如下:



























void myWelSimChartPlot::syncVtkThemeWithQtDark(QWidget* qtWidget){    vtkRenderWindow* renderWindow = this->renderWindow();    vtkRendererCollection* renderers = renderWindow ? renderWindow->GetRenderers() : nullptr;    vtkRenderer* renderer = renderers ? renderers->GetFirstRenderer() : nullptr;    if (!qtWidget || !renderer || !renderWindow) return;    const QPalette palette = qtWidget->palette();    const QColor bgColor = palette.color(QPalette::Base);    const QColor fgColor = palette.color(QPalette::WindowText);    renderer->SetBackground(qColorToVtk(bgColor));    vtkColor4ub color;    color.Set(bgColor.red(), bgColor.green(), bgColor.blue(), bgColor.alpha());    this->chart()->GetBackgroundBrush()->SetColor(color);    int axisIDs[4] = { vtkAxis::BOTTOM, vtkAxis::TOP, vtkAxis::LEFT, vtkAxis::RIGHT };    for (unsigned int axisIndex = 0; axisIndex < 4; ++axisIndex)    {        int axisID = axisIDs[axisIndex];        vtkAxis* axis = this->chart()->GetAxis(axisID);        if (!axis) { assert(0); continue; }        axis->GetTitleProperties()->SetColor(qColorToVtk(fgColor));        axis->GetLabelProperties()->SetColor(qColorToVtk(fgColor));        axis->GetGridPen()->SetColorF(qColorToVtk(borderColor));        axis->GetPen()->SetColorF(qColorToVtk(fgColor));    }    renderWindow->Render();}

除了二维绘图窗口,OpenGL驱动的三维窗口也可以做相应色彩主题设置。但实际的产品设计中,往往不需要,因为三维窗口会提供其他配色。如图所示,WELSIM的3D渲染窗口支持蓝白渐变,黑色,白色三种背景。用户可以根据需要自行设置3D OpenGL渲染窗口的风格颜色。

总结

现在,一款成熟的大型工程软件,支持多风格主题已经成为一个必备功能。至少具有亮色与暗色两个风格主题。而核心就是实现暗色主题。虽然技术难度不大,但是有大量且琐碎的开发与测试工作,需要一定的开发时间,以及长期的优化与维护。如果已有的代码中有一些局部的修改样式代码,如setStyle, setStyleSheet函数,还需要做相应修改,从易于维护的角度,最好是删除那些局部风格代码。统一由全局风格来管理整个软件的界面。


WelSim与作者不隶属于Qt, 和Qt开发团队与机构没有直接关系。这里引用这些开源软件的名称和图片仅用作技术博客文章与软件使用的参考。 



来源:WELSIM
疲劳通用WELSIMpython控制渲染
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2026-03-25
最近编辑:5月前
WELSIM
一枚搞仿真的老员工
获赞 27粉丝 87文章 271课程 0
点赞
收藏
作者推荐

使用WELSIM生成复杂几何模型的粒子

随着现代工程仿真的发展,粒子仿真也越来越多的被工业届接受。粒子相关的计算和软件在各个工程和科学领域都有出现。除了单纯的粒子计算,如分子动力学计算,还有与有限元等连续介质计算方法耦合,实现更为精巧的计算。如SPH方法计算流体和沙石颗粒的运动。随之,人们对粒子计算的要求也不断提高。而生成粒子是所有计算的第一步,也是整个计算的关键一环。因此,生成粒子的算法和实现过程,就显得尤为重要了。作者曾讨论过生成粒子的数值方法,参见《自动化生成仿真粒子的方法》一文。生成简单几何模型,如立方体,的粒子并不难,但是当粒子区域轮廓变得复杂时,生成粒子就变得困难了。目前市场可以生成任意轮廓粒子的软件并不多,WELSIM已经可以很好的实现这点,并输出为外部文件,用于其他软件的计算。本文就如何在WELSIM下生成粒子,做一个简要介绍。1. 打开WELSIM软件,并导入一个STEP几何模型。这里导入一个带有圆孔的圆柱体。并将几何体的创建粒子(Create Particles)属性设为真。2. 点击网格划分按钮,便可自动生成粒子。此设置下,生成了441个粒子。3. 如果想得到密度更高的粒子,可以修改网格设置属性中的最大单元尺寸(Maximum Size)值。当把值改为0.01时,粒子的密度会增加。4. 粒子数量增加后,为了显示更为清楚,可以调整粒子显示大小。点击网格节点的三维视图(3D View),设置粒子尺寸(Particle Size)值即可,这里设为0.001。此时,可以看到生成了更多的粒子,数量达到16,060。因此,使用WELSIM可以方便快捷地生成任意密度的粒子。5. 粒子生成工作已经完成。下一步来导出粒子文件。右键点击Mesh节点,从弹出菜单中选择导出粒子(Export Particles)。6. 在导出对话框中,输入文件名称和类型。目前已经支持了VTK PolyData格式,以后版本中,会增加更多的导出格式。导出文件可以被其他软件读取并使用。如图所示,使用ParaView读取此文件的显示结果。总结本文介绍了如何使用WELSIM生成粒子的方法步骤。用户只需导入STEP格式的几何体,通过类似自动化网格划分的方式,快速得到各种不同密度的粒子。本文中使用的几何模型较为简单,复杂的几何体也可以同样的方式得到粒子。同时,提供了粒子数据导出功能,用户可以将生成的粒子用于其他软件的计算。粒子生成功能已经存在2025R3版中,会在后续的版本中不断增强和改进。WelSim与作者和ParaView开发者没有直接关系。这里引用ParaView仅用作技术博客文章与软件使用的参考。 官网:https://welsim.comQQ群:913069921 求关注,请长按二维码来源:WELSIM

未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈