# 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,有空我会回复

## 概述
+ 如果想在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:

+ bool/枚举类型编辑


+ 搜索过滤效果

## 如何使用
### 常规用法
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美化的抽象