使用 Thread 用 TStringList 中的项目填充 TComboBox

2024-01-09

我正在使用一个ComboBox显示许多项目的列表(不用担心,项目之间的差异允许通过AutoComplete :-).

该列表是在创建表单 (OnCreate事件),但为了使表单在填写时不会冻结,我添加了一个TThread执行填充TStringList然后将其分配给ComboBox.Items.

它可以工作,但是当显示表单时,它不会正确绘制,直到线程完成并且组合中的内容已经显示。难道不应该使用线程来保存这个吗?

这是我的代码: (目前它不是在 IDE 中编写的,因此可能存在拼写错误...)

type
  TLoadList = class(TThread)
  public
    constructor Create;
    destructor Destroy; override;
  private
    SL: TStrings;
    procedure UpdateCombo;
    procedure Execute; override;
  end;

implementation

uses uMain, HebNumFunc; //The main form unit

constructor TLoadList.Create;
begin
  FreeOnTerminate := True;
  SL := TStringList.Create;
  inherited Create(True);
end;

procedure TLoadList.UpdateCombo;
begin
  MainFrm.YListCombo.Items := SL;
end;

procedure TLoadList.Execute;
begin
  for var I: Integer := 1 to 6000 do SL.Add(HebNumber(I));  //HebNumber This is a function that converts the value of the number to a Hebrew alphabetic value
  Synchronize(UpdateCombo);
end;  

destructor TLoadList.Destroy;
begin
  SL.Free;
  inherited;
end;

HebNumber 函数在 HebNumFunc 单元中声明如下:

function HebNumber(const Number: Integer): string;

const
  Letters1: Array of String = ['','א','ב','ג','ד','ה','ו','ז','ח','ט'];
  Letters10: Array of String = ['','י','כ','ל','מ','נ','ס','ע','פ','צ'];
  Letters100: Array of String = ['','ק','ר','ש','ת','תק','תר','תש','תת','תתק'];

  function _ThousandsConv(const Value: Integer): string;
  var
    Input, Hundreds, Tens, Some: Integer;
  begin
    if Value <= 0 then Exit('');
    
    if Value = 1 then Exit(Format('%s'' ', [Letters1[Value]]));

    if Value in [2..9] then Exit(Format('%s"א ', [Letters1[Value]]));

    if Value >= 10 then
    begin
      Input := Value;
      Hundreds := Input div 100;
      Input := Input mod 100;
      Tens := Input div 10;
      Some := Input mod 10;
      Result := Format('%s%s%s"א ', [Letters100[Hundreds], Letters10[Tens], Letters1[Some]]);
    end;
  end;

var
  Input, Thousands, Hundreds, Tens, Some: Integer;
begin
  Input := Number;
  Thousands := Input div 1000;
  if Thousands > 999 then Exit('חריגה');

  Input := Input mod 1000;
  Hundreds := Input div 100;
  Input := Input mod 100;
  Tens := Input div 10;
  Some := Input mod 10;

  if (Thousands > 0) and (Hundreds + Tens + Some = 0) then
    Exit(Format('%sתתר', [_ThousandsConv(Thousands - 1)]));

  Result := Format('%s%s%s%s', [_ThousandsConv(Thousands),
    Letters100[Hundreds], Letters10[Tens], Letters1[Some]]);

  if Result.Contains('יה') then Exit(Result.Replace('יה', 'טו'));
  if Result.Contains('יו') then Result := Result.Replace('יו', 'טז');
end;

我在 OnCreate 事件中简单地这样调用它:

var
  LoadList: TLoadList;
begin
  LoadList := TLoadList.Create;
  LoadList.Start;
  {...}
end;

里面没有别的东西了OnCreate除了调用创建和运行线程之外,导致窗体着色延迟的事件。其中也没有执行任何额外的操作。


你的代码没有任何问题。向组合框添加 6000 个项目非常慢,并且可能会干扰窗体的初始绘制,因为向组合框添加项目也在主 (GUI) 线程中运行。

