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(, 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"(,): CreateSubClass(Params, 'EDIT');
"G:\Vcl\StdCtrls.pas"(,): CreateSubClass(Params, 'COMBOBOX');
"G:\Vcl\StdCtrls.pas"(,): CreateSubClass(Params, 'BUTTON'); // TButton
"G:\Vcl\StdCtrls.pas"(,): CreateSubClass(Params, 'BUTTON'); // TCustomCheckBox
"G:\Vcl\StdCtrls.pas"(,): CreateSubClass(Params, 'BUTTON'); // TRadioButton
"G:\Vcl\StdCtrls.pas"(,): CreateSubClass(Params, 'LISTBOX');
"G:\Vcl\StdCtrls.pas"(,): CreateSubClass(Params, 'SCROLLBAR');
"G:\Vcl\StdCtrls.pas"(,): CreateSubClass(Params, 'STATIC');
17种Windows复杂控件:
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, 'RICHEDIT');
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, WC_TABCONTROL);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, STATUSCLASSNAME);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, WC_HEADER);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, WC_TREEVIEW);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, TRACKBAR_CLASS);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, PROGRESS_CLASS);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, UPDOWN_CLASS);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, HOTKEYCLASS);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, WC_LISTVIEW);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, ANIMATE_CLASS);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, TOOLBARCLASSNAME);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, REBARCLASSNAME);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, MONTHCAL_CLASS);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, DATETIMEPICK_CLASS);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, WC_PAGESCROLLER);
"G:\Vcl\ComCtrls.pas"(,): CreateSubClass(Params, WC_COMBOBOXEX);
本着任何技术都要烂熟于心的精神,把8种基础控件的代码贴上来,混个脸熟,以后再加上注释:
procedure TCustomEdit.CreateParams(var Params: TCreateParams);
const
Passwords: array[Boolean] of DWORD = (, ES_PASSWORD);
ReadOnlys: array[Boolean] of DWORD = (, ES_READONLY);
CharCases: array[TEditCharCase] of DWORD = (, ES_UPPERCASE, ES_LOWERCASE);
HideSelections: array[Boolean] of DWORD = (ES_NOHIDESEL, );
OEMConverts: array[Boolean] of DWORD = (, 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 <> #] 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 = (, CBS_UPPERCASE, CBS_LOWERCASE);
Sorts: array[Boolean] of DWORD = (, 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, ), (, 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, ), (, 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 =
(, LBS_OWNERDRAWFIXED, LBS_OWNERDRAWVARIABLE, LBS_OWNERDRAWFIXED,
LBS_OWNERDRAWFIXED);
Sorteds: array[Boolean] of DWORD = (, LBS_SORT);
MultiSelects: array[Boolean] of DWORD = (, LBS_MULTIPLESEL);
ExtendSelects: array[Boolean] of DWORD = (, LBS_EXTENDEDSEL);
IntegralHeights: array[Boolean] of DWORD = (LBS_NOINTEGRALHEIGHT, );
MultiColumns: array[Boolean] of DWORD = (, LBS_MULTICOLUMN);
TabStops: array[Boolean] of DWORD = (, LBS_USETABSTOPS);
CSHREDRAW: array[Boolean] of DWORD = (CS_HREDRAW, );
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 <> ] or BorderStyles[FBorderStyle] or
TabStops[FTabWidth <> ];
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 :=
else
FRTLFactor := -;
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 = (, 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, );
HideSelections: array[Boolean] of DWORD = (ES_NOHIDESEL, );
begin
if FRichEditModule = then
begin
FRichEditModule := LoadLibrary(RichEditModuleName);
if FRichEditModule <= HINSTANCE_ERROR then FRichEditModule := ;
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;
Delphi一共封装(超类化)了8种Windows基础控件和17种复杂控件的更多相关文章
- 窗口的子类化与超类化——子类化是窗口实例级别的,超类化是在窗口类(WNDCLASS)级别的
1. 子类化 理论:子类化是这样一种技术,它允许一个应用程序截获发往另一个窗口的消息.一个应用程序通过截获属于另一个窗口的消息,从而实现增加.监视或者修改那个窗口的缺省行为.子类化是用来改变或者扩展一 ...
- C++ 中超类化和子类化
超类化和子类化没有具体的代码,其实是一种编程技巧,在MFC和WTL中可以有不同的实现方法. 窗口子类化: 原理就是改变一个已创建窗口类的窗口过程函数.通过截获已创建窗口的消息,从而实现监视或修改已创建 ...
- C++ 中超类化和子类化常用API
在windows平台上,使用C++实现子类化和超类化常用的API并不多,由于这些API函数的详解和使用方法,网上一大把.本文仅作为笔记,简单的记录一下. 子类化:SetWindowLong,GetWi ...
- 窗口 超类化 子类化 HOOK
body { font-family: Bitstream Vera Sans Mono; font-size: 11pt; line-height: 1.5; } html, body { colo ...
- 眼见为实(2):介绍Windows的窗口、消息、子类化和超类化
眼见为实(2):介绍Windows的窗口.消息.子类化和超类化 这篇文章本来只是想介绍一下子类化和超类化这两个比较“生僻”的名词.为了叙述的完整性而讨论了Windows的窗口和消息,也简要讨论了进程和 ...
- Delphi中封装ADO之我重学习记录
delphi adodataset ctstatic 数据是缓存在服务器端还是客户端 答:客户端,开启本地缓存功能后,就能数据在本地批量修改后,再批量提交,减少了网络传送 原创,专业,图文 Del ...
- Delphi 询问框 汉化
Delphi 询问框 汉化 d:\program files (x86)\embarcadero\studio\17.0\source\fmx\FMX.Consts.pas add this file ...
- Delphi 7里Messages.pas里所有104种重定义消息种类,180种不同的消息名称
Delphi 7里Messages.pas里所有消息.经统计,共104种重定义消息种类,方便使用,180种不同的消息名称.省得像VC里一样,处处自己解析wParam和LParam参数进行分析.有空我要 ...
- MFC控件编程之 按钮编辑框.静态文本的使用,以及访问控件的七种方法.
MFC控件编程之 按钮编辑框.静态文本的使用以及访问控件的七种方法. 一丶按钮.静态文本的通用属性. 他们都有一个属性.就是可以输入标题内容.以及可以自定义控件ID. 创建一个MFC Dlg对话框. ...
随机推荐
- 浙江工商大学15年校赛E题 无邪的飞行棋 【经典背包】
无邪的飞行棋 Time Limit 1s Memory Limit 64KB Judge Program Standard Ratio(Solve/Submit) 15.38%(4/26) Descr ...
- POJ 2479 不相交最大子段和
题目意思还是很好理解的,在一个数列中,找出不相交的两个子串使得其和最大. 解题思路: 对于每个i来说,求出[0 ~ i - 1] 的最大子段和以及[i ~ n - 1]的最大子段和,在加起来,求最大的 ...
- AWVS介绍(转)
使用AWVS对域名进行全局分析,深入探索: 首先,介绍一下AWVS这个工具. Acunetix Web Vulnerability Scanner(简称AWVS)是一款知名的网络漏洞扫描工具,它通过网 ...
- hadoop安全模式
hadoop安全模式在分布式文件系统启动的时候,开始的时候会有安全模式,当分布式文件系统处于安全模式的情况下,文件系统中的内容不允许修改也不允许删除,直到安全模式结束.安全模式主要是为了系统启动的 ...
- 基于visual Studio2013解决C语言竞赛题之0416完数
题目 解决代码及点评 完数的解决方案依旧是遍历,然后写出判断完数的函数进行处理 /************************************************** ...
- qq邮箱是怎么做到同一个浏览器让多个不用用户同时打开的? --session的控制
待解:..... 借鉴网址:http://www.zhihu.com/question/20235500 欢迎来讨论.....
- three.js 源代码凝视(十四)Math/Sphere.js
商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 - 本博客专注于 敏捷开发 ...
- Android内存之VSS/RSS/PSS/USS
Terms VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存) RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存) PSS - P ...
- Eclipse生成Jar包方法
Eclipse生成jar包 第一:普通类导出jar包,我说的普通类就是指此类包含main方法,并且没有用到别的jar包. 1.在eclipse中选择你要导出的类或者package,右击,选择Exp ...
- iOS开发之使用Ad Hoc进行测试
由于最近某个项目需要给别人测试,使用的是Ad Hoc方法 首先登录开发者官网配置证书 1.添加Certificates,从电脑获取certSigningRequest然后添加进去 2.在Identif ...