Delphi一共封装(超类化)了8种Windows基础控件和17种复杂控件

超类化源码:

procedure TWinControl.CreateSubClass(var Params: TCreateParams; ControlClassName: PChar);
const
  {CS_OWNDC标志,属于此窗口类的窗口实例都有自己的DC(称为私有DC) }
  {CS_CLASSDC标志,所有属于该类的窗口实例共享相同的DC(称为类DC).类DC有一些私有DC的优点,而更加节约内存}
  {CS_PARENTDC标志,属于这个类的窗口都使用它的父窗口的句柄。和CS_CLASSDC相似的是,多个窗口共享一个DC,不同的是,这多个窗口(虽然有父子关系并且共享DC)并不要求都属于同一个窗口类}
  {CS_GLOBALCLASS标志,是唯一一个针对类本身起作用而不是对单个窗口起作用的标志。}
  CS_OFF = CS_OWNDC or CS_CLASSDC or CS_PARENTDC or CS_GLOBALCLASS;
  {CS_HREDRAW和CS_VREDRAW标志表示当窗口的水平尺寸(宽度)改变的时候,重画整个窗口。按钮和滚动条都有这两种风格。}
  CS_ON = CS_VREDRAW or CS_HREDRAW;
var
  SaveInstance: THandle;
begin
  // 说是子类化,其实是超类化
  // http://www.cnblogs.com/findumars/p/4121704.html Delphi对Button的超类化
  // http://www.cnblogs.com/findumars/p/4680601.html 子类化是窗口实例级别的,超类化是在窗口类(WNDCLASS)级别的
  // http://www.cnblogs.com/sfqh/p/3384457.html 探索Win32系统之窗口类

  // important 两个参数:Windows类的风格,类名(Windows的内置类)
  // Creates a windowed control derived from an existing Windows window class.
  // CreateSubClass allows VCL controls to create registered Windows controls.
  // 问题:不明白,哪里创建新类了。回答:根据已有的Windows类,创建Windows控件,注意是控件,不是类。
  // 此单元没有调用此函数,但TButton,TEdit,TCombobox 等等都调用了它。

  if ControlClassName <> nil then // 如果类名不为空
    with Params do // 它是可变参数,结构体Params.WindowClass
    begin
      // 记录当前Windows类的句柄实例(其实是整个EXE模块的句柄)
      SaveInstance := WindowClass.hInstance;
      // API取得相关信息(第三个参数)。 失败返回0
      // 只有三次执行都失败(2个句柄,一个类名),条件才成立。也就是这个ControlClassName新类还没有在内存中注册过。
      if not GetClassInfo(HInstance, ControlClassName, WindowClass) and // API 取得信息填充,第一个参数是Application.Instance(全局变量),第二个参数是类名,第三个参数等待填充的结构,即Params.WindowClass
         not GetClassInfo(0, ControlClassName, WindowClass) and         //
         not GetClassInfo(MainInstance, ControlClassName, WindowClass)  // MainInstance就这一处,标识EXE文件的Instance(系统级全局变量)
      then
        // 根据句柄和名称得到WindowClass的所有信息,注意,有可能覆盖了原先的hInstance,所以要事先记录,事后赋值
        GetClassInfo(WindowClass.hInstance, ControlClassName, WindowClass); // API,第三个参数是Out
      // 一旦发现类名注册过了,就什么都不用做

      // 为了保险起见,除了EXE模块句柄不得不重新赋值以外,其它一切旧有记录信息从Windows内核中直接取出。连类名都有可能被改变。
      // fixme TButton调用了它,应该跟踪一下。
      WindowClass.hInstance := SaveInstance;
      // 改变风格标记,不希望自绘,并且窗口大小或位置改变后,就重绘整个窗口
      // 注意,TEdit等等都是直接继承自TWinControl,没有自绘句柄。
      WindowClass.style := WindowClass.style and not CS_OFF or CS_ON; // fixme 抛弃一切DC,准备使用Delphi体系的Canvas进行自绘。
      // 问题:执行以后,类名到底是TButton还是Button?
      // important 取到的信息,都通过Params.WindowClass传出去
    end;
end;

8种Windows基础控件:

"G:\Vcl\StdCtrls.pas"(1898,3):  CreateSubClass(Params, ‘EDIT‘);
"G:\Vcl\StdCtrls.pas"(2986,3):  CreateSubClass(Params, ‘COMBOBOX‘);
"G:\Vcl\StdCtrls.pas"(3512,3):  CreateSubClass(Params, ‘BUTTON‘); // TButton
"G:\Vcl\StdCtrls.pas"(3658,3):  CreateSubClass(Params, ‘BUTTON‘); // TCustomCheckBox
"G:\Vcl\StdCtrls.pas"(3783,3):  CreateSubClass(Params, ‘BUTTON‘); // TRadioButton
"G:\Vcl\StdCtrls.pas"(4369,3):  CreateSubClass(Params, ‘LISTBOX‘);
"G:\Vcl\StdCtrls.pas"(4783,3):  CreateSubClass(Params, ‘SCROLLBAR‘);
"G:\Vcl\StdCtrls.pas"(4984,3):  CreateSubClass(Params, ‘STATIC‘);

17种Windows复杂控件:

"G:\Vcl\ComCtrls.pas"(11434,3):  CreateSubClass(Params, ‘RICHEDIT‘);
"G:\Vcl\ComCtrls.pas"(4263,3):  CreateSubClass(Params, WC_TABCONTROL);
"G:\Vcl\ComCtrls.pas"(5604,3):  CreateSubClass(Params, STATUSCLASSNAME);
"G:\Vcl\ComCtrls.pas"(6268,3):  CreateSubClass(Params, WC_HEADER);
"G:\Vcl\ComCtrls.pas"(8410,3):  CreateSubClass(Params, WC_TREEVIEW);
"G:\Vcl\ComCtrls.pas"(10039,3):  CreateSubClass(Params, TRACKBAR_CLASS);
"G:\Vcl\ComCtrls.pas"(10376,3):  CreateSubClass(Params, PROGRESS_CLASS);
"G:\Vcl\ComCtrls.pas"(11856,3):  CreateSubClass(Params, UPDOWN_CLASS);
"G:\Vcl\ComCtrls.pas"(12181,3):  CreateSubClass(Params, HOTKEYCLASS);
"G:\Vcl\ComCtrls.pas"(13593,3):  CreateSubClass(Params, WC_LISTVIEW);
"G:\Vcl\ComCtrls.pas"(15775,3):  CreateSubClass(Params, ANIMATE_CLASS);
"G:\Vcl\ComCtrls.pas"(16837,3):  CreateSubClass(Params, TOOLBARCLASSNAME);
"G:\Vcl\ComCtrls.pas"(19840,3):  CreateSubClass(Params, REBARCLASSNAME);
"G:\Vcl\ComCtrls.pas"(21313,3):  CreateSubClass(Params, MONTHCAL_CLASS);
"G:\Vcl\ComCtrls.pas"(21421,3):  CreateSubClass(Params, DATETIMEPICK_CLASS);
"G:\Vcl\ComCtrls.pas"(21691,3):  CreateSubClass(Params, WC_PAGESCROLLER);
"G:\Vcl\ComCtrls.pas"(22175,3):  CreateSubClass(Params, WC_COMBOBOXEX);

本着任何技术都要烂熟于心的精神,把8种基础控件的代码贴上来,混个脸熟,以后再加上注释:

procedure TCustomEdit.CreateParams(var Params: TCreateParams);
const
  Passwords: array[Boolean] of DWORD = (0, ES_PASSWORD);
  ReadOnlys: array[Boolean] of DWORD = (0, ES_READONLY);
  CharCases: array[TEditCharCase] of DWORD = (0, ES_UPPERCASE, ES_LOWERCASE);
  HideSelections: array[Boolean] of DWORD = (ES_NOHIDESEL, 0);
  OEMConverts: array[Boolean] of DWORD = (0, ES_OEMCONVERT);