您不能在后台线程中移动该分配,因为使用 GUI 控件必须在主线程中完成。

您所看到的问题的发生是因为线程内的代码运行得非常快,并且在表单有机会正确绘制自身之前将与主线程同步。

有几种可能的解决方案:

  1. 由于后台线程中的代码运行速度很快,因此删除线程并直接在 ComboBox 中填充 ComboBoxOnCreate事件处理程序。

  2. 将代码移自OnCreate to the OnShow事件处理程序,在接近显示表单的时间运行代码。但是,此事件可以多次触发,因此您需要额外的布尔字段来填充组合框一次。

但是,这仍然不足以防止故障。为此,请添加一个Sleep()在线程内稍微减慢其执行速度,并给窗体一些时间来完成其初始绘制。然后你可以打电话Synchronize()来填充组合框。

您可能需要尝试睡眠时间,因为速度较慢的计算机将需要更多时间来完成窗体的绘制,但不要睡眠时间太长,因为在这种情况下用户将能够访问空的 ComboBox。

procedure MainFrm.FormShow(Sender: TObject);
begin
  if not FFilled then
    begin
      FFilled := True;
      TThread.CreateAnonymousThread(
        procedure
        var
          sl: TStringList;
        begin
          sl := TStringList.Create;
          try
            for var I: Integer := 1 to 6000 do
              sl.Add(HebNumber(I));
          
            // Sleep for some small amount of time before synchronizing
            // with the main thread to allow form to fully paint itself
            Sleep(100);

            TThread.Synchronize(nil,
              procedure
              begin
                YListCombo.Items := sl;
              end);
          finally
            sl.Free;
          end;
        end).Start;
    end;
end;

