delphi 对窗体中的控件进行遍历

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了delphi 对窗体中的控件进行遍历相关的知识,希望对你有一定的参考价值。

在一个窗体上放置若干个按钮、编辑框,写一个方法对窗体中的控件进行遍历,若为按钮,将其Caption设为“按钮”,若为编辑框,将其text设为“编辑框”。

参考技术A for i := 0 to Form1.ComponentCount-1 do
begin
if Form1.Components[i] is TButton then
TButton(Form1.Components[i]).Caption := '按钮'
else
if Form1.Components[i] is TEdit then
TEdit(Form1.Components[i]).Text := '编辑框';
end;本回答被提问者采纳
参考技术B 关注

C# Winform项目中多线程环境下, 如何跨线程对Window窗体控件进行安全访问?

[简介]
常用网名: 猪头三
出生日期: 1981.XX.XX
个人网站: http://www.x86asm.com
QQ交流: 643439947
编程生涯: 2001年~至今[共15年]
职业生涯: 13年
开发语言: C/C++、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python
开发工具: Visual Studio、Delphi、XCode、Eclipse
技能种类: 逆向 驱动 磁盘 文件
研发领域: Windows应用软件安全/Windows系统内核安全/Windows系统磁盘数据安全
项目经历: 磁盘性能优化/文件系统数据恢复/文件信息采集/敏感文件监测跟踪/网络安全检测

[序言]
由于我的主力编程语言不是C#, 因此很多细节都没有进行充分的研究. 但由于C#越来越优秀, 也越来越面向跨平台的优势发展. 因此我的项目都在有计划的移植到.NET环境. 在利用C#进行软件开发时, 最头痛的是多线程环境下进行跨线程对Window窗体控件进行安全访问和内容更新. 但这方面的资料非常少, 至少我没有见到国内有人总结出来, 就算有人总结出来, 也基本还停留在 new Thread + InvokeRequired + Invoke + Delegate模式上, 真的非常过时了, 而且开发起来也非常繁琐. 现在已经进化到.NET 4.0以上了, 经过几次软件的开发, 我个人觉得我是十分推荐.NET 4.0 以上的多线程模式. 下面我们就说说这方面的技术细节.

