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对话框. ...
随机推荐
- Android的ProgressBar
注意点: 必须在setContentView 前面设置,否则会报错. 重要的方法: progress.incrementProgressBy(int diff);//参数为进度数,进度满了为100.不 ...
- SQLite数据转换成sql server数据
需要将SQLite数据库里的数据导入到SQL Server,在网上搜了好久,没有找到一个方便实用的方法. 经过本人的细心琢磨实验,终于让我给找到一好的方法:使用CSV文件作为介质来做转换.现在记录下来 ...
- 17.1.1.7 Setting Up Replication with New Master and Slaves 设置复制对于新的Master和Slaves:
17.1.1.7 Setting Up Replication with New Master and Slaves 设置复制对于新的Master和Slaves: 最简单和最直接的方法是设置复制用于使 ...
- qq邮箱是怎么做到同一个浏览器让多个不用用户同时打开的? --session的控制
待解:..... 借鉴网址:http://www.zhihu.com/question/20235500 欢迎来讨论.....
- 分享:json2.js源代码解读笔记
1. 怎样理解"json" 首先应该意识到,json是一种数据转换格式,既然是个"格式",就是个抽象的东西.它不是js对象,也不是字符串,它仅仅是一种格式,一种 ...
- ListView中加入Button后,Button的点击事件和ListView的点击事件冲突
1.在ItemView配置的xml文件里的根节点加入属性android:descendantFocusability="blocksDescendants" 2.在要加入事件的控件 ...
- jQuery(expression, [context]) , $(即jQuery)的參数问题
jQuery(expression, [context]) 返回值:jQuery 概述 这个函数接收一个包括 CSS 选择器的字符串,然后用这个字符串去匹配一组元素. jQuery 的 ...
- 变相的取消Datagridview控件的选中状态
思路:把每一列的文字颜色设为黑色,选中时候的背景为白色,颜色为黑色.每一列都这样设置,那么变相的达到了取消选中效果. 图:
- 网站实战 从效果图开始CSS+DIV 布局华为网站
经过我们的前面css的学习,我们已经分模块的掌握的CSS的技术,但是,要是完整的做一个页面,我们还没有接触过,这次呢,小强老师来和大家完整的利用CSS+DIV做一个网站案例,我们来模仿下华为的网站. ...
- boost 分析命令行参数
#include <boost/program_options.hpp> #include <iostream> #include <vector> using n ...