begin
  inherited CreateParams(Params);
  CreateSubClass(Params, ‘EDIT‘);
  with Params do
  begin
    Style := Style or (ES_AUTOHSCROLL or ES_AUTOVSCROLL) or
      BorderStyles[FBorderStyle] or Passwords[FPasswordChar <> #0] or
      ReadOnlys[FReadOnly] or CharCases[FCharCase] or
      HideSelections[FHideSelection] or OEMConverts[FOEMConvert];
    if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then
    begin
      Style := Style and not WS_BORDER;
      ExStyle := ExStyle or WS_EX_CLIENTEDGE;
    end;
  end;
end;

procedure TCustomComboBox.CreateParams(var Params: TCreateParams);
const
  ComboBoxStyles: array[TComboBoxStyle] of DWORD = (
    CBS_DROPDOWN, CBS_SIMPLE, CBS_DROPDOWNLIST,
    CBS_DROPDOWNLIST or CBS_OWNERDRAWFIXED,
    CBS_DROPDOWNLIST or CBS_OWNERDRAWVARIABLE);
  CharCases: array[TEditCharCase] of DWORD = (0, CBS_UPPERCASE, CBS_LOWERCASE);
  Sorts: array[Boolean] of DWORD = (0, CBS_SORT);
begin
  inherited CreateParams(Params);
  CreateSubClass(Params, ‘COMBOBOX‘);
  with Params do
    Style := Style or (WS_VSCROLL or CBS_HASSTRINGS or CBS_AUTOHSCROLL) or
      ComboBoxStyles[FStyle] or Sorts[FSorted] or CharCases[FCharCase];
end;

procedure TButton.CreateParams(var Params: TCreateParams);
const
  ButtonStyles: array[Boolean] of DWORD = (BS_PUSHBUTTON, BS_DEFPUSHBUTTON);
begin
  inherited CreateParams(Params);
  CreateSubClass(Params, ‘BUTTON‘);
  Params.Style := Params.Style or ButtonStyles[FDefault];
end;

procedure TCustomCheckBox.CreateParams(var Params: TCreateParams);
const
  Alignments: array[Boolean, TLeftRight] of DWORD =
    ((BS_LEFTTEXT, 0), (0, BS_LEFTTEXT));
begin
  inherited CreateParams(Params);
  CreateSubClass(Params, ‘BUTTON‘);
  with Params do
  begin
    Style := Style or BS_3STATE or
      Alignments[UseRightToLeftAlignment, FAlignment];
    WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW);
  end;
end;

procedure TRadioButton.CreateParams(var Params: TCreateParams);
const
  Alignments: array[Boolean, TLeftRight] of DWORD =
    ((BS_LEFTTEXT, 0), (0, BS_LEFTTEXT));
begin
  inherited CreateParams(Params);
  CreateSubClass(Params, ‘BUTTON‘);
  with Params do
    Style := Style or BS_RADIOBUTTON or
      Alignments[UseRightToLeftAlignment, FAlignment];
end;

procedure TCustomListBox.CreateParams(var Params: TCreateParams);
type
  PSelects = ^TSelects;
  TSelects = array[Boolean] of DWORD;
const
  Styles: array[TListBoxStyle] of DWORD =
    (0, LBS_OWNERDRAWFIXED, LBS_OWNERDRAWVARIABLE, LBS_OWNERDRAWFIXED,
     LBS_OWNERDRAWFIXED);
  Sorteds: array[Boolean] of DWORD = (0, LBS_SORT);
  MultiSelects: array[Boolean] of DWORD = (0, LBS_MULTIPLESEL);
  ExtendSelects: array[Boolean] of DWORD = (0, LBS_EXTENDEDSEL);
  IntegralHeights: array[Boolean] of DWORD = (LBS_NOINTEGRALHEIGHT, 0);
  MultiColumns: array[Boolean] of DWORD = (0, LBS_MULTICOLUMN);
  TabStops: array[Boolean] of DWORD = (0, LBS_USETABSTOPS);
  CSHREDRAW: array[Boolean] of DWORD = (CS_HREDRAW, 0);
  Data: array[Boolean] of DWORD = (LBS_HASSTRINGS, LBS_NODATA);
var
  Selects: PSelects;
begin
  inherited CreateParams(Params);
  CreateSubClass(Params, ‘LISTBOX‘);
  with Params do
  begin
    Selects := @MultiSelects;
    if FExtendedSelect then Selects := @ExtendSelects;
    Style := Style or (WS_HSCROLL or WS_VSCROLL or
      Data[Self.Style in [lbVirtual, lbVirtualOwnerDraw]] or
      LBS_NOTIFY) or Styles[FStyle] or Sorteds[FSorted] or
      Selects^[FMultiSelect] or IntegralHeights[FIntegralHeight] or
      MultiColumns[FColumns <> 0] or BorderStyles[FBorderStyle] or
      TabStops[FTabWidth <> 0];
    if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then
    begin
      Style := Style and not WS_BORDER;
      ExStyle := ExStyle or WS_EX_CLIENTEDGE;
    end;
    WindowClass.style := WindowClass.style and not (CSHREDRAW[UseRightToLeftAlignment] or CS_VREDRAW);
  end;