[首先按照下面的截图, 创建一个C# Winform项目]
1> 按钮 类名为: Bn_Start
2> 按钮 单击事件为: private void Bn_Start_Click(object sender, EventArgs e)...;
3> TextBox文本框 类名为: Tb_Text


[注意一个细节]

如果你的异步方法没有出现await逻辑处理, 可以使用await Task.Yield()来强制你的方法转换为异步上下文环境, 详细说明: https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.task.yield(v=vs.110).aspx

[下面我们开始写一个简单的多线程代码]

多线程代码功能: 循环 1000000 次 , 然后把计数显示在TextBox文本框.
private void Bn_Start_Click(object sender, EventArgs e)

    // 启动任务线程
    Task.Run(()=>
    
        for (int int_Index = 0; int_Index < 1000000; int_Index++)
        
            Tb_Text.Text = int_Index.ToString();
        
    );

    // 异步显示对话框
    MessageBox.Show("异步执行...");

// End Bn_Start_Click()

请尝试运行这段代码, 结果你会发现微软开发工具会提示, Tb_Text.Text = int_Index.ToString(); 涉及"对Windows窗体控件进行线程安全调用", 并给了如下的解决方案:https://msdn.microsoft.com/zh-cn/library/ms171728(v=vs.100).aspx 结果看到这篇文章, 我彻底蒙了. 还是.NET的过去式技术. 为什么不给出一个合理的Task模式下的跨线程访问Windows 窗体控件呢? 于是我只能阅读大量的MSDN文档. 终于找到了2个最合理的技术解决方案....
[方案1: Task + WindowsFormsSynchronizationContext + Send]
请看如下代码:
private SynchronizationContext mpr_sc_UIContext;
mpr_sc_UIContext = WindowsFormsSynchronizationContext.Current;

private void Bn_Start_Click(object sender, EventArgs e)

    // 启动任务线程
    Task.Run(()=>
    
        for (int int_Index = 0; int_Index < 1000000; int_Index++)
        
            mpr_sc_UIContext.Send( _ =>
            
                Tb_Text.Text = int_Index.ToString();
            , null);
        
    );

    // 异步显示对话框
    MessageBox.Show("异步执行...");

// End Bn_Start_Click()

经过上面的改进之后, 你会发现TextBox文本框里面内容能实时更新了, 但是由于 for 1000000次 这个运算消耗了大量的CPU时间片, 因此MessageBox.Show("异步执行...")这个代码没有能立即异步执行. 要过几秒钟才能弹出. 这样不是很完美, 那有没有更好的方案呢? 有的, 下面请看方案2.
[方案2: Task + TaskScheduler.FromCurrentSynchronizationContext + Task.Factory.StartNew]

请看如下代码:
private TaskScheduler mpr_ts_UIContext;
mpr_ts_UIContext = TaskScheduler.FromCurrentSynchronizationContext();

private void Bn_Start_Click(object sender, EventArgs e)

    // 启动任务线程
    Task.Run(()=>
    
        for (int int_Index = 0; int_Index < 1000000; int_Index++)
        
            var ts_Run = Task.Factory.StartNew(() =>
            
                Tb_Text.Text = int_Index.ToString();
            , CancellationToken.None, TaskCreationOptions.None, mpr_ts_UIContext);
            // 注意这里要同步等待Task.Factory.StartNew的任务结束
            ts_Run.Wait();
        
    );

    // 异步显示对话框
    MessageBox.Show("异步执行...");

// End Bn_Start_Click()

经过方案2的改进之后, 你会发现MessageBox.Show("异步执行...")这个代码能立即异步执行了. 是不是很爽.
[方案3: Task + TaskScheduler.FromCurrentSynchronizationContext + Task.Factory.StartNew + async + Unwrap]

请看如下代码:
private TaskScheduler mpr_ts_UIContext;
mpr_ts_UIContext = TaskScheduler.FromCurrentSynchronizationContext();

private void Bn_Start_Click(object sender, EventArgs e)

    // 启动任务线程
    Task.Run(()=>
    
        for (int int_Index = 0; int_Index < 1000000; int_Index++)
        
            var ts_Run = Task.Factory.StartNew(async () =>
            
                Tb_Text.Text = int_Index.ToString();
                
                // 模拟使用await xxxx ;
                await Task.Delay(100);

            , CancellationToken.None, TaskCreationOptions.None, mpr_ts_UIContext).Unwrap();

            // 注意这里要同步等待Task.Factory.StartNew().Unwrap()返回的任务(PS: 这个任务是async模式)
            ts_Run.Wait();
        
    );

    // 异步显示对话框
    MessageBox.Show("异步执行...");

// End Bn_Start_Click()

上面的方案3, 大家看到什么玄机了吗? 其实就是Task.Factory.StartNew任务支持async模式, 这样我们就可以在任务线程里面使用await进行同步了. 但是要注意, 如果在Task.Factory.StartNew任务下使用async模式, 那么必须使用Unwrap()来获取async模式的任务对象, 再进行Wait(), 就可以做到Task.Factory.StartNew任务的同步等待. 如果你不使用Unwrap(), 那么是无法等待的.
[总结]
这3个方案, 都是非常实用且国内还真没有人分享这个技术. 那就让我来填补这个空白吧. 技术是否有价值, 大家可以慢慢体会了...




以上是关于delphi 对窗体中的控件进行遍历的主要内容,如果未能解决你的问题,请参考以下文章

如何遍历winform窗体中的所有控件

窗体内元素遍历-通用方法(DevExpress 中BarManager的遍历)

delphi 7 superobject控件如何遍历子对象

在C#winform中如何遍历子窗体中所有的控件

在C#winform中如何遍历子窗体中有容器中的所有的控件

delphi 如何获取其它应用程序窗体中的所有控件句柄