You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi XE7填充22个TComboBox耗时超4秒,求性能优化方案

优化Delphi XE7中TComboBox批量填充的性能问题

我们的应用基于Windows 10系统,采用Delphi XE7开发,窗体上包含26个TComboBox。从文件读取数据填充这些ComboBox列表时,耗时超过4秒,列表最大条目数约为800项。通过Debuginfo过程记录的各阶段耗时日志如下:

  • 22:11:10.179,开始填充数字列表
  • 22:11:10.180,开始清空数字列表
  • 22:11:10.182,结束清空数字列表
  • 22:11:10.183,开始解析数字列表
  • 22:11:10.536,结束解析数字列表
  • 22:11:10.536,开始复制数字列表
  • 22:11:15.667,结束复制数字列表
  • 22:11:15.668,结束填充数字列表

相关代码如下:

procedure TForm1.fill_digital_lists(whserch:string; dg:byte);
var xdr:integer; filltxt:string;
begin
  with work_cfg do
  begin
    debuginfo(wavepath,formatdatetime('hh:nn:ss.zzz',now)+', Start Fill Digital List');
    if totdig>0 then
    begin
      debuginfo(wavepath,formatdatetime('hh:nn:ss.zzz',now)+', Start Clear Digital List');
      brk1.Items.Clear;
      brk2.Items.Clear;
      brk3.Items.Clear;
      brk4.Items.Clear;
      evt1.Items.Clear;
      evt2.Items.Clear;
      evt3.Items.Clear;
      evt4.Items.Clear;
      evt5.Items.Clear;
      evt6.Items.Clear;
      evt7.Items.Clear;
      evt8.Items.Clear;
      evt9.Items.Clear;
      evt10.Items.Clear;
      evt11.Items.Clear;
      evt12.Items.Clear;
      evt13.Items.Clear;
      evt14.Items.Clear;
      evt15.Items.Clear;
      evt16.Items.Clear;
      evt17.Items.Clear;
      evt18.Items.Clear;
      evt19.Items.Clear;
      evt20.Items.Clear;
      evt21.Items.Clear;
      evt22.Items.Clear;
      debuginfo(wavepath,formatdatetime('hh:nn:ss.zzz',now)+', End Clear Digital List');
      debuginfo(wavepath,formatdatetime('hh:nn:ss.zzz',now)+', Start Parse Digital List');
      for xdr:=1 to totdig do
      begin
        if ansipos('SPARE',ansiuppercase(digitl_chans[xdr]))=0 then
        begin
          filltxt:='';
          if (dg=1) and (length(whserch)>0) then
          begin
            if (ansipos(ansiuppercase(whserch),ansiuppercase(digitl_chans[xdr]))>0) then filltxt:=digitl_chans[xdr]
          end else filltxt:=digitl_chans[xdr];
          if length(filltxt)>0 then brk1.Items.Add(filltxt);
        end;
      end;
      debuginfo(wavepath,formatdatetime('hh:nn:ss.zzz',now)+', End Parse Digital List');
      debuginfo(wavepath,formatdatetime('hh:nn:ss.zzz',now)+', Start Copy Digital List');
      brk2.Items:=brk1.Items;
      brk3.Items:=brk1.Items;
      brk4.Items:=brk1.Items;
      evt1.Items:=brk1.Items;
      evt2.Items:=brk1.Items;
      evt3.Items:=brk1.Items;
      evt4.Items:=brk1.Items;
      evt5.Items:=brk1.Items;
      evt6.Items:=brk1.Items;
      evt7.Items:=brk1.Items;
      evt8.Items:=brk1.Items;
      evt9.Items:=brk1.Items;
      evt10.Items:=brk1.Items;
      evt11.Items:=brk1.Items;
      evt12.Items:=brk1.Items;
      evt13.Items:=brk1.Items;
      evt14.Items:=brk1.Items;
      evt15.Items:=brk1.Items;
      evt16.Items:=brk1.Items;
      evt17.Items:=brk1.Items;
      evt18.Items:=brk1.Items;
      evt19.Items:=brk1.Items;
      evt20.Items:=brk1.Items;
      evt21.Items:=brk1.Items;
      evt22.Items:=brk1.Items;
      debuginfo(wavepath,formatdatetime('hh:nn:ss.zzz',now)+', End Copy Digital List');
    end;
    debuginfo(wavepath,formatdatetime('hh:nn:ss.zzz',now)+', End Fill Digital List');
  end;