end;

procedure TScrollBar.CreateParams(var Params: TCreateParams);
const
  Kinds: array[TScrollBarKind] of DWORD = (SBS_HORZ, SBS_VERT);
begin
  inherited CreateParams(Params);
  CreateSubClass(Params, ‘SCROLLBAR‘);
  Params.Style := Params.Style or Kinds[FKind];
  if FKind = sbVertical then
    if not UseRightToLeftAlignment then
      Params.Style := Params.Style or SBS_RIGHTALIGN
    else
      Params.Style := Params.Style or SBS_LEFTALIGN;
  if NotRightToLeft then
    FRTLFactor := 1
  else
    FRTLFactor := -1;
end;

procedure TCustomStaticText.CreateParams(var Params: TCreateParams);
const
  Alignments: array[Boolean, TAlignment] of DWORD =
    ((SS_LEFT, SS_RIGHT, SS_CENTER), (SS_RIGHT, SS_LEFT, SS_CENTER));
  Borders: array[TStaticBorderStyle] of DWORD = (0, WS_BORDER, SS_SUNKEN);
begin
  inherited CreateParams(Params);
  CreateSubClass(Params, ‘STATIC‘);
  with Params do
  begin
    Style := Style or SS_NOTIFY or
      Alignments[UseRightToLeftAlignment, FAlignment] or Borders[FBorderStyle];
    if not FShowAccelChar then Style := Style or SS_NOPREFIX;
    WindowClass.style := WindowClass.style and not CS_VREDRAW;
  end;
end;

再看看RichEdit的封装代码:

procedure TCustomRichEdit.CreateParams(var Params: TCreateParams);
const
  RichEditModuleName = ‘RICHED32.DLL‘;
  HideScrollBars: array[Boolean] of DWORD = (ES_DISABLENOSCROLL, 0);
  HideSelections: array[Boolean] of DWORD = (ES_NOHIDESEL, 0);
begin
  if FRichEditModule = 0 then
  begin
    FRichEditModule := LoadLibrary(RichEditModuleName);
    if FRichEditModule <= HINSTANCE_ERROR then FRichEditModule := 0;
  end;
  inherited CreateParams(Params);
  CreateSubClass(Params, ‘RICHEDIT‘);
  with Params do
  begin
    Style := Style or HideScrollBars[FHideScrollBars] or
      HideSelections[HideSelection];
    WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW);
  end;
end;
时间: 2024-12-15 01:49:09

Delphi一共封装(超类化)了8种Windows基础控件和17种复杂控件的相关文章

子类化和超类化区别(介绍Windows的窗口、消息、子类化和超类化)(转)

原文地址:http://maqianli210.blog.sohu.com/75497589.html 这篇文章本来只是想介绍一下子类化和超类化这两个比较“生僻”的名词.为了叙述的完整性而讨论了Windows的窗口和消息,也简要讨论了进程和线程.子类化(Subclassing)和超类化(Superclassing)是伴随Windows窗口机制而产生的两个复用代码的方法.不要把“子类化.超类化”与面向对象语言中的派生类.基类混淆起来.“子类化.超类化”中的“类”是指Windows的窗口类. 0 运

窗口的子类化与超类化——子类化是窗口实例级别的,超类化是在窗口类(WNDCLASS)级别的

1. 子类化 理论:子类化是这样一种技术,它允许一个应用程序截获发往另一个窗口的消息.一个应用程序通过截获属于另一个窗口的消息,从而实现增加.监视或者修改那个窗口的缺省行为.子类化是用来改变或者扩展一个已存在的窗口的行为.而不用重新开发的有效途径.想要获得那些预定义控件窗口类(按钮控件.编辑控件.列表控件.下拉列表控件.静态控件和滚动条控件)的功能而又要修改它们的某些行为的一个便利的方法就是对它们进行子类化.例如,对于一个在对话框中的多行编辑框来说,当用户按下Enter键时,对话框会关闭.通过对