注意:我使用匿名线程来填充组合框,因为这种方法不需要创建额外的类,并且代码更简单。但是,如果您不愿意,则不必更改这部分代码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Thread 用 TStringList 中的项目填充 TComboBox 的相关文章

  • 如何在Delphi中显示Vista风格的气球提示?

    在输入验证时 我使用气球提示而不是消息框 我的问题是 在 Vista 上 它们具有带圆角的旧 XP 样式 而不是较新的矩形外观 我尝试使用 CreateWindowEx 创建它们并且tooltips class32或使用 SendMessa
  • Delphi中使用FindVCLWindow调用WinHelp32(WinXP Pro SP3 32bit)

    有什么问题吗 procedure TForm1 VCLHelpClick Sender TObject var Ctrl TWinControl begin Ctrl FindVCLWindow Mouse CursorPos if Ctr
  • 如何比较枚举类型集

    从某个时刻开始 我厌倦了编写设定条件 and or 因为对于更多的条件或更长的变量名 重新编写会变得笨拙且烦人 所以我开始写助手这样我就可以写ASet ContainsOne ceValue1 ceValue2 代替 ceValue1 in
  • 如何在Delphi中将对象方法作为参数传递,然后调用它?

    我担心这可能是一个有点愚蠢的问题 但这让我很难过 我正在寻找将对象的方法传递到过程中的最简单的方法 以便过程可以调用对象的方法 例如 超时后 或者可能在不同的线程中 所以基本上我想 捕获对对象方法的引用 将该引用传递给过程 使用该引用 从过
  • Delphi - Indy - 保存 GMail 草稿

    我一直在 Delphi 下使用 Indy 通过 gmail 帐户发送消息 使用 TIdSMTP 和 TIdMessage 组件 这绝对没问题 但是 我的客户请求将消息保存到 DRAFTS 文件夹 以便他在实际发送消息之前对 以编程方式创建的
  • 任何第三方都可以从我的项目加载嵌入式资源吗?

    请参考我的一篇之前的问题 https stackoverflow com questions 14681364 issues passing data from dll to application 我问的是如何从 DLL 加载已编译的资源
  • 使用 Delphi 读取 Excel 电子表格

    我需要使用 Delphi 2010 读取和写入 Excel 电子表格 没什么花哨的 只需读取和写入不同工作表上特定单元格和范围的值 需要在没有安装 Excel 的情况下工作并支持 Excel 2007 我看过的一些东西 我尝试过使用ADO
  • 似乎有时 Delphi 是区分大小写的 - “覆盖方法应该与祖先的大小写匹配”

    今天我遇到了一个 奇怪 的提示 覆盖方法 xxxx 应匹配祖先 yyyy 的大小写 解决方案是完全按照祖先中的方式声明方法名称 我相信这是自 Delphi Net 编译器以来编译器中保留的东西 与祖先中完全相同的方法声明方法使编译器 沉默
  • (发件人:TObject)

    发件人 TObject 是什么意思 如 procedure TForm1 Button1Click Sender TObject var s Integer begin end Sender 是对触发事件的组件的引用 在这种情况下 Send
  • 如何修复这个 delphi 7 编译错误 - “重复资源”

    我正在尝试编译我继承的 Delphi 7 项目 但收到此错误 错误 警告 重复资源 错误 类型 2 位图 ID 编辑 错误 文件 C 路径缩短 common CRGrid res 资源已保留 文件 c common raptree RES
  • 在网格上拖动时拖动图像更改

    我正在 StartDrag 上创建自定义 DragObject 的实例 procedure TForm1 GridStartDrag Sender TObject var DragObject TDragObject begin DragO
  • Delphi 应用程序被 Google Chrome 视为“危险”

    我经常用Delphi 2009制作数学软件 并将其发布在我的网站上 然而 去年左右 Google Chrome 开始认为我的一小部分 但数量不断增加 EXE 是 有害的 并且 Google Chrome 拒绝下载它们 例如 今天我编写了一个
  • 通过“修改日期”确定文件夹中的哪个文件是最新的?

    我需要扫描特定文件夹中的最新文件 基本上检查修改日期以查看哪个是最新的 但请记住这些文件具有随机名称 这是我到目前为止得到的 procedure TForm1 Button1Click Sender TObject begin ftp Ho
  • 新编译的应用程序需要 UAC/elevation?

    我有一个系统 我将其设置为普通的 UAC 并在我的 delphi 环境中编译名为 ka exe 的项目 并为其创建一个 installshield 项目 设置完毕 一切顺利 但每当我开始我的程序时 它都需要提升 而我不知道为什么 为了确保
  • Soap Delphi 客户端因 1MB 调用超时而结束

    我们正在开发 SOAP Web 服务 Apache PHP 所有小规模调用都运行良好 但对于 1Mb 的 Soap 调用 HTTPS 调用大小为 1MB 我们的 Delphi Soap 客户端在除一台 PC 之外的所有 PC 上都因超时而停
  • Delphi 是否在构造对象之前分配变量?

    Delphi 是否在对象完全构造之前分配实例变量 换句话说 给定一个变量 var customer TCustomer nil 然后我们构造一个客户并将其分配给变量 customer TCustomer Create 有没有可能custom
  • 什么是代码页 0?

    我正在使用Delphi函数 StringCodePage 我在 COM 函数 Acrobat Annotation getContents 请参阅我的其他帖子 返回的字符串上调用它 它返回 0 0是什么 安西 代码页 0 是 CP ACP
  • Delphi:如何计算大文件的 SHA 哈希值

    您好 我需要生成 5 Gig 文件的 SHA 您知道有一个非基于字符串的 Delphi 库可以做到这一点吗 你应该使用DCPcrypt v2 http www cityinthesky co uk cryptography html读取缓冲
  • 如何为每个线程自动全局初始化/取消初始化某些内容?

    我有一个单位initialization and finalization部分 该单元包含一个复杂的对象 该对象在initialization并毁于finalization 但是 该对象还包含一个 ADO 连接 这使得跨线程使用它时出现问题
  • delphi专家中的第三方依赖

    我正在编写一个delphi ide Expert 带有一些第三方依赖项 视觉控件 我的问题是当这个专家将安装在目标机器上时 这台电脑是否也需要安装这些第三方组件 或者组件是embeded在生成的 bpl 内部 它们将依赖于您放置在包的 re

随机推荐