end;

优化建议

1. 解决核心耗时:优化列表复制逻辑

从日志可见,复制数字列表阶段耗时超过5秒,是性能瓶颈。当前直接赋值Items属性会触发每个ComboBox的多次重绘和冗余内存操作,可替换为:

  • 使用Assign方法批量赋值:brk2.Items.Assign(brk1.Items);,该方法内部做了批量处理,减少事件触发次数。
  • 提前创建共享TStringList,填充后统一分配给所有ComboBox(若后续需单独修改某ComboBox列表,需先复制实例避免互相影响):
    var SharedList: TStringList;
    begin
      SharedList := TStringList.Create;
      try
        // 将解析后的内容先存入SharedList
        for xdr:=1 to totdig do
        begin
          // ...原有解析逻辑,将符合条件的内容Add到SharedList
        end;
        // 统一分配给所有ComboBox
        brk1.Items.Assign(SharedList);
        brk2.Items.Assign(SharedList);
        // ...其他ComboBox依次处理
      finally
        SharedList.Free;
      end;
    end;
    

2. 减少UI重绘开销

在清空、填充ComboBox时,临时禁用控件重绘,避免每次操作都触发界面刷新:

// 批量禁用重绘
brk1.Perform(WM_SETREDRAW, 0, 0);
brk2.Perform(WM_SETREDRAW, 0, 0);
// ...其他ComboBox依次执行

// 执行清空或填充操作
brk1.Items.Clear;
brk2.Items.Clear;
// ...

// 恢复重绘并刷新界面
brk1.Perform(WM_SETREDRAW, 1, 0);
brk2.Perform(WM_SETREDRAW, 1, 0);
brk1.Invalidate;
brk2.Invalidate;
// ...其他ComboBox依次执行

3. 优化字符串解析效率

解析阶段的字符串处理可减少重复计算:

  • 提前转换搜索关键词为大写,避免循环内重复调用AnsiUpperCase:
    var UpperWhSerch: string;
    begin
      UpperWhSerch := AnsiUpperCase(whserch);
      brk1.Items.BeginUpdate;
      try
        for xdr:=1 to totdig do
        begin
          var UpperChan := AnsiUpperCase(digitl_chans[xdr]);
          if AnsiPos('SPARE', UpperChan) = 0 then
          begin
            if (dg=1) and (Length(whserch)>0) then
            begin
              if AnsiPos(UpperWhSerch, UpperChan) > 0 then
                brk1.Items.Add(digitl_chans[xdr]);
            end
            else
              brk1.Items.Add(digitl_chans[xdr]);
          end;
        end;
      finally
        brk1.Items.EndUpdate;
      end;
    end;
    
  • 用BeginUpdate和EndUpdate包裹Add操作,避免每次添加条目都触发重绘。

4. 简化清空操作

将所有ComboBox存入数组,通过循环批量处理清空和重绘控制,减少重复代码:

var Combos: array of TComboBox;
begin
  SetLength(Combos, 22);
  Combos[0] := brk1;
  Combos[1] := brk2;
  Combos[2] := brk3;
  // ...依次添加其他ComboBox到数组

  // 禁用重绘
  for var Combo in Combos do
    Combo.Perform(WM_SETREDRAW, 0, 0);
  
  // 批量清空
  for var Combo in Combos do
    Combo.Items.Clear;
  
  // 恢复重绘
  for var Combo in Combos do
  begin
    Combo.Perform(WM_SETREDRAW, 1, 0);
    Combo.Invalidate;
  end;
end;

内容的提问来源于stack exchange,提问作者MRoth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 19:27:36