【问题标题】:How to test if a control is a RichEdit control如何测试控件是否为 RichEdit 控件
【发布时间】:2010-02-19 08:42:23
【问题描述】:

Delphi 中的大多数 TWinControl 后代都有一个覆盖方法 CreateParams 来定义它的子类,例如:'EDIT'、'COMBOBOX'、'BUTTON'、'RICHEDIT' 等。

CreateSubClass(Params, 'EDIT');
CreateSubClass(Params, 'COMBOBOX');
CreateSubClass(Params, 'BUTTON');

Delphi 有很多丰富的编辑控件,包括来自第三方供应商的控件。所有这些控件都是 RichEdit 的子类。

我想知道是否有一种方法可以通过测试 CreateParams 中定义的 SubClass 来测试控件是否为 RichEdit,而不管它的原始供应商是什么?

【问题讨论】:

    标签: delphi richedit


    【解决方案1】:

    使用 Win32 API GetClassName() 或 RealGetWindowClass() 函数(请参阅 What makes RealGetWindowClass so much more real than GetClassName? 了解它们之间的区别),然后检查可用的各种 RichEdit 类名称的结果:

    • 'RICHEDIT' (1.0)
    • 'RICHEDIT20A' 或 'RICHEDIT20W' (2.x+)
    • 'RICHEDIT50W' (4.1)
    • 'TRichEdit'(VCL 封装)
    • 对于其他 3rd 方包装器以此类推

    【讨论】:

    • 我在 Windows.pas 中找不到 GetWindowClass。我正在使用 Delphi 2010。
    • 我认为假设您可以访问传递给 CreateSubClass 的“ControlClassName”,这将起作用。
    • 那么我该如何访问它呢?我在单元 windows.pas 中找不到 GetWindowClass
    • 我尝试 GetClassName 但它返回控件的 Delphi 类名。例如,它为 TRichEdit 控件返回“TRichEdit”,而不是 Remy Lebeau 提到的“RICHEDIT”、“RICHEDIT20A”或“RICHEDIT20W”。
    • @MtwStark:我知道的唯一方法是对2.0中失败的控件执行3.0操作,看看会发生什么
    【解决方案2】:

    感谢所有反馈。我认为没有办法获得 TWinControl 的 windows 类名。

    这是从 JamesB 的版本修改而来的另一个 IsRichEdit 版本:

    type TWinControlAccess = class(TWinControl);
    
    function IsRichEdit(C: TWinControl): boolean;
    
    const A: array[0..8] of string = (
               'RICHEDIT',
               'RICHEDIT20A', 'RICHEDIT20W',
               'RICHEDIT30A', 'RICHEDIT30W',
               'RICHEDIT41A', 'RICHEDIT41W',
               'RICHEDIT50A', 'RICHEDIT50W'
              );
    
    var Info: TWNDClass;
        p: pointer;
        s: string;
    begin
      p := TWinControlAccess(C).DefWndProc;
    
      Result := False;
    
      for s in A do begin
        if GetClassInfo(HInstance, PChar(s), Info) and (Info.lpfnWndProc = p) then begin
          Result := True;
          Break;
        end;
      end;
    end;
    

    如果 Windows 有更新版本的 RichEdit 类,我们可能会修改数组 A。

    另一个可能但有风险的解决方案是我只检查控件的 VCL 类名称是否包含“RichEdit”字符串,因为来自 Delphi 的几乎丰富的编辑 VCL 类或第三方供应商以这种方式命名控件。

    【讨论】:

      【解决方案3】:

      我错过了什么吗?是不是单纯的测试案例:

      if (MyControl is TRichEdit)
      

      或

      if (MyControl is TCustomRichEdit)
      

      【讨论】:

      • 这些是 Delphi 的 VCL 丰富的编辑控件。有 TcxRichEdit、TRxRichEdit 等等……
      • 这仅适用于从 T(Custom)RichEdit 派生的控件。它不适用于从 TWinControl 或 TCustomControl 派生的控件。
      • 是的,但是在您的问题中,您说:“Delphi 有很多丰富的编辑控件,包括来自第三方供应商的控件。所有这些控件都是 RichEdit 的子类。”如果它们是 TRichEdit 的子类,则 is 测试有效。
      • @_J_:不,它没有,在这种情况下的子类化与Delphi的继承无关。
      • cxControls 继承自 TcxControl,而 TcxControl 又来自 TCustomControl,所以这对那些不起作用。
      【解决方案4】:

      你可以使用

       function GetClassInfo(hInstance: HINST; lpClassName: PChar;  var lpWndClass: TWndClass): BOOL;
      

      我认为这就是雷米想要做的。

      类似:

      Function IsRichEdit(MyControl : TWinControl):Boolean;
      var 
          Info : TWNDClass;
      begin
          Result := False;
          if GetClassInfo(HInstance,PCHAR('RICHEDIT'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc) then 
              Result := True
          else if GetClassInfo(HInstance,PCHAR('RICHEDIT20A'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc)  then 
              Result := True
          else if GetClassInfo(HInstance,PCHAR('RICHEDIT30A'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc)  then 
              Result := True
          else if GetClassInfo(HInstance,PCHAR('RICHEDIT41A'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc)  then 
              Result := True
          else if GetClassInfo(HInstance,PCHAR('RICHEDIT50A'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc)  then 
              Result := True
      end;
      

      如果您使用的是 Delphi > 2007,那么您可能还需要测试“W”(unicode)版本,例如“RICHEDIT20W”

      编辑:添加 Info.WndProc 测试以匹配控件。

      奇怪的是,这对 cxControls 不起作用,因为 cxRichEdit 不是使用富编辑窗口的控件(它是一个包含,因此您需要传递 cxControl.InnerControl 以使其返回 true)。

      编辑除了创建的第一个 Richedit 控件外,我无法让它工作。

      【讨论】:

      • 差不多。除了您的函数将为您传递给它的 any 控件返回 True,只要您的应用程序为这些类之一创建了子类。 GetClassInfo 的第一个参数应该是应用程序实例(HInstance,或系统类的 0),而不是控件的句柄。正确的测试可能是:如果 GetClassInfo(HInstance, 'RICHEDIT', Info) and (Info.lpfnWndProc = THackWinControl(MyControl).DefWndProc) then ...
      • 您的代码有效。这是测试控件是否为富编辑的唯一方法吗? RichEdit 窗口类似乎很少(例如:RICHEDIT、RICHEDIT20A、RICHEDIT20W、...)。你知道他们有多少吗?无论如何要返回 TWinControl 实例的窗口类名吗?然后我可以检查窗口类名是否包含“RICHEDIT”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-16
      • 1970-01-01
      • 2013-12-20
      • 2015-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多