Delphi cxgrid设置OnFocusedRecordChanged 事件导致内存泄露.
设计界面:

需求说明:
1.上面是订单总表,下面是订单明细,
2.总表gridview设置了OnFocusedRecordChanged 事件,即当用户选择总表中的记录时,下面会显示出此订单下的所有明细
3.日期定位可以让用户快速的设置筛选日期区间
实现过程:
一.以下代码实现目标2.
procedure TFraModuleXSDD.GridViewFocusedRecordChanged(Sender: TcxCustomGridTableView; APrevFocusedRecord, AFocusedRecord: TcxCustomGridRecord; ANewItemRecordFocusingChanged: Boolean); begin //获取对应的订单明细 PODH := FDQuery1.FieldByName('单据编号').AsString; scGPPael3.Caption := '订单明细 >>> ' + PODH; FDQuery2.Filter := 'POID=' + FDQuery1.FieldByName('POID').AsString; FDQuery2.Filtered := True; GridView1.EditForm.CaptionMask := Mask + PODH; end;
二.以下代码实现目标3
procedure TFraModuleXSDD.DateRangeComBoxChange(Sender: TObject); begin //筛选日期区间 var FlieterStr := ''; var i := StrToInt(DateRangeComBox.Items[DateRangeComBox.ItemIndex].Detail); //ID保存在Detail属性中 var today := Date(); //今天 var yesterday := today - 1; //昨天 var dayBeforeYesterday := today - 2; //前天 case i of 1: //当天 begin FlieterStr := '[创建日期]=''' + FormatDateTime('yyyy-mm-dd', today) + ''''; end; 2: //昨天 begin FlieterStr := '[创建日期] = ''' + FormatDateTime('yyyy-mm-dd', yesterday) + ''''; end; 3: //前天 begin FlieterStr := '[创建日期] = ''' + FormatDateTime('yyyy-mm-dd', dayBeforeYesterday) + ''''; end; 4: //本周(周一至周日) begin // 计算本周一(固定以周一为一周的第一天) var daysFromMonday := (DayOfWeek(today) - 2 + 7) mod 7; // 周一=0, 周二=1, ..., 周日=6 var monday := today - daysFromMonday; var sunday := monday + 6; // 本周日 FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', monday) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', sunday) + ''''; end; 5: //上周(周一至周日) begin // 计算本周一 var daysFromMonday := (DayOfWeek(today) - 2 + 7) mod 7; var thisMonday := today - daysFromMonday; // 上周一 = 本周一 - 7 var lastMonday := thisMonday - 7; // 上周日 = 上周一 + 6 var lastSunday := lastMonday + 6; FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', lastMonday) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', lastSunday) + ''''; end; 6: //近七天 begin var sevenDaysAgo := today - 6; //包含今天,共7天 FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', sevenDaysAgo) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', today) + ''''; end; 7: //本月 begin var monthStart := EncodeDate(YearOf(today), MonthOf(today), 1); var monthEnd := EndOfTheMonth(today); FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', monthStart) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', monthEnd) + ''''; end; 8: //上月 begin var lastMonth := IncMonth(today, -1); var monthStart := EncodeDate(YearOf(lastMonth), MonthOf(lastMonth), 1); var monthEnd := EndOfTheMonth(lastMonth); FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', monthStart) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', monthEnd) + ''''; end; 9: //近两个月 begin var twoMonthsAgo := IncMonth(today, -2); FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', twoMonthsAgo) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', today) + ''''; end; 10: //近六个月 begin var sixMonthsAgo := IncMonth(today, -6); FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', sixMonthsAgo) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', today) + ''''; end; 11: //上半年 begin var year := YearOf(today); var half1Start := EncodeDate(year, 1, 1); var half1End := EncodeDate(year, 6, 30); FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', half1Start) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', half1End) + ''''; end; 12: //下半年 begin var year := YearOf(today); var half2Start := EncodeDate(year, 7, 1); var half2End := EncodeDate(year, 12, 31); FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', half2Start) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', half2End) + ''''; end; 13: //本年 begin var yearStart := EncodeDate(YearOf(today), 1, 1); var yearEnd := EncodeDate(YearOf(today), 12, 31); FlieterStr := '[创建日期] >= ''' + FormatDateTime('yyyy-mm-dd', yearStart) + ''' AND [创建日期] <= ''' + FormatDateTime('yyyy-mm-dd', yearEnd) + ''''; end; 14: //全部 begin FlieterStr := ''; //空字符串表示不筛选 end; end; //修正订单明细 scGPPael3.Caption := '订单明细 >>> 全部明细'; FDQuery2.Filter := ''; FDQuery1.Filter := FlieterStr; FDQuery1.Filtered := True; end;
但是在实际运行时发现,选择了日期区间后,上面无反应,而且还会报错.
后来发现是日期的过虑条件写错了,比如下面:
FlieterStr:='[创建日期]=#2026-02-27#'; //错误 FlieterStr:='[创建日期]=''2026-02-27'''; //正确

修正后又出现了新的问题:

当时我选择的日期是2026-02-27,总表中只有25和26两天的记录,所以理论上应该是返回空的数据集,但是它不仅把25/26两天的数据显示出来了,还给我报了一个错误.这就很难理解.更糟的是,当我正常关闭程序时,它又给我报了一个错误:

报内存泄露了!这是好事,起码有了解决问题的大致方向了.
问题分析:
1.在我没有进行日期定位操作前,可以正常关闭程序,且不报错.
2.在我进行日期定位操作后,程序报内存泄露.
所以问题的关键就在这个组合框COMBOX这里,整个单元上下,它只有一个change事件.
然后我从头到尾看了整个事件,大部分都在计算时间区间,起到实质性操作的只有这么几句:
//修正订单明细 scGPPael3.Caption := '订单明细 >>> 全部明细'; FDQuery2.Filter := ''; FDQuery1.Filter := FlieterStr; FDQuery1.Filtered := True;
我实在是没看出来这几句代码有什么问题.所以卡在这里很久很久....
以至于我后面又单独创建一个新项目,只有订单总表,没有订单明细表,结果这个程序一点问题也没有!
而新项目和现有项目的区别就在于 订单明细表! 这两个表的关联点就在于 总表gridview设置了OnFocusedRecordChanged 事件,这个事件里有对 订单明细表进行了操作.
所以接下来我要先把这个事件给切了,看看能不能解决问题:
GridView.OnFocusedRecordChanged := nil; //取消事件关联 //修正订单明细 scGPPael3.Caption := '订单明细 >>> 全部明细'; FDQuery2.Filter := ''; FDQuery1.Filter := FlieterStr; FDQuery1.Filtered := True; GridView.OnFocusedRecordChanged := GridViewFocusedRecordChanged; //恢复事件关联
结果完美解决问题.


浙公网安备 33010602011771号