VCL控件组件大都应该重载TWinControl的虚函数WndProc来进行处理窗口消息的工作
TWinControl的构造函数中会调用MakeObjectInstance并且传递MainWndProc作为窗口消息处理函数,而MainWndProc则会调用虚函数WndProc来处理窗口消息。留个爪,对TButton的主要方法,都要仔细解读一下。
推测VCL控件组件大都应该重载TWinControl的虚函数WndProc来进行处理窗口消息的工作,举例:
procedure TButtonControl.WndProc(var Message: TMessage); override;
begin
case Message.Msg of
WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
if not (csDesigning in ComponentState) and not Focused then
begin
FClicksDisabled := True;
Windows.SetFocus(Handle); // Windows单元
FClicksDisabled := False;
if not Focused then Exit;
end;
CN_COMMAND:
if FClicksDisabled then Exit;
end;
inherited WndProc(Message);
TButtonControl = class(TWinControl)
private
FClicksDisabled: Boolean;
FWordWrap: Boolean;
function IsCheckedStored: Boolean;
procedure CNCtlColorStatic(var Message: TWMCtlColorStatic); message CN_CTLCOLORSTATIC;
procedure WMEraseBkGnd(var Message: TWMEraseBkGnd); message WM_ERASEBKGND;
procedure SetWordWrap(const Value: Boolean);
protected
procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
function GetActionLinkClass: TControlActionLinkClass; override;
function GetChecked: Boolean; virtual;
procedure SetChecked(Value: Boolean); virtual;
procedure WndProc(var Message: TMessage); override;
procedure CreateParams(var Params: TCreateParams); override;
property Checked: Boolean read GetChecked write SetChecked stored IsCheckedStored default False;
property ClicksDisabled: Boolean read FClicksDisabled write FClicksDisabled;
property WordWrap: Boolean read FWordWrap write SetWordWrap default False;
public
constructor Create(AOwner: TComponent); override;
end; TButton = class(TButtonControl)
private
FDefault: Boolean;
FCancel: Boolean;
FActive: Boolean;
FModalResult: TModalResult;
procedure SetDefault(Value: Boolean);
procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;
procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
procedure CMFocusChanged(var Message: TCMFocusChanged); message CM_FOCUSCHANGED;
procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
procedure CNCtlColorBtn(var Message: TWMCtlColorBtn); message CN_CTLCOLORBTN;
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure SetButtonStyle(ADefault: Boolean); virtual;
public
constructor Create(AOwner: TComponent); override;
procedure Click; override;
function UseRightToLeftAlignment: Boolean; override;
end;
// TButtonControl 研究
constructor TButtonControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
if SysLocale.FarEast and (Win32Platform = VER_PLATFORM_WIN32_NT) then
ImeMode := imDisable;
end; procedure TButtonControl.ActionChange(Sender: TObject; CheckDefaults: Boolean);
begin
inherited ActionChange(Sender, CheckDefaults);
if Sender is TCustomAction then
with TCustomAction(Sender) do
begin
if not CheckDefaults or (Self.Checked = False) then
Self.Checked := Checked;
end;
end; function TButtonControl.GetActionLinkClass: TControlActionLinkClass;
begin
Result := TButtonActionLink;
end; function TButtonControl.IsCheckedStored: Boolean;
begin
Result := (ActionLink = nil) or not TButtonActionLink(ActionLink).IsCheckedLinked;
end; procedure TButtonControl.CNCtlColorStatic(var Message: TWMCtlColorStatic);
begin
with ThemeServices do
if ThemesEnabled then
begin
DrawParentBackground(Handle, Message.ChildDC, nil, False);
{ Return an empty brush to prevent Windows from overpainting we just have created. }
Message.Result := GetStockObject(NULL_BRUSH);
end
else
inherited;
end; procedure TButtonControl.WMEraseBkGnd(var Message: TWMEraseBkGnd);
begin
{ Under theme services the background is drawn in CN_CTLCOLORSTATIC. }
if ThemeServices.ThemesEnabled then
Message.Result :=
else
inherited;
end; procedure TButtonControl.CreateParams(var Params: TCreateParams);
begin
inherited;
if FWordWrap then
Params.Style := Params.Style or BS_MULTILINE;
end; procedure TButtonControl.SetWordWrap(const Value: Boolean);
begin
if FWordWrap <> Value then
begin
FWordWrap := Value;
RecreateWnd;
end;
end;
// TButton研究
constructor TButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := [csSetCaption, csDoubleClicks];
Width := ;
Height := ;
TabStop := True;
end; procedure TButton.Click;
var
Form: TCustomForm;
begin
Form := GetParentForm(Self);
if Form <> nil then Form.ModalResult := ModalResult;
inherited Click;
end; function TButton.UseRightToLeftAlignment: Boolean;
begin
Result := False;
end; procedure TButton.SetButtonStyle(ADefault: Boolean);
const
BS_MASK = $000F;
var
Style: Word;
begin
if HandleAllocated then
begin
if ADefault then Style := BS_DEFPUSHBUTTON else Style := BS_PUSHBUTTON;
if GetWindowLong(Handle, GWL_STYLE) and BS_MASK <> Style then
SendMessage(Handle, BM_SETSTYLE, Style, );
end;
end; procedure TButton.SetDefault(Value: Boolean);
var
Form: TCustomForm;
begin
FDefault := Value;
if HandleAllocated then
begin
Form := GetParentForm(Self);
if Form <> nil then
Form.Perform(CM_FOCUSCHANGED, , Longint(Form.ActiveControl));
end;
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 TButton.CreateWnd;
begin
inherited CreateWnd;
FActive := FDefault;
end; procedure TButton.CNCommand(var Message: TWMCommand);
begin
if Message.NotifyCode = BN_CLICKED then Click;
end; procedure TButton.CMDialogKey(var Message: TCMDialogKey);
begin
with Message do
if (((CharCode = VK_RETURN) and FActive) or
((CharCode = VK_ESCAPE) and FCancel)) and
(KeyDataToShiftState(Message.KeyData) = []) and CanFocus then
begin
Click;
Result := ;
end else
inherited;
end; procedure TButton.CMDialogChar(var Message: TCMDialogChar);
begin
with Message do
if IsAccel(CharCode, Caption) and CanFocus then
begin
Click;
Result := ;
end else
inherited;
end; procedure TButton.CMFocusChanged(var Message: TCMFocusChanged);
begin
with Message do
if Sender is TButton then
FActive := Sender = Self
else
FActive := FDefault;
SetButtonStyle(FActive);
inherited;
end; procedure TButton.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
if ThemeServices.ThemesEnabled then
Message.Result :=
else
DefaultHandler(Message);
end; procedure TButton.CNCtlColorBtn(var Message: TWMCtlColorBtn);
begin
with ThemeServices do
if ThemesEnabled then
begin
DrawParentBackground(Handle, Message.ChildDC, nil, False);
{ Return an empty brush to prevent Windows from overpainting we just have created. }
Message.Result := GetStockObject(NULL_BRUSH);
end
else
inherited;
end;
其它继承的组件:
TCustomCheckBox = class(TButtonControl)
TCheckBox = class(TCustomCheckBox)
TRadioButton = class(TButtonControl)
VCL控件组件大都应该重载TWinControl的虚函数WndProc来进行处理窗口消息的工作的更多相关文章
- 关于VCL的编写 (一) 如何编写自己的VCL控件
如何编写自己的VCL控件 用过Delphi的朋友们,大概对Delphi的最喜欢Delphi的不是他的强类型的pascal语法,而是强大的VCL控件,本人就是一位VCL控件的爱好者. VCL控件的开源, ...
- 浅谈控件(组件)制作方法一(附带一delphi导出数据到Excel的组件实例)(原创)
来自:http://blog.csdn.net/zhdwjie/article/details/1490741 -------------------------------------------- ...
- Victor 串口 VCL 控件 - 简单实用, 功能强大的 C++ Builder 串口控件!
源:Victor 串口 VCL 控件 - 简单实用, 功能强大的 C++ Builder 串口控件! 2014年02月06日发布控件的重要更新版本: Victor 串口控件 1.5.0.2 版本 (包 ...
- 一句话改变TWinControl控件的left坐标的前世今生(入口函数是SetBounds,然后调用SetWindowPos起作用,并发消息更新Delphi的left属性值)
Delphi的重要属性,主要是Enable, Visible, Color, left等等.这里分析left,因为TWinControl里有些覆盖函数的原因,虽然起点都是TControl.SetLe ...
- TCustomControl绘制自己和图形子控件共四步,TWinControl关键属性方法速记
TCustomControl = class(TWinControl) private FCanvas: TCanvas; procedure WMPaint(var Message: TWMPain ...
- vcl控件经常使用属性和方法
TTabControl属性 DisplayRect:仅仅定该控件客户区的一个矩形 HotTrack:设置当鼠标经过页标签时,它的字是否有变化.假设为True,是字会变成蓝色Images:为每一个页标签 ...
- Android图表日历控件组件
1.图表引擎 - AChartEngine AChartEngine是一款基于Android的图表绘制引擎,它为Android开发人员提供了非常多有用的图表绘制工具类,假设你须要在Android应用中 ...
- Bootstrap树控件(Tree控件组件)使用经验分享
前言:很多时候我们在项目中需要用到树,有些树仅仅是展示层级关系,有些树是为了展示和编辑层级关系,还有些树是为了选中项然后其他地方调用选中项.不管怎么样,树控件都是很多项目里面不可或缺的组件之一.今天, ...
- 运行时改变控件的大小(点击后立刻ReleaseCapture,然后计算位移,最后发消息改变位置)——最有趣的是TPanel其实也有窗口标题,因此可发HTCAPTION消息
//光标在控件不同位置时的样式 // 由于拐角这点手动精确实在困难 所以用范围 范围+3 这样很容易就找到这一点了 procedure CtrlMouseMove(Ctrl: TWinControl; ...
随机推荐
- 破解 zip 压缩包程序
目录 项目文件结构 代码实现过程 演示效果 代码地址如下:http://www.demodashi.com/demo/12021.html 项目文件结构 在当前目录有三个文件: 3-zipCrack. ...
- 《windows核心编程》- 线程栈
当系统创建线程的时候,会为线程栈预订一块地址空间区域,并给该区域调拨一些物理存储器.默认会预订1MB的地址空间并调拨两个页面的存储器.但是在构建 应用程序的时候可以改变这个默认值 在构建应用程序的时候 ...
- unity, inspector debug
以前经常因为脚本中private变量不在inspector界面中显示,不方便观察其值的变化,所以本该用private的用了public. 今天发现,原来inspector有个选项,如图,平常勾选的是N ...
- Android 使用handler实现线程间发送消息 (主线程 与 子线程之间)、(子线程 与 子线程之间)
keyword:Android 使用handler实现线程间发送消息 (主线程 与 子线程之间).(子线程 与 子线程之间) 相信大家平时都有使用到异步线程往主线程(UI线程)发送消息的情况. 本文主 ...
- 时间序列 R 读书笔记 04 Forecasting: principles and practice
本章開始学习<Forecasting: principles and practice> 1 getting started 1.1 事件的可预言性 一个时间能不能被预言主要取决于以下三点 ...
- C++语言基础(11)-多态
一.产生背景 先看下面的例子: #include <iostream> using namespace std; //基类People class People{ public: Peop ...
- iOS开发多线程篇 10 —NSOperation基本操作
iOS开发多线程篇—NSOperation基本操作 一.并发数 (1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3 (2)最大并发数:同一时间最多只能执行的任务的个数. ...
- 设计模式中类的关系之聚合关系(Aggregation)
聚合关系是关联关系的一种特例,它体现的是整体与部分的关系,即has-a的关系,此时整体与部分之间是可分离的,它们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享.比如计算机与 ...
- Problem #3263 丽娃河的狼人传说 区间满足灯数,r排序后贪心。
丽娃河的狼人传说 Time limit per test: 1.0 seconds Time limit all tests: 1.0 seconds Memory limit: megabytes ...
- ssh远程登录+查看系统版本+使用scp命令上传下载
ssh远程登录命令简单实例 ssh命令用于远程登录上Linux主机. 常用格式:ssh [-l login_name] [-p port] [user@]hostname 更详细的可以用ssh ...