C++ 中超类化和子类化

超类化和子类化没有具体的代码,其实是一种编程技巧,在MFC和WTL中可以有不同的实现方法. 窗口子类化: 原理就是改变一个已创建窗口类的窗口过程函数.通过截获已创建窗口的消息,从而实现监视或修改已创建窗口类的行为属性.可以用来改变或者扩展一个已存在的窗口的行为,而不用重新开发.比如要获得那些预定义控件窗口类(按钮控件.编辑控件.列表控件.下 拉列表控件.静态控件和滚动条控件)的功能而又要修改它们的某些行为. 子类化的优点主要体现在以下两个方面:首先,它不需要创建新的窗口类,不需要了解一个窗口的窗

窗口的子类化与超类化

1. 子类化 改变一个已经存在的窗口实例的性质:消息处理与其他实例属性.在SDK编程范畴内,子类化就是改变一个窗口实例的窗口函数(通过GetWindowLong()和SetWindowLong()),子类化所要做的就是为某窗口实例编写新的窗口函数.其操作是在实例级别上进行的.在MFC中子类化的情况有所不同:所有MFC窗口有相同的窗口函数,由该窗口函数根据窗口句柄查找窗口实例,在把消息映射到该窗口类(class)得消息处理函数上.为了利用MFC的消息映射机制,不宜改变窗口函数(名),MFC也把子类

C++ 中超类化和子类化常用API

在windows平台上,使用C++实现子类化和超类化常用的API并不多,由于这些API函数的详解和使用方法,网上一大把.本文仅作为笔记,简单的记录一下. 子类化:SetWindowLong,GetWindowLong,CallWindowProc,FindWindowEx 超类化:GetClassInfoEx,RegisterClassEx,UnRegisterClass 以上函数在代码中的使用见<C++ 中超类化和子类化> VC中基于SDK编程的窗口子类化 VC中基于SDK编程的窗口子类化的

眼见为实(2):介绍Windows的窗口、消息、子类化和超类化

眼见为实(2):介绍Windows的窗口.消息.子类化和超类化 这篇文章本来只是想介绍一下子类化和超类化这两个比较"生僻"的名词.为了叙述的完整性而讨论了Windows的窗口和消息,也简要讨论了进程和线程.子类化(Subclassing)和超类化(Superclassing)是伴随Windows窗口机制而产生的两个复用代码的方法.不要把"子类化.超类化"与面向对象语言中的派生类.基类混淆起来."子类化.超类化"中的"类"是指W

窗口 超类化 子类化 HOOK

body { font-family: Bitstream Vera Sans Mono; font-size: 11pt; line-height: 1.5; } html, body { color: #000000; background-color: #C2E7C7; } h1 { font-size:1.5em; font-weight:bold; } h2 { font-size:1.4em; font-weight:bold; } h3 { font-size:1.3em; fon

FMX有两种消息处理的实现方式,一种是用TMessageManager来实现自定义的消息,另外一种象TEdit中的实现,直接声明消息方法

看FMX代码,发现有两种消息处理的实现方式,一种是用TMessageManager来实现自定义的消息,另外一种象TEdit中的实现,直接声明消息方法. 早前,看过文章说TMessageManager的用法,可用到的时候,又找不到,只好自己动手. 我的应用场景是这样: 当前的Frame弹出一个对话框Frame,当操作对话框的时候,想让当前的Frame跟着应响,让用户看到操作的结果,如下图,点大中小字体,后面的题目的字体会跟着变化: 参考fmx的代码,试着用消息机制实现了: 1.声明消息类: typ

MFC 访问控件的几种方法

访问控件的方法 控件是一种交互的工具,应用程序需要通过某种方法来访问控件以对其进行查询和设置.访问控件有四种方法: 利用对话框的数据交换功能访问控件.这种方法适用于自动创建的控件.先用ClassWizard为对话框类加入与控件对应的数据成员变量,然后在适当的时侯调用UpdateData,就可以实现对话框和控件的数据交换.这种方法只能交换数据,不能对控件进行全面的查询和设置,而且该方法不是针对某个控件,而是针对所有参与数据交换的控件.另外,对于新型的Win32控件,不能用ClassWizard创建