Files
BudgetPro/gui/SARibbon/readme-cn.md
T
2026-05-24 23:21:33 +02:00

788 lines
39 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[Click here for English](./readme.md)
<div align="center">
<p>
<img src="https://img.shields.io/badge/C++-17-blue"/>
<img src="https://img.shields.io/badge/Qt-5.14+-green"/>
<img src="https://img.shields.io/badge/Qt-6-green"/>
<img src="https://img.shields.io/badge/license-MIT-yellow"/>
</p>
<p>
<img src="https://img.shields.io/badge/windows-0077d6"/>
<img src="https://img.shields.io/badge/ubuntu-ed6432"/>
<img src="https://img.shields.io/badge/macos-000"/>
</p>
</div>
QQ交流群:434014314
<div align="center">
<img src="./doc/SARibbon-qq%E4%BA%A4%E6%B5%81%E7%BE%A4.jpg"/>
</div>
||Windows(2019, latest)|Linux ubuntu(20.04, latest)|Mac(11-latest)|
|:-|:-|:-|:-|
|Qt5.12|[![cmake-win-qt5.12](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt5.12.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt5.12.yml)|[![CMake-Linux-Qt5.12](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt5.12.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt5.12.yml)|[![cmake-mac-qt5.12](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt5.12.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt5.12.yml)|
|Qt5.13|[![cmake-win-qt5.13](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt5.13.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt5.13.yml)|[![CMake-Linux-Qt5.13](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt5.13.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt5.13.yml)|[![cmake-mac-qt5.13](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt5.13.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt5.13.yml)|
|Qt5.14|[![cmake-win-qt5.14](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt5.14.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt5.14.yml)|[![CMake-Linux-Qt5.14](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt5.14.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt5.14.yml)|[![cmake-mac-qt5.14](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt5.14.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt5.14.yml)|
|Qt5.15|[![cmake-win-qt5.15](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt5.15.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt5.15.yml)|[![CMake-Linux-Qt5.15](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt5.15.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt5.15.yml)|[![cmake-mac-qt5.15](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt5.15.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt5.15.yml)|
|Qt6.0|[![cmake-win-qt6.0](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.0.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.0.yml)|[![CMake-Linux-Qt6.0](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.0.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.0.yml)|[![cmake-mac-qt6.0](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.0.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.0.yml)|
|Qt6.1|[![cmake-win-qt6.1](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.1.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.1.yml)|[![CMake-Linux-Qt6.1](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.1.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.1.yml)|[![cmake-mac-qt6.1](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.1.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.1.yml)|
|Qt6.2|[![cmake-win-qt6.2](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.2.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.2.yml)|[![CMake-Linux-Qt6.2](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.2.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.2.yml)|[![cmake-mac-qt6.2](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.2.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.2.yml)|
|Qt6.3|[![cmake-win-qt6.3](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.3.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.3.yml)|[![CMake-Linux-Qt6.3](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.3.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.3.yml)|[![cmake-mac-qt6.3](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.3.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.3.yml)|
|Qt6.4|[![cmake-win-qt6.4](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.4.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.4.yml)|[![CMake-Linux-Qt6.4](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.4.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.4.yml)|[![cmake-mac-qt6.4](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.4.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.4.yml)|
|Qt6.5|[![cmake-win-qt6.5](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.5.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.5.yml)|[![CMake-Linux-Qt6.5](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.5.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.5.yml)|[![cmake-mac-qt6.5](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.5.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.5.yml)|
|Qt6.6|[![cmake-win-qt6.6](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.6.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.6.yml)|[![CMake-Linux-Qt6.6](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.6.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.6.yml)|[![cmake-mac-qt6.6](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.6.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.6.yml)|
# SARibbon简介
这是一个`Qt`下的`Ribbon`界面控件,提供了类似微软Office系列软件的操作界面。
- `SARibbon`适用于大型软件、工业软件、复杂软件的ui
- `SARibbon`在设计时参考了MFC Ribbon接口的命名风格
- `SARibbon`的界面样式参考了微软Office系列软件以及WPS软件的Ribbon界面,并结合了两者的优点
- `SARibbon`是一个可定义多种主题风格的Ribbon控件,它能通过qss快速的定义出自己想要的主题风格
为了方便大型软件的开发,`SARibbon`对常用的一些功能性控件进行了封装,例如:[颜色选择按钮和颜色选择画板](https://github.com/czyt1988/SAColorWidgets)
## 功能特点
- 针对Ribbon的布局和显示
![Ribbon的布局和显示](./doc/screenshot/SARibbonBar-overview.gif)
- 支持最小化模式,ribbon只显示标签(默认双击标签会进行切换),支持上下文标签tab
![SARibbon最小化模式](./doc/screenshot/SARibbonBar-minMode.gif)
- 支持quickAccessBar(word快速菜单),在不同布局模式下会有不同的显示效果
![SARibbon-quickAccessBar](./doc/screenshot/SARibbonBar-quickAccessBar.gif)
- 支持4种不同的ribbon button,普通按钮,延迟弹出菜单按钮,菜单按钮,action菜单按钮(action菜单按钮是此ribbon控件最主要解决的问题之一)
![SARibbon-4种不同的ribbon button](./doc/screenshot/SARibbonBar-ribbonbutton.gif)
- 支持4种不同风格的布局样式
![SARibbon-4种不同风格的布局样式](./doc/screenshot/SARibbonBar-style.gif)
- 支持qss对ribbon进行自定义设置,可实时切换主题,内置了5种不同风格的主题
win7主题:
![SARibbon-theme-win7](./doc/screenshot/SARibbon-theme-win7.png)
office2013主题:
![SARibbon-theme-office2013](./doc/screenshot/SARibbon-theme-office2013.png)
office2016主题:
![SARibbon-theme-office2016](./doc/screenshot/SARibbon-theme-office2016.png)
office2021主题:
![SARibbon-theme-office2021](./doc/screenshot/SARibbon-theme-office2021.png)
dark主题:
![SARibbon-theme-dark](./doc/screenshot/SARibbon-theme-dark.png)
- 提供Gallery控件
![](./doc/screenshot/SARibbonBar-gallery.gif)
- 支持超长滚动和Option Action
![](./doc/screenshot/SARibbonBar-option-action.gif)
- 提供居中对齐模式
![](./doc/screenshot/SARibbon-aligment-center.png)
- 支持4K屏和多屏幕扩展
- 支持linux和MacOS(界面未做深度适配)
MIT协议,欢迎大家使用并提出意见
[gitee(码云) - https://gitee.com/czyt1988/SARibbon](https://gitee.com/czyt1988/SARibbon)
[github - https://github.com/czyt1988/SARibbon](https://github.com/czyt1988/SARibbon)
# 构建
这里建议使用cmake进行构建,cmake构建完成后并进行安装(install),使用cmake构建,你的工程既可以用cmake引入SARibbonBar,也可以使用qmake引入SARibbonBar
SARibbon提供qmake和cmake两种构建方式,同时提供了一个集成的SARibbon.h和SARibbon.cpp文件方便静态的嵌入到单一工程
> SARibbon支持第三方无边框库[QWindowkit](https://github.com/stdware/qwindowkit),同时也支持简单的无边框方案,如果你需要操作系统原生的窗口支持,如windows7以后的贴边处理,windows11的最大化按钮悬停的效果,建议开启[QWindowkit](https://github.com/stdware/qwindowkit)库,[QWindowkit](https://github.com/stdware/qwindowkit)库还能较好解决多屏幕移动问题
开启`QWindowkit`后的效果如下:
![](./doc/pic/set-qwindowkit-on-snap.gif)
如果你要依赖[QWindowkit](https://github.com/stdware/qwindowkit)库,需要先编译[QWindowkit](https://github.com/stdware/qwindowkit)库,[QWindowkit](https://github.com/stdware/qwindowkit)库作为SARibbon项目的submodules,如果在`git clone`时没有附带`--recursive`参数,需要执行`submodule update`命令:
```shell
git submodule update --init --recursive
```
> 用户指定使用[QWindowkit](https://github.com/stdware/qwindowkit)后,要求C++标准最低为C++17否则最低要求为c++14
## 编译为动态库
具体构建过程,见文档:[SARibbon构建](./doc/how-to-build-cn.md)
## 直接引入工程(静态)
你可以不对SARibbon库进行构建,直接引入,通过cmake构建安装后,也提供静态文件引入的内容
SARibbon提供了合并好的`SARibbon.h`文件和`SARibbon.cpp`文件,只需要在自己的工程中引入这两个文件,同时把资源文件和第三方库文件引入就可以使用,无需编译为动态库或者静态库,可以参考StaticExample例子(位于`example/StaticExample`),静态嵌入将使用到`SARibbon.h``SARibbon.cpp``SARibbon.pri``SARibbonBar/resource.qrc`这4个文件,以及`SARibbonBar/resource`这个文件夹:
你的工程目录将如下所示:
```
|-you-project-dir
| |-you-project.pro
| |-SARibbon.h
| |-SARibbon.cpp
| |-SARibbon.pri
| |-SARibbonBar
| |-resource.qrc
| |-resource(直接把SARibbonBar下的resource完整复制过来)
| |-resource files
```
### 使用qmake
使用qmake编译,有如下步骤:
- 1. 把`SARibbon.h``SARibbon.cpp``SARibbon.pri`拷贝到自己工程目录下
- 2. 在自己工程目录下创建`SARibbonBar`文件夹
- 3. 把源码中的`src/SARibbonBar/resource.qrc`文件拷贝到自己工程目录下的`SARibbonBar`文件夹
- 4. 把源码`src/SARibbonBar`下的`resource`文件夹和`3rdparty`文件夹拷贝到自己工程目录下的`SARibbonBar`文件夹中
- 5. 在自己工程的pro文件中引入`SARibbon.pri`文件,如:`include($$PWD/SARibbon.pri)`
qmake可以通过`SARibbon.pri`文件设置是否开启第三方无边框库
### 使用cmake
使用cmake的话参考StaticExample(位于`example/StaticExample`)例子的cmake编写方式编写,主要把上诉的几个文件引入工程即可
```cmake
SET(SARIBBON_DIR {SARibbon.h和SARibbon.cpp所在目录})
set(SARIBBON_STATIC_FILE
${SARIBBON_DIR}/SARibbon.h
${SARIBBON_DIR}/SARibbon.cpp
${SARIBBON_DIR}/SARibbonBar/resource.qrc
)
add_executable({you-target}
{你项目的cpp和头文件}
${SARIBBON_STATIC_FILE}
)
```
基于cmake在静态引入方案中,如果你需要使用`QWindowkit`,你的工程首先要添加好`QWindowkit`库,并且增加预定义宏:
```cmake
find_package(QWindowKit)
target_link_libraries({you-target} PRIVATE QWindowKit::Widgets)
target_compile_definitions({you-target} PRIVATE SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=1)
```
否则你需要把它设置为0
```cmake
target_compile_definitions({you-target} PRIVATE SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=0)
```
# 使用方法
## 引入库
在编译完成后,按照如下方法引入SARibbon
### qmake(不推荐)
就算你的工程使用的是qmake,但构建过程还是建议使用cmake,并通过install命令,形成标准的库安装,通过cmake安装的SARibbon,也可以通过qmake引入
#### 通过qmake构建的引入
如果你的SARibbon是通过qmake构建,那么会在SARibbon目录下生成`bin_qt{Qt version}_{MSVC/GNU}_x{32/64}`文件夹,简单的引入,你只需把如下文件按目录结构拷贝到你的工程中
先在你的工程中建立一个3rdparty文件夹,再把整个SARibbon文件夹拷贝过去,SARibbon内部已经有几个pri文件可以很方便的让你把工程引入到自己目录中,`./importSARibbonBarLib.pri`文件是用于引入SARibbon库的
在自己的Qt工程pro文件中加入如下语句即可
```shell
include($$PWD/3rdparty/SARibbon/importSARibbonBarLib.pri)
```
qmake的编译过程会在SARibbon下生成`bin_qt{Qt version}_{MSVC/GNU}_x{32/64}`文件夹,库文件和dll文件都在此文件夹下,importSARibbonBarLib.pri会自动把这个文件夹下的库引用进来
此时你的工程目录结构大致如下:
```
|-[you-project-dir]
| |-you-project.pro
| |-[3rdparty]
| |-[SARibbon](直接把SARibbon完整复制过来)
| |-importSARibbonBarLib.pri
| |-SARibbonBar.pri
| |-common.pri
| |-[bin_qtx.x.x_{MSVC/GNU}_x{32/64}]
| |-[src]
| | |-[SARibbonBar]
```
几个pri文件的说明:
- common.pri
qmake配置文件,里面定义配置信息,在编译库的时候可以通过此文件改动配置,引入的时候要和编译的时候配置一致
- importSARibbonBarLib.pri
用于引入库,实际就是include(SARibbonBar.pri)
- SARibbonBar.pri
用于引入库的具体实现
- src/SARibbon.pri
针对SARibbon.h和SARibbon.cpp的pri文件,如果你用静态集成模式,使用此pri文件
---
你自己可以把所有头文件复制到一个文件夹,并引入SARibbon库,具体操作和引入其它库方式一致,但这里需要注意的是,你如果自己引入,需要指定一下以下几个宏:
- SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
这个宏指定你是否使用第三方无边框库`QWindowkit`,如果编译时,使用了`QWindowkit`,那么,需要定义SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=1,否则为0,在你的pro文件中,你可以这样写:
```shell
# 编译使用了QWindowkit
DEFINES += SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=1
# 编译没有使用QWindowkit
DEFINES += SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=1
```
#### 通过cmake构建的引入
就算你的项目使用qmake管理,也建议SARibbon的构建使用cmake构建并进行安装,因为cmake构建并进行安装后,也提供了qmake的引入方案,位于安装位置的`lib/qmake/SARibbonBar`目录下,你仅仅需要在你pro文件中加入如下语句即可引入:
```shell
include({SARibbon安装目录}/lib/qmake/SARibbonBar/SARibbonBar.pri)
```
### cmake(推荐)
建议在执行install后使用此库
cmake引入方法:
```cmake
find_package(SARibbonBar REQUIRED)
...
target_link_libraries({your_target_name} PUBLIC SARibbonBar::SARibbonBar)
```
如果find_package找不到`SARibbonBar`,你需要把`SARibbon`安装位置告诉cmake工程
```
set(SARibbonBar_DIR "[你的SARibbonBar安装根目录]/lib/cmake")
```
如果你编译时,`SARIBBON_INSTALL_IN_CURRENT_DIR`选项设置为`ON`(默认),那会在SARibbon工程根目录下下生成`bin_qt{Qt version}_{MSVC/GNU}_x{32/64}`文件夹作为安装目录,这是为了和qmake统一,也是为了方便一个操作系统进行多个不同版本qt和编译器进行区分安装,否则,windows系统会默认安装在`C:\Program Files\SARibbonBar`文件夹下
通过cmake引入SARibbon可参考`example/MainWindowExample/CMakeLists.txt`
具体见文档:[SARibbon构建](./doc/how-to-build-cn.md)
## 快速开始
Ribbon是把菜单栏和工具栏合并了,并通过一个tab控件进行展示,Ribbon是无法简单的使用Tab+Toolbar替代的,涉及到很多细节问题,`SARibbon`在设计时参考了MFC Ribbon接口的命名风格,标签页称之为`Category`(种类),每个`Category`下面有多个`pannel`(面板),面板下面管理着toolbutton,`pannel`有点类似传统的`Toolbar`,其层次结构如下图所示,这些命名参考了MFC的ribbon界面类
![msdn ribbon 介绍页](./doc/pic/msdn-ribbon.png)
一些常见的名词解释如下
- **Category 类别**,代表一个标签所呈现的内容,对应`SARibbonCategory`
- **Context Category 上下文类别**,这个是一种特殊的类别,它正常不显示,需要基于上下文判断是否应该显示,最常用的就是word中插入图片后,会有图片修改相关的标签出现,如果没选中图片,这个标签就消失,这个就是上下文类别,对应`SARibbonContextCategory`
- **Pannel 面板**,这个是一组菜单的集合,类似一个Toolbar,对应`SARibbonPannel`
- **Application Button 应用按钮**,标签栏最左边的按钮(word就是对应文件按钮),这个按钮会触发一些特殊的页面或菜单,对应`SARibbonApplicationButton`,可以隐藏
- **Quick Access Bar 快速响应栏**,位于最顶部的一个简单工具栏,用于放置一些常用的action,对应`SARibbonQuickAccessBar`
- **Gallery 预览控件**,这是Ribbon最吸引眼球的控件,用直观的图像把功能显示出来,甚至有些会根据上下文进行实时渲染,典型的就是word开始标签下的样式选择,对应`SARibbonGallery`
SARibbonBar的层次如下图所示:
![](./doc/pic/saribbonbar-level.png)
> 注:不同的布局方案影响着`Category`和`Quick Access Bar`的摆放方式,具体可见[SARibbonBar布局方案](#SARibbonBar布局方案)
### 在MainWindow中使用Ribbon
要MainWindow中使用SARibbon,需要把`QMainWindow`替换为`SARibbonMainWindow``SARibbonMainWindow`修改了`QMainWindow`对menubar的渲染方式
> 注意,如果使用ui文件,要把原来ui文件的菜单删除,否则可能引起一些异常,如下图所示:
> ![](./doc/pic/remove-menu-bar-at-uifile.png)
示例代码如下:
```cpp
#include "SARibbonMainWindow.h"
class MainWindow : public SARibbonMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* par = nullptr);
...
}
```
`SARibbonMainWindow`也支持普通模式的渲染,SARibbonMainWindow的构造函数第二个参数用于设定是否用ribbon模式:
```cpp
SARibbonMainWindow(QWidget *parent = nullptr, bool useRibbon = true);
```
第二个参数如果设置为false,将会使用普通的菜单工具栏模式,预留这个接口是为了一些项目需要能在ribbon和经典菜单工具栏切换的场景设计的,Ribbon状态和经典状态不支持热切换,如果需要切换,用户可以设置一个配置文件或者注册表,在应用重启时给第二个参数传入false即可进入到经典菜单工具栏模式
### 在QWidget或QDialog中使用SARibbonBar
SARibbonBar支持在QWidget或者QDialog上使用,具体可见例子:`example/WidgetWithRibbon`
项目提供了`SARibbonWidget`类,widget窗口继承`SARibbonWidget`即可实现ribbon效果的窗口
```cpp
#include "SARibbonWidget.h"
class RibbonWidget : public SARibbonWidget
{
Q_OBJECT
public:
RibbonWidget(QWidget* parent = nullptr);
};
```
`SARibbonWidget`类提供了`setWidget`方法,可以嵌入任意的widget
```cpp
RibbonWidget::RibbonWidget(QWidget* parent) : SARibbonWidget(parent)
{
// 直接创建SARibbonBar
SARibbonBar* ribbonbar = ribbonBar();
// QWidget模式下,没有必要再显示标题
ribbonbar->setTitleVisible(false);
// QWidget模式下,直接使用紧凑模式效果更好
ribbonbar->setRibbonStyle(SARibbonBar::RibbonStyleCompactThreeRow);
// 取消applicationbutton
ribbonbar->setApplicationButton(nullptr);
//
//buildRibbon(ribbonbar);
//
setWidget(new InnerWidget());
}
```
效果如下:
![Ribbon用在QWidget上](./doc/screenshot/ribbonbar-use-in-qwidget.png)
### 创建Category和Pannel
创建ribbon的顺序是:先创建类别(Category),再创建面板(Pannel),最后创建对应的toolbuttonaction
使用`SARibbonBar::addCategoryPage`把Category添加到SARibbonBar中,使用`SARibbonCategory::addPannel``Pannel`添加到`Category`中,使用`SARibbonPannel::addAction`可以在Pannel上添加action
下面的代码,演示了添加一个action的示例:
```cpp
//添加主标签页 - 通过addCategoryPage工厂函数添加
SARibbonCategory* categoryMain = ribbon->addCategoryPage(tr("Main"));
//使用addPannel函数来创建SARibbonPannel,效果和new SARibbonPannel再addPannel一样
SARibbonPannel* pannel1 = categoryMain->addPannel("Panel 1");
QAction* actSave = new QAction(this);
actSave->setText("save");
actSave->setIcon(QIcon(":/icon/icon/save.svg"));
actSave->setObjectName("actSave");
actSave->setShortcut(QKeySequence(QLatin1String("Ctrl+S")));
pannel1->addLargeAction(actSave);
```
上面的操作添加了一个按钮,效果如下图所示:
![](./doc/pic/add-large-action.png)
用户也可以直接new出SARibbonCategory,并添加到pannel中,下面的代码效果和上面的一样:
```cpp
SARibbonCategory* categoryMain = new SARibbonCategory(tr("Main"));
ribbon->addCategoryPage(categoryMain);
SARibbonPannel* pannel1 = new SARibbonPannel("Panel 1");
categoryMain->addPannel(pannel1);
QAction* actSave = new QAction(this);
...
pannel1->addLargeAction(actSave);
```
Ribbon的图标有大有小,通过`addLargeAction``addMediumAction``addSmallAction`可以组合出不同的布局样式
具体可见[./example/MainWindowExample/mainwindow.cpp](./example/MainWindowExample/mainwindow.cpp)
### ContextCategory 上下文标签
所谓上下文标签是指在特殊情况下才出现的标签/标签组,例如office word在选中图片时会出现图片编辑的上下文标签,如下图所示:
![上下文标签](doc/pic/word-contextcategory.png)
SARibbon中上下文标签对应的类为`SARibbonContextCategory`
上下文标签一般在程序初始化的时候就创建好,平时隐藏,等待需要显示的时候再显示,创建上下文标签如下:
由于上下文标签需要使用时唤起,因此,用一个成员变量保存起来是一个比较好的选择,当然也可以遍历查找(`SARibbonBar::contextCategoryList`可以例举所有的`SARibbonContextCategory`
头文件:
```cpp
SARibbonContextCategory* m_contextCategory;
```
cpp文件:
```cpp
SARibbonBar* ribbon = ribbonBar();
//创建一个contextCategory,颜色随机
m_contextCategory = ribbon->addContextCategory(tr("context"), QColor());
SARibbonCategory* contextCategoryPage1 = m_contextCategory->addCategoryPage(tr("Page1"));
//对contextCategoryPage1进行操作
......
SARibbonCategory* contextCategoryPage2 = m_contextCategory->addCategoryPage(tr("Page2"));
//对contextCategoryPage2进行操作
......
```
`SARibbonContextCategory`创建的`SARibbonCategory``SARibbonContextCategory`管理,只有`SARibbonContextCategory`“显示了”,其管理的`SARibbonCategory`才显示,**注意:** `SARibbonContextCategory`并不是一个窗口,所以,它的“显示”打了引号
要显示一个上下文只需要调用`SARibbonBar::showContextCategory`/`SARibbonBar::hideContextCategory`即可:
```cpp
void MainWindow::onShowContextCategory(bool on)
{
if (on) {
this->ribbonBar()->showContextCategory(m_contextCategory);
} else {
this->ribbonBar()->hideContextCategory(m_contextCategory);
}
}
```
**注意:** 如果要删除`contextCategory`需要调用`SARibbonBar::destroyContextCategory`,而不是直接delete,调用`SARibbonBar::destroyContextCategory`之后无需再对ContextCategory的指针delete
不同样式的contextCategory有不一样的风格,具体可见:[SARibbon样式](#SARibbon样式)以及[不同样式下的显示对比](#不同样式下的显示对比)
### ApplicationButton
ribbon界面左上角有个特殊且明显的按钮,称之为`applicationButton`,这个按钮一般用于调出菜单,SARibbonBar在构造时默认就创建了`applicationButton`,可以通过如下方式设置其文字:
```cpp
SARibbonBar* ribbon = ribbonBar();
ribbon->applicationButton()->setText(("File"));
```
默认的applicationButton继承自`SARibbonApplicationButton`,而`SARibbonApplicationButton`继承自`QPushButton`,因此你可以对其进行`QPushButton`所有的操作,当然如果想设置自己的Button作为applicationButton也是可以的,只需要调用`SARibbonBar::setApplicationButton`函数即可
### QuickAccessBar和rightButtonGroup
QuickAccessBar是左上角的快速工具栏,rightButtonGroup是右上角的快速工具栏,在office模式下分左右两边,在wps模式下,左右将合起来,统一放到右边
![QuickAccessBar And RightButtonGroup](./doc/screenshot/QuickAccessBarAndRightButtonGroup.png)
SARibbon中:
- QuickAccessBar对应`SARibbonQuickAccessBar`
- rightButtonGroup对应`SARibbonButtonGroupWidget`
SARibbonBar在初始化时会默认创建QuickAccessBar和RightButtonGroup,通过`SARibbonBar::quickAccessBar``SARibbonBar::rightButtonGroup`即可获取其指针进行操作,示例如下:
```cpp
QAction* MainWindow::createAction(const QString& text, const QString& iconurl, const QString& objName)
{
QAction* act = new QAction(this);
act->setText(text);
act->setIcon(QIcon(iconurl));
act->setObjectName(objName);
return act;
}
void MainWindow::initQuickAccessBar(){
SARibbonBar* ribbon = ribbonBar();
SARibbonQuickAccessBar* quickAccessBar = ribbon->quickAccessBar();
quickAccessBar->addAction(createAction("save", ":/icon/icon/save.svg", "save-quickbar"));
quickAccessBar->addSeparator();
quickAccessBar->addAction(createAction("undo", ":/icon/icon/undo.svg"),"undo");
quickAccessBar->addAction(createAction("redo", ":/icon/icon/redo.svg"),"redo");
quickAccessBar->addSeparator();
}
void MainWindow::initRightButtonGroup(){
SARibbonBar* ribbon = ribbonBar();
SARibbonButtonGroupWidget* rightBar = ribbon->rightButtonGroup();
QAction* actionHelp = createAction("help", ":/icon/icon/help.svg","help");
connect(actionHelp, &QAction::triggered, this, &MainWindow::onActionHelpTriggered);
rightBar->addAction(actionHelp);
}
```
### SARibbonBar布局方案
`SARibbon`支持4种ribbon布局方案,布局方案参考了`office`的ribbon风格和`WPS`的ribbon风格,布局方案的切换可
通过`void SARibbonBar::setRibbonStyle(RibbonStyle v)`实现
`office`模式是最常见的ribbon模式,`tab`和标题栏占用位置较多,`WPS`设计的ribbon模式进行了改良,它为了减小ribbon的高度,把标签和标题栏设置在一起,这样减少了一个标题栏高度,有效利用了垂直空间,同时还把pannel的按钮布局由最大摆放3个变为摆放两个,进一步压缩了垂直空间
office的word界面和WPS Word界面截图对比
![office 界面截图](./doc/pic/office-screenshot.png)
![Wps 改动了ribbon的布局方式](./doc/pic/wps-change-ribbon-1.jpg)
在正常屏幕下,WPS 样式会比 Office 样式减少至少30像素左右的垂直高度,相比1920*1080的屏幕来说,相当于节约了接近3%的垂直空间
SARibbon中把带有标题栏的称之为宽松布局(Loose),宽松布局的各个元素如下图排列:
![宽松布局](./doc/pic/ribbonbar-geometry-office3.png)
这个布局和office的默认布局是一致的
SARibbon中把带有标题栏和tab结合一起的布局方式称之为紧凑布局(Compact),紧凑布局的各个元素如下图排列:
![紧凑布局](./doc/pic/ribbonbar-geometry-wps3.png)
SARibbonBar提供了`setRibbonStyle`函数,可以定义当前的布局方案,枚举`SARibbonBar::RibbonStyle`定义了四种布局方案:
- `SARibbonBar::RibbonStyleLooseThreeRow`宽松结构,3行模式(v0.x版本为`SARibbonBar::OfficeStyle`)
![SARibbonBar::RibbonStyleLooseThreeRow](doc/screenshot/office-3-style.png)
- `SARibbonBar::RibbonStyleLooseTwoRow`宽松结构,2行模式(v0.x版本为`SARibbonBar::OfficeStyleTwoRow`)
![SARibbonBar::RibbonStyleLooseTwoRow](doc/screenshot/office-2-style.png)
- `SARibbonBar::RibbonStyleCompactThreeRow`紧凑结构,3行模式(v0.x版本为`SARibbonBar::WpsLiteStyle`)
![SARibbonBar::RibbonStyleCompactThreeRow](doc/screenshot/wps-3-style.png)
- `SARibbonBar::RibbonStyleCompactTwoRow`紧凑结构,2行模式(v0.x版本为`SARibbonBar::WpsLiteStyleTwoRow`)
![SARibbonBar::RibbonStyleCompactTwoRow](doc/screenshot/wps-2-style.png)
### SARibbonBar文字换行,及图标大小
通过`SARibbonBar::setEnableWordWrap`函数可以控制SARibbonBar的文字是否换行,`SARibbonBar`的高度是固定的,文字是否换行会影响图标显示的大小,因此,如果你想图标看起来更大,可以设置文字不换行
`SARibbonBar::RibbonStyleCompactTwoRow`的布局模式下,文字不换行的显示效果如下:
![](doc/screenshot/wps-2-style-nowrap.png)
SARibbonBar文字设置为不换行后,会使图标的显示空间变得更大
### 不同的“按钮”布局方式
`SARibbonPannel`提供了三个添加action的方法:
- `addLargeAction`
- `addMediumAction`
- `addSmallAction`
在标准的pannel中,一个action(按钮)有3种布局,以office word为例,pannel的三种布局其实是所占行数:
- 第一种,占满整个pannel,称之为`large`
- 第二种,一个pannel下可以放置2个按钮,称之为`medium`
- 第三种,一个pannel放置3个按钮,称之为`samll`
![word pannel 布局示例](./doc/pic/pannelLayout3row-example.png)
枚举`SARibbonPannelItem::RowProportion`是为了表征每个窗体在pannel所占行数的情况,在pannel布局中会常用到,这个枚举定义如下:
```cpp
/**
* @brief 定义了行的占比,ribbon中有largemedia和small三种占比
*/
enum RowProportion {
None ///< 为定义占比,这时候将会依据expandingDirections来判断,如果能有Qt::Vertical,就等同于Large,否则就是Small
, Large ///< 大占比,一个widget的高度会充满整个pannel
, Medium ///< 中占比,在@ref SARibbonPannel::pannelLayoutMode 为 @ref SARibbonPannel::ThreeRowMode 时才会起作用,且要同一列里两个都是Medium时,会在三行中占据两行
, Small ///< 小占比,占SARibbonPannel的一行,Medium在不满足条件时也会变为Small,但不会变为Large
};
```
`SARibbonPannel`里管理的每个action都会带有一个私有的属性(`SARibbonPannelItem::RowProportion`),这个属性决定了这个action在pannel里的布局
### SARibbonPannel的布局模式
#### 3行模式
三行模式是传统的pannel布局方式,如下图所示:
![3行模式ribbon布局示例](./doc/pic/pannelLayout3row.png)
3行模式下有三种占位(`SARibbonPannelItem::RowProportion`),分别为large、medium和small
3行模式下的pannel会显示pannel的标题在`Pannel Title`区域,另外还有一个`OptionAction`的区域,这个是给这个action添加特殊触发使用的,如果没有设置`OptionAction`,这个区域是隐藏。
#### 2行模式
2行模式是WPS的改进布局法(具体是否是WPS首先这样做的不清楚,我是按照WPS的布局进行参考的),如下图所示:
![2行模式ribbon布局示例](./doc/pic/pannelLayout2row.png)
2行模式下medium和small占位(`SARibbonPannelItem::RowProportion`)是一样的,不做区分。
2行模式下pannel是不显示标题的
### SARibbon的自定义功能
ribbon的自定义是ribbon的一个特色,参考了office和wps的自定义界面,用户可以为自己的ribbon定义非常多的内容,甚至可以定义出一个完全和原来不一样的界面。
以下是office的自定义界面
![office的自定义界面](./doc/screenshot/customize/customization-office-ui.png)
SARibbon参考office和wps的界面,封装了方便使用的`SARibbonCustomize**`类,包括如下5个类:
> - SARibbonCustomizeDialog
> - SARibbonCustomizeWidget
> - SARibbonCustomizeData
> - SARibbonActionsManager
> - SARibbonActionsManagerModel
实际用户使用仅会面对`SARibbonActionsManager``SARibbonCustomizeDialog`/`SARibbonCustomizeWidget`,其余类用户正常不会使用。
`SARibbonActionsManager`是用来管理`QAction`,把想要自定义的`QAction`添加到`SARibbonActionsManager`中管理,并可以对`QAction`进行分类,以便在`SARibbonCustomizeDialog`/`SARibbonCustomizeWidget`中显示
`SARibbonCustomizeDialog`/`SARibbonCustomizeWidget`是具体的显示窗口,`SARibbonCustomizeDialog``SARibbonCustomizeWidget`封装为对话框,如果要实现office那样集成到配置对话框中可以使用`SARibbonCustomizeWidget``SARibbonCustomizeDialog`的效果如下图所示:
![SARibbon的自定义界面](./doc/screenshot/customize/customization-saribbon-ui.png)
#### 给界面添加自定义功能
这里演示如何添加自定义功能
首先定义`SARibbonActionsManager`作为MainWindow的成员变量
```cpp
//MainWindow.h 中定义成员变量
SARibbonActionsManager* m_ribbonActionMgr;///< 用于管理所有action
```
在MainWindow的初始化过程中,还需要创建大量的`QAction``QAction`的父对象指定为MainWindow,另外还会生成ribbon布局,例如添加category,添加pannel等操作,在上述操作完成后添加如下步骤,自动让`SARibbonActionsManager`管理所有的`QAction`
```cpp
//MainWindow的初始化,生成QAction
//生成ribbon布局
m_ribbonActionMgr = new SARibbonActionsManager(mainWinowPtr);
m_ribbonActionMgr->autoRegisteActions(mainWinowPtr);
```
`SARibbonActionsManager`的关键函数`autoRegisteActions`可以遍历 `SARibbonMainWindow`下的所有子object,找到action并注册,并会遍历所有`SARibbonCategory`,把`SARibbonCategory`下的action按`SARibbonCategory`的title name进行分类,此函数还会把`SARibbonMainWindow`下面的action,但不在任何一个category下的作为NotInRibbonCategoryTag标签注册,默认名字会赋予not in ribbon
在需要调用`SARibbonCustomizeDialog`的地方如下操作:
```cpp
QString cfgpath = "customization.xml";
SARibbonCustomizeDialog dlg(this, this);
dlg.setupActionsManager(m_ribbonActionMgr);
dlg.fromXml(cfgpath);//调用这一步是为了把已经存在的自定义步骤加载进来,在保存时能基于原有的自定义步骤上追加
if (QDialog::Accepted == dlg.exec()) {
dlg.applys();//应用自定义步骤
dlg.toXml(cfgpath);//把自定义步骤保存到文件中
}
```
在MainWindow生成前还需要把自定义的内容加载,因此在构造函数最后应该加入如下语句:
```cpp
//MainWindow的构造函数最后
sa_apply_customize_from_xml_file("customization.xml", this, m_ribbonActionMgr);
```
`sa_apply_customize_from_xml_file``SARibbonCustomizeWidget.h`中提供的函数,直接把配置文件中的自定义内容应用到MainWindow中。
这样软件每次启动都会按照配置文件加载。
# 更多截图
- 这是使用SARibbon构建的软件截图
![](./doc/screenshot/data-workbench-screenshot1-cn.gif)
![](./doc/screenshot/data-workbench-screenshot01-en.png)
[github - https://github.com/czyt1988/data-workbench](https://github.com/czyt1988/data-workbench)
[gitee - https://gitee.com/czyt1988/data-workbench](https://gitee.com/czyt1988/data-workbench)
具体Ribbon的生成代码可见:
[https://github.com/czyt1988/data-workbench/blob/master/src/APP/DAAppRibbonArea.cpp](https://github.com/czyt1988/data-workbench/blob/master/src/APP/DAAppRibbonArea.cpp)
# 文档生成
你可以通过doxygen生成qch和html类型的文档,`doc/Doxyfile-qch-cn`文件用于生成`.qch`格式的qt帮助文档,你可以把它集成到qt creator当中,`doc/Doxyfile-wiki-cn`文件用于生成html格式的文档,方便你在浏览器中查阅
# 常见问题
## 1、高分屏显示问题
针对高分屏显示,有如下两个方面准备
1 - 在main函数中为QApplication设置`Qt::AA_EnableHighDpiScaling`属性
这个属性使得应用程序自动检测显示器的像素密度来实现自动缩放,示例代码如下:
```cpp
int main(int argc, char* argv[])
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
QApplication a(argc, argv);
......
}
```
2 - 在main函数中为QApplication设置缩放策略:`QApplication::setHighDpiScaleFactorRoundingPolicy`
Qt5.6提供了`Qt::AA_EnableHighDpiScaling`,但不能完全解决,Qt5.14开始提供了高分屏缩放策略设置`QApplication::setHighDpiScaleFactorRoundingPolicy`,同`AA_EnableHighDpiScaling`一样需要在main函数前面设置
```cpp
int main(int argc, char* argv[])
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
QApplication a(argc, argv);
......
}
```
## 2、快捷键问题
经常有人反馈使用SARibbonBar后,没有被激活的tab页的快捷键没有响应,只有激活的标签页的快捷键才有反应,如果是传统的toolbar模式,由于action所在的toolbar一直在最前端,因此快捷键一直生效,但如果是SARibbonBaraction所在的pannel是会隐藏的,隐藏后快捷键就不生效,如果想快捷键无论Pannel是否隐藏都生效,设置快捷键的`shortcutContext`属性为`Qt::ApplicationShortcut`也无效,这时,可以在创建Category的地方手动创建快捷键
例如:
```cpp
ribbon构建
...
QShortcut* shortCut = new QShortcut(QKeySequence(QLatin1String("Ctrl+S")), this);
connect(shortCut, &QShortcut::activated, this, [ actSave ]() {
actSave->trigger();
});
```
这个快捷键的创建位置在Mainwidnow,这样快捷键就随着mainwindow周期
# 给我一个鼓励
如果项目对你有用,请你给我一个鼓励:
![](./doc/pic/赞赏码.png)