204 lines
6.3 KiB
Markdown
204 lines
6.3 KiB
Markdown
# DateVarSet 类分析与解决方案
|
|
|
|
## 一、类功能概述
|
|
|
|
`DateVarSet` 是一个用于日期变量设置的 Qt 界面类,继承自 `QWidget` 和 `ParaSettingUI`。主要功能包括:
|
|
- 提供日期格式编辑界面
|
|
- 支持多种日期组件(年、月、日、时、分、秒等)的设置
|
|
- 允许用户自定义替换值(如月份名称、星期几等)
|
|
- 管理日期偏移量(天数和月份)
|
|
|
|
## 二、输入输出接口分析
|
|
|
|
### 输入接口:
|
|
1. `void edit(PicDateItem* item)` - 编辑指定的日期项目
|
|
2. `void setDateModel(const DateItemModel& model)` - 设置日期模型数据
|
|
3. `void bindSysPara(SysPara *sysPara)` - 绑定系统参数
|
|
4. `void bindTxTEdit(QTextEdit* textEdit)` - 绑定文本编辑器
|
|
|
|
### 输出接口:
|
|
1. `DateItemModel dateModel()` - 获取当前日期模型
|
|
2. `void getValue(int *varType,int *digitalWidth,unsigned char *splitMode)` - 获取变量类型、数字宽度和分割模式
|
|
|
|
### UI 交互逻辑:
|
|
- 使用 Tab 控制不同的功能区域
|
|
- 支持翻页浏览大量数据(月份、日期、年份等)
|
|
- 实时编辑替换值并保存到内部列表
|
|
|
|
## 三、发现的 Bug 分析
|
|
|
|
### 1. 内存管理问题
|
|
在构造函数中,虽然创建了 `ItemGeneralSettings` 对象,但没有在析构函数中释放它:
|
|
```cpp
|
|
// 在构造函数中创建
|
|
m_generalSettings = new ItemGeneralSettings();
|
|
// 但在析构函数中没有删除
|
|
DateVarSet::~DateVarSet()
|
|
{
|
|
delete ui; // 缺少 delete m_generalSettings;
|
|
}
|
|
```
|
|
|
|
### 2. 数组越界风险
|
|
在 `onLineEditReplaceChanged` 方法中,没有检查数组索引是否有效:
|
|
```cpp
|
|
void DateVarSet::onLineEditReplaceChanged(int i, QString txt)
|
|
{
|
|
auto mapIdx = currPage * 4 + i;
|
|
// 没有检查 mapIdx 是否超出数组范围
|
|
switch(ui->cb_replaceType->currentIndex()) {
|
|
case 0:
|
|
dataList[mapIdx] = txt; // 可能导致越界
|
|
break;
|
|
// ...
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. 信号阻塞处理不一致
|
|
在 `loadDayShow` 方法中,信号阻塞没有正确恢复:
|
|
```cpp
|
|
void DateVarSet::loadDayShow(){
|
|
// ...
|
|
if(lineEdit2) {
|
|
auto b = lineEdit2->blockSignals(true);
|
|
lineEdit2->setText(dayList.at(i));
|
|
lineEdit2->blockSignals(false); // 直接设为false,而不是恢复原状态
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. 未使用的成员变量
|
|
`dataMap` 在 `DateItemModel` 中被标记为 "unused",但仍参与序列化操作。
|
|
|
|
### 5. 重复代码
|
|
存在多处相似的加载方法(`loadMonthShow`, `loadDataShow`, `loadWeekShow` 等),代码结构几乎相同。
|
|
|
|
### 6. 静态全局变量使用不当
|
|
使用了全局静态变量 `vartypeR` 和 `replaceValueMap`,这可能导致不同实例间的数据污染。
|
|
|
|
## 四、解决方案
|
|
|
|
### 1. 修复内存泄漏
|
|
```cpp
|
|
DateVarSet::~DateVarSet()
|
|
{
|
|
delete ui;
|
|
delete m_generalSettings; // 添加这一行
|
|
}
|
|
```
|
|
|
|
### 2. 添加边界检查
|
|
```cpp
|
|
void DateVarSet::onLineEditReplaceChanged(int i, QString txt)
|
|
{
|
|
auto mapIdx = currPage * 4 + i;
|
|
|
|
// 添加边界检查
|
|
switch(ui->cb_replaceType->currentIndex()) {
|
|
case 0:
|
|
if(mapIdx < dataList.size()) {
|
|
dataList[mapIdx] = txt;
|
|
}
|
|
break;
|
|
case 1:
|
|
if(mapIdx < weekList.size()) {
|
|
weekList[mapIdx] = txt;
|
|
}
|
|
break;
|
|
case 2:
|
|
if(mapIdx < monthList.size()) {
|
|
monthList[mapIdx] = txt;
|
|
}
|
|
break;
|
|
case 3:
|
|
if(mapIdx < yearList.size()) {
|
|
yearList[mapIdx] = txt;
|
|
}
|
|
break;
|
|
case 4:
|
|
if(mapIdx < dayList.size()) {
|
|
dayList[mapIdx] = txt;
|
|
}
|
|
break;
|
|
case 5:
|
|
if(mapIdx < hourList.size()) {
|
|
hourList[mapIdx] = txt;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. 修复信号阻塞
|
|
```cpp
|
|
void DateVarSet::loadDayShow(){
|
|
// ...
|
|
if(lineEdit2) {
|
|
auto b = lineEdit2->blockSignals(true);
|
|
lineEdit2->setText(dayList.at(i));
|
|
lineEdit2->blockSignals(b); // 恢复原始状态,不是硬编码为false
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. 重构重复代码
|
|
创建通用模板方法来替代重复的加载逻辑:
|
|
```cpp
|
|
template<typename T>
|
|
void DateVarSet::loadGenericShow(const QStringList& sourceList, int maxPages, int itemsPerPage = 4) {
|
|
if(currPage > maxPages) {
|
|
currPage = maxPages;
|
|
}
|
|
|
|
int objectIndex = 1;
|
|
for(int i = currPage * itemsPerPage; (i < (currPage + 1) * itemsPerPage) && (i < sourceList.size()); i++) {
|
|
QString strObject = QString("lineEditName") + QString::number(objectIndex);
|
|
QLineEdit *lineEdit = this->findChild<QLineEdit*>(strObject);
|
|
if(lineEdit) {
|
|
lineEdit->setText(QString::number(i + 1));
|
|
}
|
|
|
|
QString strObject2 = QString("lineEdit_Replace") + QString::number(objectIndex);
|
|
QLineEdit *lineEdit2 = this->findChild<QLineEdit*>(strObject2);
|
|
if(lineEdit2) {
|
|
auto b = lineEdit2->blockSignals(true);
|
|
lineEdit2->setText(sourceList.at(i));
|
|
lineEdit2->blockSignals(b);
|
|
}
|
|
objectIndex++;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5. 移除不必要的全局变量
|
|
将全局静态变量移入类中作为成员变量:
|
|
```cpp
|
|
private:
|
|
unsigned char m_varTypeR = 0x00;
|
|
QMap<int, QMap<int, QString>> m_replaceValueMap;
|
|
```
|
|
|
|
## 五、可移除的无用逻辑
|
|
|
|
根据要求,需要移除构造默认 `DateItemModel` 的逻辑。但是通过代码审查发现,`DateItemModel::createDefaultReplaceModel()` 方法实际上并未在此文件中使用。该方法存在于 `ViewModels.h` 中,但 `DateVarSet` 类并未调用它。
|
|
|
|
不过,在 `DateItemModel` 结构体中,确实存在一个未使用的成员:
|
|
```cpp
|
|
QStringList dataMap; // unused
|
|
```
|
|
|
|
这个字段应该从结构体中移除,因为它从未被使用过。
|
|
|
|
## 六、其他改进建议
|
|
|
|
1. **改进错误处理**:在 `edit` 方法中添加更详细的参数验证
|
|
2. **优化性能**:减少不必要的 UI 更新操作
|
|
3. **增强类型安全**:使用枚举代替魔法数字(如 `cb_replaceType` 的索引值)
|
|
4. **完善注释**:为复杂的业务逻辑添加详细注释
|
|
|
|
这些修改将提高代码的健壮性、可维护性和性能。
|
|
|
|
## 七、总结
|
|
|
|
`DateVarSet` 类存在多个潜在问题,主要包括内存泄漏、数组越界风险、代码重复和全局变量使用不当。通过上述解决方案可以显著改善代码质量,同时移除无用的 `dataMap` 字段可以简化数据结构。 |