{"id":15039411,"url":"https://github.com/czyt1988/saribbon","last_synced_at":"2025-05-14T16:14:03.461Z","repository":{"id":38310342,"uuid":"108355079","full_name":"czyt1988/SARibbon","owner":"czyt1988","description":"Ribbon Control for Qt","archived":false,"fork":false,"pushed_at":"2025-03-12T08:49:59.000Z","size":18080,"stargazers_count":1171,"open_issues_count":17,"forks_count":343,"subscribers_count":45,"default_branch":"master","last_synced_at":"2025-04-12T21:18:56.537Z","etag":null,"topics":["cpp","office-framework","office-ribbon","office-ui","qribbon","qt","qt-ribbon","ribbon","ribbon-control","wps","wps-ui"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/czyt1988.png","metadata":{"files":{"readme":"readme-cn.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-26T03:08:16.000Z","updated_at":"2025-04-12T13:41:23.000Z","dependencies_parsed_at":"2023-10-12T10:15:48.663Z","dependency_job_id":"c8e898dd-70b5-4f10-914b-26bea3931b4c","html_url":"https://github.com/czyt1988/SARibbon","commit_stats":{"total_commits":508,"total_committers":16,"mean_commits":31.75,"dds":0.16338582677165359,"last_synced_commit":"cb1c73a22a20c17d5af1c9c5a620b4d630f40b57"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czyt1988%2FSARibbon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czyt1988%2FSARibbon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czyt1988%2FSARibbon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czyt1988%2FSARibbon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/czyt1988","download_url":"https://codeload.github.com/czyt1988/SARibbon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248631862,"owners_count":21136579,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","office-framework","office-ribbon","office-ui","qribbon","qt","qt-ribbon","ribbon","ribbon-control","wps","wps-ui"],"created_at":"2024-09-24T20:42:43.650Z","updated_at":"2025-04-12T21:19:04.155Z","avatar_url":"https://github.com/czyt1988.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿[Click here for English](./readme.md)\r\n\r\n\u003cdiv align=\"center\"\u003e\r\n\u003cp\u003e\r\n\u003cimg src=\"https://img.shields.io/badge/C++-17-blue\"/\u003e\r\n\u003cimg src=\"https://img.shields.io/badge/ -5.14+-green\"/\u003e\r\n\u003cimg src=\"https://img.shields.io/badge/Qt-6-green\"/\u003e\r\n\u003cimg src=\"https://img.shields.io/badge/license-MIT-yellow\"/\u003e\r\n\u003c/p\u003e\r\n\u003cp\u003e\r\n\u003cimg src=\"https://img.shields.io/badge/windows-0077d6\"/\u003e\r\n\u003cimg src=\"https://img.shields.io/badge/ubuntu-ed6432\"/\u003e\r\n\u003cimg src=\"https://img.shields.io/badge/macos-000\"/\u003e\r\n\u003c/p\u003e\r\n\u003c/div\u003e\r\n\r\nQQ交流群:434014314\r\n\r\n\u003cdiv align=\"center\"\u003e\r\n\u003cimg src=\"./doc/SARibbon-qq%E4%BA%A4%E6%B5%81%E7%BE%A4.jpg\" style=\"width:300px;\"/\u003e\r\n\u003c/div\u003e\r\n\r\n||Windows(latest)|Linux ubuntu(latest)|Mac(latest)|\r\n|:-|:-|:-|:-|\r\n|Qt5.12 LTS|[![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)|\r\n|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)|\r\n|Qt5.15 LTS|[![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)|\r\n|Qt6.2 LTS|[![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)|\r\n|Qt6.5 LTS|[![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)|\r\n|Qt6.8 LTS|[![cmake-win-qt6.8](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.8.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-win-qt6.8.yml)|[![CMake-Linux-Qt6.8](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.8.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-linux-qt6.8.yml)|[![cmake-mac-qt6.8](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.8.yml/badge.svg)](https://github.com/czyt1988/SARibbon/actions/workflows/cmake-mac-qt6.8.yml)|\r\n\r\n# SARibbon简介\r\n\r\n这是一个`Qt`下的`Ribbon`界面控件，提供了类似微软Office系列软件的操作界面。\r\n\r\n- `SARibbon`适用于大型软件、工业软件、复杂软件的ui\r\n- `SARibbon`在设计时参考了MFC Ribbon接口的命名风格\r\n- `SARibbon`的界面样式参考了微软Office系列软件以及WPS软件的Ribbon界面，并结合了两者的优点\r\n- `SARibbon`是一个可定义多种主题风格的Ribbon控件，它能通过qss快速的定义出自己想要的主题风格\r\n\r\n为了方便大型软件的开发，`SARibbon`对常用的一些功能性控件进行了封装，例如：[颜色选择按钮和颜色选择画板](https://github.com/czyt1988/SAColorWidgets)\r\n\r\n## 功能特点\r\n\r\n- 针对Ribbon的布局和显示\r\n\r\n![Ribbon的布局和显示](./doc/screenshot/SARibbonBar-overview.gif)\r\n\r\n- 支持最小化模式，ribbon只显示标签（默认双击标签会进行切换）,支持上下文标签tab\r\n\r\n![SARibbon最小化模式](./doc/screenshot/SARibbonBar-minMode.gif)\r\n\r\n- 支持quickAccessBar（word快速菜单），在不同布局模式下会有不同的显示效果\r\n\r\n![SARibbon-quickAccessBar](./doc/screenshot/SARibbonBar-quickAccessBar.gif)\r\n\r\n- 支持4种不同的ribbon button，普通按钮，延迟弹出菜单按钮，菜单按钮，action菜单按钮（action菜单按钮是此ribbon控件最主要解决的问题之一）\r\n\r\n![SARibbon-4种不同的ribbon button](./doc/screenshot/SARibbonBar-ribbonbutton.gif)\r\n\r\n- 支持4种不同风格的布局样式\r\n\r\n![SARibbon-4种不同风格的布局样式](./doc/screenshot/SARibbonBar-style.gif)\r\n\r\n- 支持qss对ribbon进行自定义设置，可实时切换主题,内置了5种不同风格的主题\r\n\r\nwin7主题：\r\n![SARibbon-theme-win7](./doc/screenshot/SARibbon-theme-win7.png)\r\noffice2013主题：\r\n![SARibbon-theme-office2013](./doc/screenshot/SARibbon-theme-office2013.png)\r\noffice2016主题：\r\n![SARibbon-theme-office2016](./doc/screenshot/SARibbon-theme-office2016.png)\r\noffice2021主题：\r\n![SARibbon-theme-office2021](./doc/screenshot/SARibbon-theme-office2021.png)\r\ndark主题：\r\n![SARibbon-theme-dark](./doc/screenshot/SARibbon-theme-dark.png)\r\n\r\n- 提供Gallery控件\r\n\r\n![](./doc/screenshot/SARibbonBar-gallery.gif)\r\n\r\n- 支持超长滚动和Option Action\r\n\r\n![](./doc/screenshot/SARibbonBar-option-action.gif)\r\n\r\n- 提供居中对齐模式\r\n\r\n![](./doc/screenshot/SARibbon-aligment-center.png)\r\n\r\n- 支持4K屏和多屏幕扩展\r\n- 支持linux和MacOS（界面未做深度适配）\r\n\r\nMIT协议，欢迎大家使用并提出意见\r\n\r\n[gitee(码云) - https://gitee.com/czyt1988/SARibbon](https://gitee.com/czyt1988/SARibbon)\r\n\r\n[github - https://github.com/czyt1988/SARibbon](https://github.com/czyt1988/SARibbon)\r\n\r\n# 构建\r\n\r\n这里建议使用cmake进行构建，cmake构建完成后并进行安装（install），使用cmake构建，你的工程既可以用cmake引入SARibbonBar，也可以使用qmake引入SARibbonBar\r\n\r\nSARibbon提供qmake和cmake两种构建方式，同时提供了一个集成的SARibbon.h和SARibbon.cpp文件可以快速静态的嵌入到工程中\r\n\r\n\u003e SARibbon支持第三方无边框库[QWindowkit](https://github.com/stdware/qwindowkit)，同时也支持简单的无边框方案，如果你需要操作系统原生的窗口支持，如windows7以后的贴边处理，windows11的最大化按钮悬停的效果，建议开启[QWindowkit](https://github.com/stdware/qwindowkit)库，[QWindowkit](https://github.com/stdware/qwindowkit)库还能较好解决多屏幕移动问题\r\n\r\n开启`QWindowkit`后的效果如下：\r\n\r\n![](./doc/pic/set-qwindowkit-on-snap.gif)\r\n\r\n如果你要依赖[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`命令:\r\n\r\n```shell\r\ngit submodule update --init --recursive\r\n```\r\n\r\n\u003e 用户指定使用[QWindowkit](https://github.com/stdware/qwindowkit)后，要求C++标准最低为C++17否则最低要求为c++14\r\n\r\n## 编译为动态库\r\n\r\n具体构建过程，见文档：[SARibbon构建](./doc/how-to-build-cn.md)\r\n\r\n## 静态引入工程\r\n\r\n你可以不对SARibbon库进行构建，直接引入\r\n\r\nSARibbon提供了合并好的`SARibbon.h`文件和`SARibbon.cpp`文件，资源文件也都合并进`SARibbon.cpp`中，只需要在自己的工程中引入这两个文件即可，无需编译为动态库，可以参考StaticExample例子（位于`example/StaticExample`）\r\n\r\n### 使用qmake\r\n\r\n使用qmake编译，有如下步骤：\r\n\r\n- 1. 把`SARibbon.h`、`SARibbon.cpp`、`SARibbon.pri`（位于`./src`目录下）拷贝到自己工程目录下\r\n- 2. 在自己工程的pro文件中引入`SARibbon.pri`文件，如：`include($$PWD/SARibbon.pri)`\r\n\r\nqmake可以通过`SARibbon.pri`文件设置是否开启第三方无边框库\r\n\r\n### 使用cmake\r\n\r\n使用cmake的话参考StaticExample（位于`example/StaticExample`）例子的cmake编写方式编写，把`SARibbon.h`、`SARibbon.cpp`引入工程即可\r\n\r\n```cmake\r\n\r\nset(SARIBBON_FILES\r\n    SARibbon.h\r\n    SARibbon.cpp\r\n)\r\nadd_executable({you-target} \r\n            {你项目的cpp和头文件}\r\n            ${SARIBBON_FILES}\r\n)\r\n```\r\n\r\n如果你需要使用`QWindowkit`,你的工程要引入`QWindowkit`库，并且增加预定义宏：\r\n\r\n```cmake\r\nfind_package(QWindowKit)\r\ntarget_link_libraries({you-target} PRIVATE QWindowKit::Widgets)\r\ntarget_compile_definitions({you-target} PRIVATE SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=1)\r\n```\r\n\r\n否则你需要把它设置为0\r\n\r\n```cmake\r\ntarget_compile_definitions({you-target} PRIVATE SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=0)\r\n```\r\n\r\n# 使用方法\r\n\r\n## 引入库\r\n\r\n在编译完成后，按照如下方法引入SARibbon\r\n\r\n### qmake\r\n\r\n- 1. 把`SARibbon.h`、`SARibbon.cpp`、`SARibbon.pri`（位于`./src`目录下）拷贝到自己工程目录下\r\n- 2. 在自己工程的pro文件中引入`SARibbon.pri`文件，如：`include($$PWD/SARibbon.pri)`\r\n\r\n `SARibbon.pri`文件可进行设置，具体可参见文件中的注释\r\n\r\n### cmake\r\n\r\n如果你是动态构建，在执行install后使用此库\r\n\r\ncmake引入方法：\r\n\r\n设置你的`SARibbonBar`安装目录，如：\r\n\r\n```\r\nset(SARibbonBar_DIR \"[你的SARibbonBar安装根目录]/lib/cmake\")\r\n```\r\n\r\n通过find_package引入\r\n\r\n```cmake\r\nfind_package(SARibbonBar REQUIRED)\r\n...\r\ntarget_link_libraries({your_target_name} PUBLIC SARibbonBar::SARibbonBar)\r\n```\r\n\r\n\r\n## 快速开始\r\n\r\nRibbon是把菜单栏和工具栏合并了，并通过一个tab控件进行展示，Ribbon是无法简单的使用Tab+Toolbar替代的，涉及到很多细节问题，`SARibbon`在设计时参考了MFC Ribbon接口的命名风格，标签页称之为`Category`(种类)，每个`Category`下面有多个`pannel`（面板），面板下面管理着toolbutton，`pannel`有点类似传统的`Toolbar`，其层次结构如下图所示，这些命名参考了MFC的ribbon界面类\r\n\r\n![msdn ribbon 介绍页](./doc/pic/msdn-ribbon.png)\r\n\r\n一些常见的名词解释如下\r\n\r\n- **Category 类别**，代表一个标签所呈现的内容，对应`SARibbonCategory`\r\n- **Context Category 上下文类别**，这个是一种特殊的类别，它正常不显示，需要基于上下文判断是否应该显示，最常用的就是word中插入图片后，会有图片修改相关的标签出现，如果没选中图片，这个标签就消失，这个就是上下文类别，对应`SARibbonContextCategory`\r\n- **Pannel 面板**，这个是一组菜单的集合，类似一个Toolbar，对应`SARibbonPannel`\r\n- **Application Button 应用按钮**，标签栏最左边的按钮（word就是对应文件按钮），这个按钮会触发一些特殊的页面或菜单，对应`SARibbonApplicationButton`,可以隐藏\r\n- **Quick Access Bar 快速响应栏**，位于最顶部的一个简单工具栏，用于放置一些常用的action，对应`SARibbonQuickAccessBar`\r\n- **Gallery 预览控件**,这是Ribbon最吸引眼球的控件，用直观的图像把功能显示出来，甚至有些会根据上下文进行实时渲染，典型的就是word开始标签下的样式选择，对应`SARibbonGallery`\r\n\r\nSARibbonBar的层次如下图所示：\r\n\r\n![](./doc/pic/saribbonbar-level.png)\r\n\r\n\u003e 注：不同的布局方案影响着`Category`和`Quick Access Bar`的摆放方式，具体可见[SARibbonBar布局方案](#SARibbonBar布局方案)\r\n\r\n### 在MainWindow中使用Ribbon\r\n\r\n要MainWindow中使用SARibbon，需要把`QMainWindow`替换为`SARibbonMainWindow`，`SARibbonMainWindow`修改了`QMainWindow`对menubar的渲染方式\r\n\r\n\u003e 注意，如果使用ui文件，要把原来ui文件的菜单删除，否则可能引起一些异常，如下图所示：\r\n\u003e ![](./doc/pic/remove-menu-bar-at-uifile.png)\r\n\r\n示例代码如下:\r\n\r\n```cpp\r\n#include \"SARibbonMainWindow.h\"\r\nclass MainWindow : public SARibbonMainWindow\r\n{\r\n    Q_OBJECT\r\npublic:\r\n    MainWindow(QWidget* par = nullptr);\r\n    ...\r\n}\r\n```\r\n\r\n`SARibbonMainWindow`也支持普通模式的渲染，SARibbonMainWindow的构造函数第二个参数用于设定是否用ribbon模式：\r\n\r\n```cpp\r\nSARibbonMainWindow(QWidget *parent = nullptr, bool useRibbon = true);\r\n```\r\n\r\n第二个参数如果设置为false，将会使用普通的菜单工具栏模式，预留这个接口是为了一些项目需要能在ribbon和经典菜单工具栏切换的场景设计的，Ribbon状态和经典状态不支持热切换，如果需要切换，用户可以设置一个配置文件或者注册表，在应用重启时给第二个参数传入false即可进入到经典菜单工具栏模式\r\n\r\n### 在QWidget或QDialog中使用SARibbonBar\r\n\r\nSARibbonBar支持在QWidget或者QDialog上使用，具体可见例子：`example/WidgetWithRibbon`\r\n\r\n项目提供了`SARibbonWidget`类，widget窗口继承`SARibbonWidget`即可实现ribbon效果的窗口\r\n\r\n```cpp\r\n#include \"SARibbonWidget.h\"\r\n\r\nclass RibbonWidget : public SARibbonWidget\r\n{\r\n Q_OBJECT\r\npublic:\r\n    RibbonWidget(QWidget* parent = nullptr);\r\n};\r\n```\r\n\r\n`SARibbonWidget`类提供了`setWidget`方法，可以嵌入任意的widget\r\n\r\n```cpp\r\nRibbonWidget::RibbonWidget(QWidget* parent) : SARibbonWidget(parent)\r\n{\r\n    // 获取SARibbonBar\r\n    SARibbonBar* ribbonbar = ribbonBar();\r\n    // QWidget模式下，没有必要再显示标题\r\n    ribbonbar-\u003esetTitleVisible(false);\r\n    // QWidget模式下，直接使用紧凑模式效果更好\r\n    ribbonbar-\u003esetRibbonStyle(SARibbonBar::RibbonStyleCompactThreeRow);\r\n    // 取消applicationbutton\r\n    ribbonbar-\u003esetApplicationButton(nullptr);\r\n\r\n    setWidget(new InnerWidget());\r\n}\r\n```\r\n\r\n效果如下：\r\n\r\n![Ribbon用在QWidget上](./doc/screenshot/ribbonbar-use-in-qwidget.png)\r\n\r\n### 创建Category和Pannel\r\n\r\n创建ribbon的顺序是：先创建类别(Category)，再创建面板(Pannel)，最后创建对应的toolbutton（action）\r\n\r\n使用`SARibbonBar::addCategoryPage`把Category添加到SARibbonBar中，使用`SARibbonCategory::addPannel`把`Pannel`添加到`Category`中,使用`SARibbonPannel::addAction`可以在Pannel上添加action\r\n\r\n下面的代码，演示了添加一个action的示例：\r\n\r\n```cpp\r\n//添加主标签页 - 通过addCategoryPage工厂函数添加\r\nSARibbonCategory* categoryMain = ribbon-\u003eaddCategoryPage(tr(\"Main\"));\r\n //使用addPannel函数来创建SARibbonPannel，效果和new SARibbonPannel再addPannel一样\r\nSARibbonPannel* pannel1 = categoryMain-\u003eaddPannel(\"Panel 1\");\r\nQAction* actSave = new QAction(this);\r\nactSave-\u003esetText(\"save\");\r\nactSave-\u003esetIcon(QIcon(\":/icon/icon/save.svg\"));\r\nactSave-\u003esetObjectName(\"actSave\");\r\nactSave-\u003esetShortcut(QKeySequence(QLatin1String(\"Ctrl+S\")));\r\npannel1-\u003eaddLargeAction(actSave);\r\n```\r\n\r\n上面的操作添加了一个按钮，效果如下图所示：\r\n\r\n![](./doc/pic/add-large-action.png)\r\n\r\n用户也可以直接new出SARibbonCategory，并添加到pannel中，下面的代码效果和上面的一样：\r\n\r\n```cpp\r\nSARibbonCategory* categoryMain = new SARibbonCategory(tr(\"Main\"));\r\nribbon-\u003eaddCategoryPage(categoryMain);\r\nSARibbonPannel* pannel1 = new SARibbonPannel(\"Panel 1\");\r\ncategoryMain-\u003eaddPannel(pannel1);\r\nQAction* actSave = new QAction(this);\r\n...\r\npannel1-\u003eaddLargeAction(actSave);\r\n```\r\n\r\nRibbon的图标有大有小，通过`addLargeAction`、`addMediumAction`、`addSmallAction`可以组合出不同的布局样式\r\n\r\n具体可见[./example/MainWindowExample/mainwindow.cpp](./example/MainWindowExample/mainwindow.cpp)\r\n\r\n### ContextCategory 上下文标签\r\n\r\n所谓上下文标签是指在特殊情况下才出现的标签/标签组，例如office word在选中图片时会出现图片编辑的上下文标签，如下图所示：\r\n\r\n![上下文标签](doc/pic/word-contextcategory.png)\r\n\r\nSARibbon中上下文标签对应的类为`SARibbonContextCategory`\r\n\r\n上下文标签一般在程序初始化的时候就创建好，平时隐藏，等待需要显示的时候再显示，创建上下文标签如下：\r\n\r\n由于上下文标签需要使用时唤起，因此，用一个成员变量保存起来是一个比较好的选择，当然也可以遍历查找（`SARibbonBar::contextCategoryList`可以例举所有的`SARibbonContextCategory`）\r\n\r\n头文件：\r\n\r\n```cpp\r\nSARibbonContextCategory* m_contextCategory;\r\n```\r\n\r\ncpp文件:\r\n\r\n```cpp\r\nSARibbonBar* ribbon = ribbonBar();\r\n//创建一个contextCategory，颜色随机\r\nm_contextCategory   = ribbon-\u003eaddContextCategory(tr(\"context\"), QColor());\r\nSARibbonCategory* contextCategoryPage1 = m_contextCategory-\u003eaddCategoryPage(tr(\"Page1\"));\r\n//对contextCategoryPage1进行操作\r\n......\r\nSARibbonCategory* contextCategoryPage2 = m_contextCategory-\u003eaddCategoryPage(tr(\"Page2\"));\r\n//对contextCategoryPage2进行操作\r\n......\r\n```\r\n\r\n由`SARibbonContextCategory`创建的`SARibbonCategory`归`SARibbonContextCategory`管理，只有`SARibbonContextCategory`“显示了”,其管理的`SARibbonCategory`才显示，**注意：** `SARibbonContextCategory`并不是一个窗口，所以，它的“显示”打了引号\r\n\r\n要显示一个上下文只需要调用`SARibbonBar::showContextCategory`/`SARibbonBar::hideContextCategory`即可:\r\n\r\n```cpp\r\nvoid MainWindow::onShowContextCategory(bool on)\r\n{\r\n    if (on) {\r\n        this-\u003eribbonBar()-\u003eshowContextCategory(m_contextCategory);\r\n    } else {\r\n        this-\u003eribbonBar()-\u003ehideContextCategory(m_contextCategory);\r\n    }\r\n}\r\n```\r\n\r\n**注意：** 如果要删除`contextCategory`需要调用`SARibbonBar::destroyContextCategory`，而不是直接delete，调用`SARibbonBar::destroyContextCategory`之后无需再对ContextCategory的指针delete\r\n\r\n不同样式的contextCategory有不一样的风格，具体可见：[SARibbon样式](#SARibbon样式)以及[不同样式下的显示对比](#不同样式下的显示对比)\r\n\r\n### ApplicationButton\r\n\r\nribbon界面左上角有个特殊且明显的按钮，称之为`applicationButton`，这个按钮一般用于调出菜单，SARibbonBar在构造时默认就创建了`applicationButton`，可以通过如下方式设置其文字：\r\n\r\n```cpp\r\nSARibbonBar* ribbon = ribbonBar();\r\nribbon-\u003eapplicationButton()-\u003esetText((\"File\"));\r\n```\r\n\r\n默认的applicationButton继承自`SARibbonApplicationButton`,而`SARibbonApplicationButton`继承自`QPushButton`，因此你可以对其进行`QPushButton`所有的操作，如果想设置自己的Button作为applicationButton也是可以的，只需要调用`SARibbonBar::setApplicationButton`函数即可\r\n\r\n### QuickAccessBar和rightButtonGroup\r\n\r\nQuickAccessBar是左上角的快速工具栏，rightButtonGroup是右上角的快速工具栏，在office模式下分左右两边，在wps模式下，左右将合起来，统一放到右边\r\n\r\n![QuickAccessBar And RightButtonGroup](./doc/screenshot/QuickAccessBarAndRightButtonGroup.png)\r\n\r\nSARibbon中：\r\n\r\n- QuickAccessBar对应`SARibbonQuickAccessBar`类\r\n- rightButtonGroup对应`SARibbonButtonGroupWidget`类\r\n\r\nSARibbonBar在初始化时会默认创建QuickAccessBar和RightButtonGroup，通过`SARibbonBar::quickAccessBar`和`SARibbonBar::rightButtonGroup`即可获取其指针进行操作，示例如下：\r\n\r\n```cpp\r\nQAction* MainWindow::createAction(const QString\u0026 text, const QString\u0026 iconurl, const QString\u0026 objName)\r\n{\r\n    QAction* act = new QAction(this);\r\n    act-\u003esetText(text);\r\n    act-\u003esetIcon(QIcon(iconurl));\r\n    act-\u003esetObjectName(objName);\r\n    return act;\r\n}\r\n\r\nvoid MainWindow::initQuickAccessBar(){\r\n    SARibbonBar* ribbon = ribbonBar();\r\n    SARibbonQuickAccessBar* quickAccessBar = ribbon-\u003equickAccessBar();\r\n    quickAccessBar-\u003eaddAction(createAction(\"save\", \":/icon/icon/save.svg\", \"save-quickbar\"));\r\n    quickAccessBar-\u003eaddSeparator();\r\n    quickAccessBar-\u003eaddAction(createAction(\"undo\", \":/icon/icon/undo.svg\"),\"undo\");\r\n    quickAccessBar-\u003eaddAction(createAction(\"redo\", \":/icon/icon/redo.svg\"),\"redo\");\r\n    quickAccessBar-\u003eaddSeparator();\r\n}\r\nvoid MainWindow::initRightButtonGroup(){\r\n    SARibbonBar* ribbon = ribbonBar();\r\n    SARibbonButtonGroupWidget* rightBar = ribbon-\u003erightButtonGroup();\r\n    QAction* actionHelp = createAction(\"help\", \":/icon/icon/help.svg\",\"help\");\r\n    connect(actionHelp, \u0026QAction::triggered, this, \u0026MainWindow::onActionHelpTriggered);\r\n    rightBar-\u003eaddAction(actionHelp);\r\n}\r\n```\r\n\r\n### SARibbonBar布局方案\r\n\r\n `SARibbon`支持4种ribbon布局方案，布局方案参考了`office`的ribbon风格和`WPS`的ribbon风格，布局方案的切换可\r\n通过`void SARibbonBar::setRibbonStyle(RibbonStyle v)`实现\r\n\r\n`office`模式是最常见的ribbon模式，`tab`和标题栏占用位置较多，`WPS`设计的ribbon模式进行了改良，它为了减小ribbon的高度，把标签和标题栏设置在一起，这样减少了一个标题栏高度，有效利用了垂直空间，同时还把pannel的按钮布局由最大摆放3个变为摆放两个，进一步压缩了垂直空间\r\n\r\noffice的word界面和WPS Word界面截图对比\r\n\r\n![office 界面截图](./doc/pic/office-screenshot.png)\r\n\r\n![Wps 改动了ribbon的布局方式](./doc/pic/wps-change-ribbon-1.jpg)\r\n\r\n在正常屏幕下，WPS 样式会比 Office 样式减少至少30像素左右的垂直高度，相比1920*1080的屏幕来说，相当于节约了接近3%的垂直空间\r\n\r\nSARibbon中把带有标题栏的称之为宽松布局（Loose），宽松布局的各个元素如下图排列：\r\n\r\n![宽松布局](./doc/pic/ribbonbar-geometry-office3.png)\r\n\r\n这个布局和office的默认布局是一致的\r\n\r\nSARibbon中把带有标题栏和tab结合一起的布局方式称之为紧凑布局（Compact），紧凑布局的各个元素如下图排列：\r\n\r\n![紧凑布局](./doc/pic/ribbonbar-geometry-wps3.png)\r\n\r\nSARibbonBar提供了`setRibbonStyle`函数，可以定义当前的布局方案，枚举`SARibbonBar::RibbonStyle`定义了四种布局方案：\r\n\r\n- `SARibbonBar::RibbonStyleLooseThreeRow`宽松结构，3行模式(v0.x版本为`SARibbonBar::OfficeStyle`)\r\n\r\n![SARibbonBar::RibbonStyleLooseThreeRow](doc/screenshot/office-3-style.png)\r\n\r\n- `SARibbonBar::RibbonStyleLooseTwoRow`宽松结构，2行模式(v0.x版本为`SARibbonBar::OfficeStyleTwoRow`)\r\n\r\n![SARibbonBar::RibbonStyleLooseTwoRow](doc/screenshot/office-2-style.png)\r\n\r\n- `SARibbonBar::RibbonStyleCompactThreeRow`紧凑结构，3行模式(v0.x版本为`SARibbonBar::WpsLiteStyle`)\r\n\r\n![SARibbonBar::RibbonStyleCompactThreeRow](doc/screenshot/wps-3-style.png)\r\n\r\n- `SARibbonBar::RibbonStyleCompactTwoRow`紧凑结构，2行模式(v0.x版本为`SARibbonBar::WpsLiteStyleTwoRow`)\r\n\r\n![SARibbonBar::RibbonStyleCompactTwoRow](doc/screenshot/wps-2-style.png)\r\n\r\n### SARibbonBar文字换行，及图标大小\r\n\r\n通过`SARibbonBar::setEnableWordWrap`函数可以控制SARibbonBar的文字是否换行，`SARibbonBar`的高度是固定的，文字是否换行会影响图标显示的大小，因此，如果你想图标看起来更大，可以设置文字不换行\r\n\r\n在`SARibbonBar::RibbonStyleCompactTwoRow`的布局模式下，文字不换行的显示效果如下：\r\n\r\n![](doc/screenshot/wps-2-style-nowrap.png)\r\n\r\nSARibbonBar文字设置为不换行后，会使图标的显示空间变得更大\r\n\r\n### 不同的“按钮”布局方式\r\n\r\n`SARibbonPannel`提供了三个添加action的方法：\r\n\r\n- `addLargeAction`\r\n- `addMediumAction`\r\n- `addSmallAction`\r\n\r\n在标准的pannel中，一个action（按钮）有3种布局，以office word为例，pannel的三种布局其实是所占行数:\r\n\r\n- 第一种，占满整个pannel，称之为`large`\r\n- 第二种，一个pannel下可以放置2个按钮，称之为`medium`\r\n- 第三种，一个pannel放置3个按钮，称之为`samll`\r\n\r\n![word pannel 布局示例](./doc/pic/pannelLayout3row-example.png)\r\n\r\n枚举`SARibbonPannelItem::RowProportion`是为了表征每个窗体在pannel所占行数的情况，在pannel布局中会常用到，这个枚举定义如下：\r\n\r\n```cpp\r\n/**\r\n  * @brief 定义了行的占比，ribbon中有large，media和small三种占比\r\n  */\r\nenum RowProportion {\r\n    None            ///\u003c 为定义占比，这时候将会依据expandingDirections来判断，如果能有Qt::Vertical，就等同于Large，否则就是Small\r\n    , Large         ///\u003c 大占比，一个widget的高度会充满整个pannel\r\n    , Medium        ///\u003c 中占比，在@ref SARibbonPannel::pannelLayoutMode 为 @ref SARibbonPannel::ThreeRowMode 时才会起作用，且要同一列里两个都是Medium时，会在三行中占据两行\r\n    , Small         ///\u003c 小占比，占SARibbonPannel的一行，Medium在不满足条件时也会变为Small，但不会变为Large\r\n};\r\n```\r\n\r\n`SARibbonPannel`里管理的每个action都会带有一个私有的属性（`SARibbonPannelItem::RowProportion`），这个属性决定了这个action在pannel里的布局\r\n\r\n### SARibbonPannel的布局模式\r\n\r\n#### 3行模式\r\n\r\n三行模式是传统的pannel布局方式，如下图所示：\r\n\r\n![3行模式ribbon布局示例](./doc/pic/pannelLayout3row.png)\r\n\r\n3行模式下有三种占位(`SARibbonPannelItem::RowProportion`)，分别为large、medium和small\r\n\r\n3行模式下的pannel会显示pannel的标题在`Pannel Title`区域，另外还有一个`OptionAction`的区域，这个是给这个action添加特殊触发使用的，如果没有设置`OptionAction`，这个区域是隐藏。\r\n\r\n#### 2行模式\r\n\r\n2行模式是WPS的改进布局法（具体是否是WPS首先这样做的不清楚，我是按照WPS的布局进行参考的），如下图所示：\r\n\r\n![2行模式ribbon布局示例](./doc/pic/pannelLayout2row.png)\r\n\r\n2行模式下medium和small占位(`SARibbonPannelItem::RowProportion`)是一样的，不做区分。\r\n\r\n2行模式下pannel是不显示标题的\r\n\r\n### SARibbon的自定义功能\r\n\r\nribbon的自定义是ribbon的一个特色，参考了office和wps的自定义界面，用户可以为自己的ribbon定义非常多的内容，甚至可以定义出一个完全和原来不一样的界面。\r\n\r\n以下是office的自定义界面\r\n\r\n![office的自定义界面](./doc/screenshot/customize/customization-office-ui.png)\r\n\r\nSARibbon参考office和wps的界面，封装了方便使用的`SARibbonCustomize**`类，包括如下5个类：\r\n\r\n\u003e - SARibbonCustomizeDialog\r\n\u003e - SARibbonCustomizeWidget\r\n\u003e - SARibbonCustomizeData\r\n\u003e - SARibbonActionsManager\r\n\u003e - SARibbonActionsManagerModel\r\n\r\n实际用户使用仅会面对`SARibbonActionsManager`和`SARibbonCustomizeDialog`/`SARibbonCustomizeWidget`，其余类用户正常不会使用。\r\n\r\n`SARibbonActionsManager`是用来管理`QAction`，把想要自定义的`QAction`添加到`SARibbonActionsManager`中管理，并可以对`QAction`进行分类，以便在`SARibbonCustomizeDialog`/`SARibbonCustomizeWidget`中显示\r\n\r\n`SARibbonCustomizeDialog`/`SARibbonCustomizeWidget`是具体的显示窗口，`SARibbonCustomizeDialog`把`SARibbonCustomizeWidget`封装为对话框，如果要实现office那样集成到配置对话框中可以使用`SARibbonCustomizeWidget`，`SARibbonCustomizeDialog`的效果如下图所示：\r\n\r\n![SARibbon的自定义界面](./doc/screenshot/customize/customization-saribbon-ui.png)\r\n\r\n#### 给界面添加自定义功能\r\n\r\n这里演示如何添加自定义功能\r\n\r\n首先定义`SARibbonActionsManager`作为MainWindow的成员变量\r\n\r\n```cpp\r\n//MainWindow.h 中定义成员变量\r\nSARibbonActionsManager* m_ribbonActionMgr;///\u003c 用于管理所有action\r\n```\r\n\r\n在MainWindow的初始化过程中，还需要创建大量的`QAction`，`QAction`的父对象指定为MainWindow，另外还会生成ribbon布局，例如添加category，添加pannel等操作，在上述操作完成后添加如下步骤，自动让`SARibbonActionsManager`管理所有的`QAction`\r\n\r\n```cpp\r\n//MainWindow的初始化，生成QAction\r\n//生成ribbon布局\r\nm_ribbonActionMgr = new SARibbonActionsManager(mainWinowPtr);\r\nm_ribbonActionMgr-\u003eautoRegisteActions(mainWinowPtr);\r\n```\r\n\r\n`SARibbonActionsManager`的关键函数`autoRegisteActions`可以遍历 `SARibbonMainWindow`下的所有子object，找到action并注册，并会遍历所有`SARibbonCategory`,把`SARibbonCategory`下的action按`SARibbonCategory`的title name进行分类，此函数还会把`SARibbonMainWindow`下面的action，但不在任何一个category下的作为NotInRibbonCategoryTag标签注册，默认名字会赋予not in ribbon\r\n\r\n在需要调用`SARibbonCustomizeDialog`的地方如下操作：\r\n\r\n```cpp\r\nQString cfgpath = \"customization.xml\";\r\nSARibbonCustomizeDialog dlg(this, this);\r\n\r\ndlg.setupActionsManager(m_ribbonActionMgr);\r\ndlg.fromXml(cfgpath);//调用这一步是为了把已经存在的自定义步骤加载进来，在保存时能基于原有的自定义步骤上追加\r\nif (QDialog::Accepted == dlg.exec()) {\r\n    dlg.applys();//应用自定义步骤\r\n    dlg.toXml(cfgpath);//把自定义步骤保存到文件中\r\n}\r\n```\r\n\r\n在MainWindow生成前还需要把自定义的内容加载，因此在构造函数最后应该加入如下语句：\r\n\r\n```cpp\r\n//MainWindow的构造函数最后\r\nsa_apply_customize_from_xml_file(\"customization.xml\", this, m_ribbonActionMgr);\r\n```\r\n\r\n`sa_apply_customize_from_xml_file`是`SARibbonCustomizeWidget.h`中提供的函数，直接把配置文件中的自定义内容应用到MainWindow中。\r\n\r\n这样软件每次启动都会按照配置文件加载。\r\n\r\n# 更多截图\r\n\r\n- 这是使用SARibbon构建的软件截图\r\n\r\n![](./doc/screenshot/data-workbench-screenshot1-cn.gif)\r\n![](./doc/screenshot/data-workbench-screenshot01-en.png)\r\n![](./doc/screenshot/data-workbench-screenshot01-cn.png)\r\n\r\n[github - https://github.com/czyt1988/data-workbench](https://github.com/czyt1988/data-workbench)\r\n\r\n[gitee - https://gitee.com/czyt1988/data-workbench](https://gitee.com/czyt1988/data-workbench)\r\n\r\n具体Ribbon的生成代码可见：\r\n\r\n[https://github.com/czyt1988/data-workbench/blob/master/src/APP/DAAppRibbonArea.cpp](https://github.com/czyt1988/data-workbench/blob/master/src/APP/DAAppRibbonArea.cpp)\r\n\r\n# 文档生成\r\n\r\n你可以通过doxygen生成qch和html类型的文档，`doc/Doxyfile-qch-cn`文件用于生成`.qch`格式的qt帮助文档,你可以把它集成到qt creator当中，`doc/Doxyfile-wiki-cn`文件用于生成html格式的文档，方便你在浏览器中查阅\r\n\r\n# 常见问题\r\n\r\n## 1、高分屏显示问题\r\n\r\n针对高分屏显示，有如下两个方面准备\r\n\r\n1 - 在main函数中为QApplication设置`Qt::AA_EnableHighDpiScaling`属性\r\n\r\n这个属性使得应用程序自动检测显示器的像素密度来实现自动缩放，示例代码如下：\r\n\r\n```cpp\r\nint main(int argc, char* argv[])\r\n{\r\n#if (QT_VERSION \u003e= QT_VERSION_CHECK(5, 6, 0))\r\n    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);\r\n    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);\r\n#endif\r\n    QApplication a(argc, argv);\r\n    ......\r\n}\r\n```\r\n\r\n2 - 在main函数中为QApplication设置缩放策略：`QApplication::setHighDpiScaleFactorRoundingPolicy`\r\n\r\nQt5.6提供了`Qt::AA_EnableHighDpiScaling`，但不能完全解决，Qt5.14开始提供了高分屏缩放策略设置`QApplication::setHighDpiScaleFactorRoundingPolicy`，同`AA_EnableHighDpiScaling`一样需要在main函数前面设置\r\n\r\n```cpp\r\nint main(int argc, char* argv[])\r\n{\r\n#if (QT_VERSION \u003e= QT_VERSION_CHECK(5, 6, 0))\r\n    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);\r\n    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);\r\n#endif\r\n#if (QT_VERSION \u003e= QT_VERSION_CHECK(5, 14, 0))\r\n    QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);\r\n#endif\r\n    QApplication a(argc, argv);\r\n    ......\r\n}\r\n```\r\n\r\n如果你使用OpenGL窗口发生了一些奇怪的问题，你可以把上面这些语句去掉看看，最新版Qt已经不需要进行上述的处理了\r\n\r\n## 2、快捷键问题\r\n\r\n经常有人反馈使用SARibbonBar后，没有被激活的tab页的快捷键没有响应，只有激活的标签页的快捷键才有反应，如果是传统的toolbar模式，由于action所在的toolbar一直在最前端，因此快捷键一直生效，但如果是SARibbonBar，action所在的pannel是会隐藏的，隐藏后快捷键就不生效，如果想快捷键无论Pannel是否隐藏都生效，设置快捷键的`shortcutContext`属性为`Qt::ApplicationShortcut`也无效，这时，可以通过Qt的`QWidget::addAction`函数把带快捷键的action添加到MainWindow中\r\n\r\n例如：\r\n\r\n```cpp\r\nvoid MainWindow::initRibbon(){\r\n    SARibbonCategory* categoryMain = ribbon-\u003eaddCategoryPage(tr(\"Main\"));\r\n    SARibbonPannel* pannel = categoryMain-\u003eaddPannel(tr(\"io\"));\r\n    //这里省略action的创建过程\r\n    QAction* actSave = new QAction(this);\r\n    ...\r\n    //给action设置快捷键\r\n    actSave-\u003esetShortcut(QKeySequence(QLatin1String(\"Ctrl+S\")));\r\n    //把action添加到pannel中\r\n    pannel-\u003eaddLargeAction(actSave);\r\n    //把action添加到MainWindow中，这样切换到其他标签页，也可以响应快捷键\r\n    addAction(actSave);\r\n}\r\n```\r\n\r\n## 3、主题设置不生效\r\n\r\n某些版本的qt，在构造函数设置主题会不完全生效，可以使用QTimer投放到队列最后执行，如：\r\n\r\n```cpp\r\nQTimer::singleShot(0, this, [ this ]() { \r\n    this-\u003esetRibbonTheme(SARibbonMainWindow::RibbonThemeDark); \r\n    });\r\n```\r\n\r\n## 4、遇到宏重定义\r\n\r\n出现这个错误是在使用SARibbon.h/cpp时，这是因为早期版本的一些写在cpp里的调试宏没有做`#ifdef`处理，多个cpp合并后就会出现问题，用共享库不会出现此问题，如果遇到此问题，更新到v2.2.8以上版本即可\r\n\r\n## 5、最大最小化图标不在右上角而在左上角\r\n\r\n如果你遇到这个问题，确认编译的库文件和头文件是否匹配，通常这个问题发生在局部更新上，也就是仅仅替换了dll，而没有替换h文件导致的，有些工程在拉取了最新的SARibbon版本后，更新完直接替换lib和dll文件，头文件没有替换就会发生此问题，修复此问题的方法是确保所有文件的版本一致性，你可以把原来涉及的文件都删除掉，如果你用cmake安装的话，将涉及如下文件/文件夹：\r\n\r\n```txt\r\nbin/SARibbonBar.dll\r\ninclude/SARibbonBar[文件夹]\r\nlib/SARibbonBar.lib\r\nlib/qmake/SARibbonBar[文件夹]\r\nlib/cmake/SARibbonBar[文件夹]\r\nSARibbonBar_amalgamate\r\n```\r\n\r\n## 6、图标没有显示\r\n\r\n如果你遇到图标不显示，例如最大最小化按钮没有图标但有按钮，那么说明你的运行环境没有找到Qt的svg插件，你的程序目录下应该要有`imageformats/qsvg.dll`插件，你可以运行windeployqt拉取你程序的依赖，或者确保你的环境变量PATH配置中能找到`plugins/imageformats`文件夹\r\n\r\n# 给我一个鼓励\r\n\r\n如果项目对你有用，请你给我一个鼓励：\r\n\u003cdiv style=\"text-align:center\"\u003e\r\n    \u003cimg src=\"./doc/pic/赞赏码.png\" alt=\"赞赏码\" style=\"width:400px;\" /\u003e\r\n\u003c/div\u003e\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczyt1988%2Fsaribbon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fczyt1988%2Fsaribbon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczyt1988%2Fsaribbon/lists"}