Delphi cxgrid设置OnFocusedRecordChanged 事件导致内存泄露.

设计界面:

image

 需求说明:

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''';    //正确

 

image

 

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

image

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

1772176322308

 报内存泄露了!这是好事,起码有了解决问题的大致方向了.

问题分析:

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;      //恢复事件关联

结果完美解决问题.

test

 

posted @ 2026-02-27 15:34  一曲轻扬  阅读(10)  评论(0)    收藏  举报