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