# QTableEditFramework **Repository Path**: Apple_Code/QTableEditFramework ## Basic Information - **Project Name**: QTableEditFramework - **Description**: 一个基于Qt的模型视图二次封装的用于表格编辑的框架,能够极大提高表格开发工作的效率,减少大量重复代码 - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-06-19 - **Last Updated**: 2025-04-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README + 欢迎大家多多fork,提出改进意见,或者一起交流学习,使用问题可以加我v,有空我会回复 ![](https://cdn.nlark.com/yuque/0/2025/png/26918264/1745635912394-b76c5c1a-f659-47b0-9882-40c52345d13d.png) ## 概述 + 如果想在Qt中实现一个复杂的表格操作,一般通过QModel/View/Delegate来实现较为复杂的自定义效果,如果你的项目中有非常多的表格操作,例如后台有诸多数据库表,在大多数情况下,你需要开发大量结构重复的代码,一般是这样的 1. 继承`QAbstractTableModel`类,例如`MyModel:public QAbstractTableModel` 2. 实现`virtual setData(),virtual data() virtual rowCount()`等几个虚函数 3. 实现视图类`MyView`,处理鼠标单击双击等事件用于右键菜单 4. 实现自定义委托类`MyDelegate`以实现自定义的绘制效果 + 此时如果你有另外一个表格需要编辑,然后重复上面的步骤……我们总结一下: - 产生了大量结构重复的代码 - 这些重复代码往往只是类的名字不一样,在具体处理逻辑上,无非就是增/删/改/查,大多都是对这几类数据类型进行操作`string、int、float、bool`,主观觉得至少占了80%甚至更多以上的代码是重复的 ## 特性 + 基于以上问题,可以使用QTableEditFramework来解决 :::color3 - 自动识别所编辑单元格的数据类型,不同类型在编辑时会有对应编辑控件,目前支持 * **int**:`QSpinBox` * **float/double**:`QDoubleSpinBox` * **QString/string**:`QLineEdit` * **bool/enum(枚举):**`QComboBox` * **自定义类型JSON/XML:**`QPushButton`,双击弹出自定义插件 ::: :::color3 - 提供下拉框选择按哪一列搜索,可以对所有列进行过滤筛选,基于`QSortFilterProxyModel`实现,搜索/过滤效果丝滑,也支持高级搜索,此功能有bug暂时隐藏,后续会提交 ::: :::color3 - 某列数据是否可编辑自定义控制,默认显示绿点为可编辑,启用某列的禁用编辑功能后,此列不可编辑且绿色可编辑状态标志消失 ::: :::color3 - 最重要的一点,在大多数情况下,能极大减少工作量,统一代码风格 ::: :::color3 - 基于Qt5.15.2开发,测试也兼容Qt6.7.2版本,下边的示例为Qt6.7.2编译效果,基于Qt原生开发,不依赖任何第三方库,开箱即用 ::: ## 直接看看实际效果 + 插件编辑非格式化数据Json/Xml: ![](https://cdn.nlark.com/yuque/0/2025/png/26918264/1745626573661-13a30c04-b65c-4b69-a80b-37d7f64c6817.png) + bool/枚举类型编辑 ![](https://cdn.nlark.com/yuque/0/2025/png/26918264/1745626812456-bd1b596a-0d7c-4b32-ae87-c08236ddf6ae.png) ![](https://cdn.nlark.com/yuque/0/2025/png/26918264/1745626854252-fedc3b28-a903-49ca-830e-c803af01f110.png) + 搜索过滤效果 ![](https://cdn.nlark.com/yuque/0/2025/png/26918264/1745627048699-a269de73-5533-4778-aad4-4ff759907d03.png) ## 如何使用 ### 常规用法 1. 继承IModel ```cpp class CStudent public:IModel { public: enum ESex{ Eboy = 0x01, Egirls } void CStudent():IModel(3){ /*在此处进行 某列禁止编辑 枚举值与字符串映射配置 某列背景颜色配置 */ } QString name; int age; int team; ESex sex; QString getFieldNameByCol(int col){ switch(col){ case 0: return name; case 1: return age; case 2: return team; case 3: return sex; /*………………*/ } } /*实现以下2/3/4说的几个虚函数*/ } ``` 2. 实现读取列名字 ```cpp /** * @brief 根据列数获取字段名称 * @param col 列索引 * @return QString 根据列数获取的字段名称 */ virtual QString getFieldNameByCol(int col)=0; ``` 3. 实现根据列名字读取列数据 ```cpp /** * @brief 根据字段名称获取字段值 * @param name 字段名称 * @return QVariant 根据字段名称获取的字段值 */ virtual QVariant getFieldValueByFielddName(const QString& name) = 0; ``` 4. 实现根据列号设置单元格数据 ```cpp /** * @brief 根据列数设置字段值 * @param col 列索引 * @param value 要设置的字段值 */ virtual void setFieldValueByCol(int col, const QVariant& value) = 0; ``` 5. 使用`UiFilterTableView`来进行添加和显示数据 1. 值得说明的是,`UiFilterTableView`中封装了一个默认视图提供右键菜单,一个默认的代理来达到上述所说的效果,核心为代理类,此为一种参考实现方式,大家可以通过源码来重新实现,达到具体项目定制的效果 2. 至此已经可以进行显示、修改功能 ```cpp UiFilterTableView view; for(int i = 0; i < 50; ++i) { QSharedPointer stu; stu.name = QString("stu%1").arg(i); stu.age = i+10; stu.team = i; stu.sex = i%2 ? Eboy : Egirls; view.appendData(stu); } view.show(); ``` ### 高级用法 + 值得说明的是,以下变量都为IModel中的,所以以下实现最好放在构造函数中 ```cpp QMap> m_fieldValueMap; // 字段的值和描述的映射 QMap sexmap; sexmap.insert(static_cast(Eboy), "男生"); sexmap.insert(static_cast(Egirls), "女生"); m_fieldValueMap.insert(getFieldNameByCol(3), sexmap); ``` ```cpp QMap m_fieldEditableMap; //字段和是否允许编辑的映射 m_fieldEditableMap.insert(getFieldNameByCol(0), false);/*名字列禁止编辑*/ ``` ```cpp QMap m_backgroundField; //字段背景颜色 m_backgroundField.insert(getFieldNameByCol(0), "#ED1C24");/*名字列背景为红色*/ ``` #### 某列启用自定义插件编辑 + 先看下插件类实现 ```cpp #ifndef CTABLEEDITPLUGIN_H #define CTABLEEDITPLUGIN_H #include #include class CTableEditPlugin : public QWidget { Q_OBJECT public: virtual bool parseData(QString data) = 0; virtual QString readData() = 0; virtual bool checkData() { return true; } protected: explicit CTableEditPlugin(QWidget *parent = nullptr){} ~CTableEditPlugin(){} }; #if defined(__GNUC__) || defined(__clang__) #define WEAK_ATTR __attribute__((weak)) #elif defined(_MSC_VER) #define WEAK_ATTR __declspec(selectany) #else #define WEAK_ATTR #endif WEAK_ATTR CTableEditPlugin* createPlugin(const QString& name){} #endif // CTABLEEDITPLUGIN_H ``` + 使用流程: 1. 继承`CTableEditPlugin` ```cpp class MyPlugin : public CTableEditPlugin{ virtual bool parseData(QString data){ /*解析数据,设置到这个类的控件上*/ } virtual QString readData(){ /*将这个控件上的数据读取出来序列化为字符串返回,Imodel会调用 setFieldValueByCol函数将这个数据设置到模型中*/ } } ``` 2. 实现全局函数`CTableEditPlugin` ```cpp CTableEditPlugin* createPlugin(const QString& name){ if(name == "MyPlugin"){ return new MyPlugin; } else if(name == "****") { return new "****"; } /********/ } ``` 1. 启用插件编辑 ```cpp QMap m_enPluginEdit; //字段是否启用插件编辑 QMap m_fieldPluginMap; //插件名字 m_enPluginEdit.insert("详细配置", true); m_fieldPluginMap.insert("详细配置","MyPlugin"); ``` ## 结束: + 对列的读取目前还在使用数字,列顺序改变时会导致代码调整,后续计划使用枚举代替列,使用注册列形式,进行抽象,达到改变列序不用更改代码 + 对视图的批量操作,批量修改,批量选中,应提供右键菜单操作,目前项目中有相关实现,但是属于定制化,缺少相关抽象,后续升级 + 代码相关UI是原生的,缺少对UI美化的抽象