1263 words
6 minutes
Nest开发笔记-NestUI v0.1.0
在本篇博客中,我将介绍NestUI模块的设计与实现,并说明如何集成第三方UI库SARibbon,如何设计MainWindow、DockWidget、DockWidgetManager等类
项目仓库:
Waiting for api.github.com...
NestUI模块概述
模块职责
- 为Nest框架提供基于Qt的UI组件
- 负责对于框架中的UI进行管理,如:对于停靠窗口的管理(DockWidgetManager)
集成SARibbon
-
SARibbon
- 是一个Qt下的Ribbon界面控件,提供了类似微软Office系列软件的操作界面
- SARibbon适用于大型软件、工业软件、复杂软件的ui
- SARibbon在设计时参考了MFC Ribbon接口的命名风格
- SARibbon的界面样式参考了微软Office系列软件以及WPS软件的Ribbon界面,并结合了两者的优点
- SARibbon是一个可定义多种主题风格的Ribbon控件,它能通过qss快速的定义出自己想要的主题风格
-
集成SARibbon
在NestUI中,我将SARibbon库作为第三方构件来支撑框架中的UI。
- 使用命令
git submodule add https://github.com/Jerryym/SARibbon.git NestUI/vendor/SARibbon将SARibbon作为子模块添加到NestUI项目中,并通过命令git submodule update --init --recursive保证子模块被正确初始化和更新
- 使用命令
MainWindow
-
设计思路、
-
设计一个结构体用于存储主窗口属性:窗口宽度、窗口高度和窗口标题
-
设计一个名为
MainWindow的类,此类继承于SARibbonMainWindow,使其能够使用SARibbon风格的UINOTE
后续根据开发和应用的实际需求,可能会把MainWindow设计成纯虚类。
-
-
代码
MainWindow.h namespace NestUI {/// @brief 窗口属性typedef struct NESTUI_API sWindowProp{unsigned int m_nWidth; //窗口宽unsigned int m_nHeight; //窗口高QString m_STitle; //窗口标题sWindowProp(unsigned int width = 1600, unsigned int height = 900,const QString& title = "Nest"): m_nWidth(width), m_nHeight(height), m_STitle(title){}}sWindowProp;/// @brief 主窗口class NESTUI_API MainWindow : public SARibbonMainWindow{Q_OBJECTpublic:MainWindow(QWidget* parent = nullptr, const sWindowProp& sProp = sWindowProp());virtual ~MainWindow() {}public:/// @brief 获取主窗口宽度/// @returnunsigned int GetWidth() const { return m_sProp.m_nWidth; }/// @brief 获取主窗口高度/// @returnunsigned int GetHeigth() const { return m_sProp.m_nHeight; }/// @brief 获取主窗口标题名/// @returnQString GetTitle() const { return m_sProp.m_STitle; }private:/// @brief 主窗口属性sWindowProp m_sProp;};}//MainWindow.cppnamespace NestUI {MainWindow::MainWindow(QWidget* parent, const sWindowProp& sProp): SARibbonMainWindow(parent), m_sProp(sProp){//设置窗口标题setWindowTitle(sProp.m_STitle);//初始化窗口大小resize(QSize(sProp.m_nWidth, sProp.m_nHeight));}}
DockWidget
-
设计思路
- 由于整个Nest框架是基于Qt开发的,所以主窗口类一定要能满足Qt相关特性(e.g:信号和槽机制)
- 支持窗口设计,如设置窗口初始大小,窗口标题,窗口图标等
- 支持可扩展,能够根据不同应用场景进行对应的继承扩展
-
实现
- 设计一个名为
DockWidget的类,此类继承于QDockWidget,使其满足Qt停靠窗口相关功能和特性。 - 设计一个名为
clearWidget方法,用于清空DockWidget内容。 - 设计一个名为
refreshWidget方法,用于刷新DockWidget内容。
- 设计一个名为
-
代码
DockWidget.h namespace NestUI {class NESTUI_API DockWidget : public QDockWidget{Q_OBJECTpublic:DockWidget(QWidget* parent = nullptr);~DockWidget();public:/// @brief 清空DockWidget内容virtual void clearWidget() = 0;/// @brief 刷新DockWidgetvirtual void refreshWidget() = 0;};}
DockWidgetManager
在框架中,我希望有一个对象能管理应用程序主窗口中的所有停靠窗口,且能够提供相关增删改查的方法。
-
功能设计
- 这个类的对象在应用程序主窗口生命周期内当前仅存在一个,因此我们可以使用单例模式设计这个类。
- 提供相关增删改查的方法。
-
实现
- 设计一个名为
DockWidgetManager的类,使用单例模式设计。 - 在类中定义一个
QMap类型的成员变量,实现DockWidget对应的窗口标题与对应的DockWidget对象对应。
- 设计一个名为
-
代码
DockWidgetManager.h namespace NestUI {/// @brief DockWidget窗口管理类class NESTUI_API DockWidgetManager{public:/// @brief 获取当前DockManager/// @returnstatic DockWidgetManager* GetDockManager(QMainWindow* mainWindow);/// @brief 添加DockWidget/// @param STitle DockWidget对应的窗口标题/// @param dockWidgetvoid AddDockWidget(const QString& STitle, QDockWidget* dockWidget, Qt::DockWidgetArea area);/// @brief 获取DockWidget/// @param STitle STitle DockWidget对应的窗口标题/// @returnQDockWidget* GetDockWidget(const QString& STitle);/// @brief 移除DockWidget/// @param STitle DockWidget对应的窗口标题void RemoveDockWidget(const QString& STitle);/// @brief 获取当前主窗口中的dockWidget个数/// @returnint GetDockWidgetNum() const { return m_DockWidgetMap.size(); }protected:DockWidgetManager(QMainWindow* mainWindow);~DockWidgetManager();private:/// @brief DockWidget窗口管理单例: 程序运行时,每个主窗口当且只能有一个DockManager存在static DockWidgetManager* s_Instance;QMainWindow* m_mainWindow; //应用程序主窗口//dockWidget MapQMap<QString, QDockWidget*> m_DockWidgetMap;};}//DockWidgetManager.cppnamespace NestUI {DockWidgetManager* DockWidgetManager::s_Instance = nullptr;DockWidgetManager::DockWidgetManager(QMainWindow* mainWindow){m_mainWindow = mainWindow;}DockWidgetManager::~DockWidgetManager(){m_mainWindow = nullptr;}DockWidgetManager* DockWidgetManager::GetDockManager(QMainWindow* mainWindow){// FIXED: 在此处插入 return 语句s_Instance = new DockWidgetManager(mainWindow);return s_Instance;}void DockWidgetManager::AddDockWidget(const QString& STitle, QDockWidget* dockWidget, Qt::DockWidgetArea area){m_DockWidgetMap.insert(STitle, dockWidget);m_mainWindow->addDockWidget(area, dockWidget);}QDockWidget* DockWidgetManager::GetDockWidget(const QString& STitle){if (m_DockWidgetMap.contains(STitle) == true){return m_DockWidgetMap[STitle];}return nullptr;}void DockWidgetManager::RemoveDockWidget(const QString& STitle){if (m_DockWidgetMap.contains(STitle) == true){m_mainWindow->removeDockWidget(m_DockWidgetMap[STitle]);m_DockWidgetMap.remove(STitle);}}}
测试
为了检测当前程序设计的可用性,在Example项目中,修改了main.cpp文件中的代码:
int main(int argc, char* argv[]){ NestApp::Application app(argc, argv);
NestUI::MainWindow* pMainWindow = new NestUI::MainWindow; app.SetMainWindow(pMainWindow); app.Run();
return app.exec();}- 运行效果
从图上可以看到,最简单的MainWindow成功显示,大功告成~
Reference
Nest开发笔记-NestUI v0.1.0
https://jerryym.github.io/posts/nest/nestui/nest开发笔记-nestui-v010/