组件制作之四(定制外观)%A

%D%A%D%A%D%A

时常想,如果一个组件能够按自己想要的外观显示,那该是件多么COOL的事啊,这一篇就要来做一个精美外观的组件,但是,做什么好呢.Button? < SPAN> 高手突破%26gt;有关于自己定义外观的Button,以及CheckBox等的做法,ButtonCustomPanel继承,重载Paint方法来画外观.如果你有兴趣,可以去找来看,这里就不做Button,做一个Memo如何呢.?是个不错的主意。

%26nbsp;

我们先起个名字叫做TCoolMemo。以上篇已经讲了很多组件的技术,这里就只说出几个重点。其余不多说了。

%26nbsp;

首先,该MemoCustomMemo继承,它有这样外观:属于平面的,边框是可以设置颜色的线,对应的颜色变量为FEdgeColor,另外,离边框以内的两个象素处,还有另一个框,当鼠标进入Memo时,这个框会显示,当鼠标离开时,为个框消失,同样也可以设置颜色,对应变量为FEnterColor

那么鼠标进入和离开怎么判断呢,这里Memo将截获两个Delphi的内部消息:

//下面两个获得Delphi的内部消息,鼠标进入和离开时发生

%26nbsp;%26nbsp;%26nbsp;%26nbsp; procedure CMMouseEnter (var Message: TMessage); message CM_MOUSEENTER;

%26nbsp;%26nbsp;%26nbsp;%26nbsp; procedure CMMouseLeave (var Message: TMessage); message CM_MOUSELEAVE;

其实父类已经截获了这两个消息,并作了相应处理,所以TCoolMemo中的消息处理函数要

Inherited;再作自己的处理。这里又用到了一个变量

MouseInBoolean;//标识鼠标是否进入组件

%26nbsp;

接下来TCoolMemo还要截获两个消息:

procedure WMPaint (var Message: TMessage); message WM_PAINT;

procedure WMNCCalcSize (var Message: TWMNCCalcSize); message WM_NCCALCSIZE;

第一个很熟悉,当需要重画时,触发该消息,

第二个是当窗体需要计算位置和尺寸时触发,消息中包含了窗口客户区的大小,我们用这个的目的主要是将客户区缩小三个象素,以便画组件时不会画到客户区。

procedure TCoolMemo.WMNCCalcSize (var Message: TWMNCCalcSize);

begin

%26nbsp; inherited;

%26nbsp; InflateRect(Message.CalcSize_Params^.rgrc[0], -3, -3);

end;

%26nbsp;

而上面几个消息处理函数,CM_MOUSEENTERCM_MOUSELEAVE;将引起TCoolMemo的外观变化,WM_PAINT保存其外观不被擦去。所以要用到一个画组件的函数,即:

drawBorder;

里面用到了几个APIGDI函数。我在代码中有详细的说明,加上自己看帮助,应该是可以看懂的。

%26nbsp;

另外,相比于Memo,它的扩展了这样的功能:设置边距和获得光标的位置。这两个对应的性属为MarginPosition。他们都是Public的,不可以在对象察看器中看到。

我们一个个来说

边距设置

property Margin:byte read FMargin write setMargin default 0;

其中setMargin函数中发送了两个消息:

//该消息取得输入区的尺寸

SendMessage(Handle, EM_GETRECT, 0, Longint(@Rect));

//该消息设定输入区的大小

SendMessage(Handle, EM_SETRECT, 0, Longint(@Rect));

%26nbsp;

光标的位置:

property Position:TPosition read getPosition;

TPostion是一个结构,其中有行和列两个值:

TPosition=record%26nbsp; //指定光标的行和列

%26nbsp;%26nbsp;%26nbsp;%26nbsp; row:longint;

%26nbsp;%26nbsp;%26nbsp;%26nbsp; col:longint;

%26nbsp;%26nbsp; end;

getPosition;中还要处理中文的问题,代码有详细说明,如果文本中有中文,一样也可以得到正确的行和列。

%26nbsp;

最后增加了两个事件

property OnEnter;

property OnExit;

都是从父类中显化出来的,其实就是CM_MOUSEENTERCM_MOUSELEAVE;消息引起的。,当你想作一个三态按钮,这两个事件很有作用。

%26nbsp;

好了,重点就是上面那几个了,以下是源代码,其中也有详细的说明:

%26nbsp;

unit CoolMemo;

%26nbsp;

interface

%26nbsp;

uses

%26nbsp;%26nbsp; Windows, Messages, Classes, Forms,Controls, Graphics, StdCtrls;

%26nbsp;

type

%26nbsp;%26nbsp;%26nbsp; //用设定边缘的空白

%26nbsp;%26nbsp; TPosition=record%26nbsp; //指定光标的行和列

%26nbsp;%26nbsp;%26nbsp;%26nbsp; row:longint;

%26nbsp;%26nbsp;%26nbsp;%26nbsp; col:longint;

%26nbsp;%26nbsp; end;

%26nbsp;%26nbsp; TCoolMemo=class(TCustomMemo)

%26nbsp;%26nbsp; private

%26nbsp;%26nbsp;%26nbsp;%26nbsp; FMargin:byte;%26nbsp; //边距的大小

%26nbsp;%26nbsp;%26nbsp;%26nbsp; FEdgeColor:TColor;//边框的颜色

%26nbsp;%26nbsp;%26nbsp;%26nbsp; FEnterColor:TColor;//鼠标进入时边框内侧的框颜色

%26nbsp;%26nbsp;%26nbsp;%26nbsp; MouseIn: Boolean; //标识鼠标是否进入

%26nbsp;%26nbsp;%26nbsp;%26nbsp; function getPosition:TPosition;//光标的行和列

%26nbsp;%26nbsp;%26nbsp;%26nbsp; procedure setMargin(value:byte);

%26nbsp;%26nbsp;%26nbsp;%26nbsp; procedure setEdgeColor(Value:TColor);

%26nbsp;%26nbsp;%26nbsp;%26nbsp; procedure setEnterColor(Value:TColor);

%26nbsp;%26nbsp;%26nbsp;%26nbsp; //下面两个获得Delphi的内部消息,鼠标进入和离开时发生

%26nbsp;%26nbsp;%26nbsp;%26nbsp; procedure CMMouseEnter (var Message: TMessage); message CM_MOUSEENTER;

%26nbsp;%26nbsp;%26nbsp;%26nbsp; procedure CMMouseLeave (var Message: TMessage); message CM_MOUSELEAVE;

%26nbsp;%26nbsp;%26nbsp;%26nbsp; //当一个窗口的外观必须被画时,应用程序发送这个消息给该窗口

%26nbsp;%26nbsp;%26nbsp;%26nbsp; procedure WMPaint (var Message: TMessage); message WM_PAINT;

%26nbsp;%26nbsp;%26nbsp;%26nbsp; //窗体需要计算位置和尺寸时触发

%26nbsp;%26nbsp;%26nbsp;%26nbsp; //我们用这个的目的主要是将客户区缩小三个象素,以便画组件时不会画到客户区。

%26nbsp; procedure WMNCCalcSize (var Message: TWMNCCalcSize); message WM_NCCALCSIZE;

%26nbsp;%26nbsp; protected

%26nbsp;%26nbsp; //画窗体的边框,使其看起来更美观.

%26nbsp;%26nbsp;%26nbsp;%26nbsp; procedure drawBorder;

%26nbsp;%26nbsp; public

%26nbsp;%26nbsp;%26nbsp;%26nbsp; constructor Create (AOwner: TComponent); override;

%26nbsp;%26nbsp;%26nbsp;%26nbsp; property Position:TPosition read getPosition;

%26nbsp;%26nbsp;%26nbsp;%26nbsp; property Margin:byte read FMargin write setMargin default 0;

%26nbsp;%26nbsp; published

%26nbsp;%26nbsp;%26nbsp; property EdgeColor:TColor read FEdgeColor write SetEdgeColor default $ff0000;

%26nbsp;%26nbsp;%26nbsp; property EnterColor:TColor read FEnterColor write SetEnterColor default $0000ff;

%26nbsp;%26nbsp;%26nbsp; //显式化父类的属性

%26nbsp;%26nbsp;%26nbsp; property Align;

%26nbsp;%26nbsp;%26nbsp; property Alignment;

%26nbsp;%26nbsp;%26nbsp; property DragCursor;

%26nbsp;%26nbsp;%26nbsp; property DragMode;

%26nbsp;%26nbsp;%26nbsp; property Enabled;

%26nbsp;%26nbsp;%26nbsp; property Color;

%26nbsp;%26nbsp;%26nbsp; property Font;

%26nbsp;%26nbsp;%26nbsp; property Lines;

%26nbsp;%26nbsp;%26nbsp; property MaxLength;

%26nbsp;%26nbsp;%26nbsp; property OEMConvert;

%26nbsp;%26nbsp;%26nbsp; property ParentFont;

%26nbsp;%26nbsp;%26nbsp; property ParentShowHint;

%26nbsp;%26nbsp;%26nbsp; property PopupMenu;

%26nbsp;%26nbsp;%26nbsp; property ReadOnly;

%26nbsp;%26nbsp;%26nbsp; property ShowHint;

%26nbsp;%26nbsp;%26nbsp; property ScrollBars;

%26nbsp;%26nbsp;%26nbsp; property TabOrder;

%26nbsp;%26nbsp;%26nbsp; property TabStop;

%26nbsp;%26nbsp;%26nbsp; property Visible;

%26nbsp;%26nbsp;%26nbsp; property WantReturns;

%26nbsp;%26nbsp;%26nbsp; property WantTabs;

%26nbsp;%26nbsp;%26nbsp; property WordWrap;

%26nbsp;

%26nbsp;%26nbsp;%26nbsp; property OnChange;

%26nbsp;%26nbsp;%26nbsp; property OnClick;

%26nbsp;%26nbsp;%26nbsp; property OnDblClick;

%26nbsp;%26nbsp;%26nbsp; property OnDragDrop;

%26nbsp;%26nbsp;%26nbsp; property OnDragOver;

%26nbsp;%26nbsp;%26nbsp; property OnEndDrag;

%26nbsp;%26nbsp;%26nbsp; //增加这两个事件,处理鼠标进入和离开

%26nbsp;%26nbsp;%26nbsp; property OnEnter;

%26nbsp;%26nbsp;%26nbsp; property OnExit;

%26nbsp;%26nbsp;%26nbsp; property OnKeyDown;

%26nbsp;%26nbsp;%26nbsp; property OnKeyPress;

%26nbsp;%26nbsp;%26nbsp; property OnKeyUp;

%26nbsp;%26nbsp;%26nbsp; property OnMouseDown;

%26nbsp;%26nbsp;%26nbsp; property OnMouseMove;

%26nbsp;%26nbsp;%26nbsp; property OnMouseUp;

%26nbsp;%26nbsp;%26nbsp; property OnStartDrag;

%26nbsp;%26nbsp; end;

%26nbsp;

procedure Register;

%26nbsp;

implementation

%26nbsp;

procedure Register;

begin

%26nbsp; RegisterComponents('Samples', [TCoolMemo]);

end;

%26nbsp;

constructor TCoolMemo.Create(AOwner:TComponent);

begin

%26nbsp; inherited Create(Aowner);

%26nbsp; ControlStyle := ControlStyle - [csFramed];

%26nbsp; ParentFont := True;

%26nbsp; FEdgeColor := $ff0000;

%26nbsp; FEnterColor := $0000ff;

%26nbsp; //设定外观,平面无边形

%26nbsp; Ctl3D := False;

%26nbsp; FMargin:=0;

%26nbsp; BorderStyle:=bsNone;

%26nbsp; height:=150;

%26nbsp; width:=200;

end;

%26nbsp;

procedure TCoolMemo.setMargin(Value:byte);

var

%26nbsp; Rect: TRect;

begin

//该消息取得客户区的尺寸

%26nbsp; SendMessage(Handle, EM_GETRECT, 0, Longint(@Rect));

%26nbsp; //以下是重新确定尺寸

%26nbsp; Rect.Top := Value;

%26nbsp; Rect.Left := Value;

%26nbsp; Rect.Right := Width -Value;

%26nbsp; Rect.Bottom := Height -Value;

//该消息设定客户区的大小

%26nbsp; SendMessage(Handle, EM_SETRECT, 0, Longint(@Rect));

%26nbsp; Fmargin:=value;

end;

%26nbsp;

function TCoolMemo.getPosition:TPosition;

var

%26nbsp; row, Col :longint;

%26nbsp; CBLines:longint;

%26nbsp; str:WideString;

begin

//该消息取得光标所在的行,

%26nbsp; row:= SendMessage(Handle,EM_LINEFROMCHAR,SelStart,0);

%26nbsp; //该消息取得光标所在行开始的位置,位置从第一行的0开始计数,

%26nbsp; //每过一个字符增加1,

%26nbsp; CBLines:=SendMessage(Handle,EM_LINEINDEX,row,0);

%26nbsp; //得到光标的所在行的所在列

%26nbsp; Col :=SelStart-CBLines;

%26nbsp; //为了解决中文的问题,需要用宽字符型来取得光标所在行

%26nbsp; //,行中光标所在列之前的字符串,这样可以解决中文列数的确定问题.

%26nbsp; str:=Copy(Lines[row],1,col);

%26nbsp; col:=Length(Str)+1;

%26nbsp; result.row:=row+1;

%26nbsp; result.col:=col;

end;

%26nbsp;

procedure TCoolMemo.setEdgeColor(Value:TCOlor);

begin

%26nbsp;if FEdgeColor%26lt;%26gt;value then

%26nbsp;begin

%26nbsp; FEdgeColor:=value;

%26nbsp; drawBorder;

%26nbsp;end;

end;

%26nbsp;

procedure TCoolMemo.setEnterColor(Value:TColor);

begin

%26nbsp;if FEnterColor%26lt;%26gt;value then

%26nbsp;begin

%26nbsp;%26nbsp; FEnterColor:=value;

%26nbsp;%26nbsp; drawBorder;

%26nbsp;end;

end;

%26nbsp;

procedure TCoolMemo.CMMouseEnter(var Message: TMessage);

begin

%26nbsp; inherited;

%26nbsp;%26nbsp;%26nbsp; MouseIn:= True;

%26nbsp;%26nbsp;%26nbsp; drawBorder;

end;

%26nbsp;

procedure TCoolMemo.CMMouseLeave(var Message:TMessage);

begin

%26nbsp; inherited;

%26nbsp; MouseIn:=False;

%26nbsp; drawBorder;

end;

%26nbsp;

procedure TCoolMemo.WMPaint (var Message: TMessage);

begin

%26nbsp; inherited;

%26nbsp; drawBorder;

end;

%26nbsp;

procedure TCoolMemo.WMNCCalcSize (var Message: TWMNCCalcSize);

begin

%26nbsp; inherited;

%26nbsp; InflateRect(Message.CalcSize_Params^.rgrc[0], -3, -3);

end;

%26nbsp;

procedure TCoolMemo.drawBorder;

var

%26nbsp; DC: HDC;%26nbsp; //设备描述表

%26nbsp; R: TRect; //客户区

%26nbsp; EnterBrush,OuterBrush,BorderBrush:HBRUSH;%26nbsp; //画笔句柄,API

begin

%26nbsp; DC:= GetWindowDC(Handle);%26nbsp; //取得该组件的设备描述表

%26nbsp; try

%26nbsp;%26nbsp;%26nbsp; GetWindowRect(Handle, R);%26nbsp; //取得该组件的客户区尺寸

%26nbsp;%26nbsp;%26nbsp; OffsetRect(R, -R.Left, -R.Top); //左上偏移

%26nbsp;%26nbsp;%26nbsp; //创建画笔,两个,分别代码边框,边框内,白色画笔

%26nbsp;%26nbsp;%26nbsp; BorderBrush := CreateSolidBrush(ColorToRGB(FEdgeColor));

%26nbsp;%26nbsp;%26nbsp; EnterBrush:= CreateSolidBrush(ColorToRGB(FEnterColor));

%26nbsp;%26nbsp;%26nbsp; OuterBrush:=CreateSolidBrush(ColorToRGB(clWhite));

//not(csDesigning in ComponentState保证在设计期不变

%26nbsp;%26nbsp;%26nbsp; if (not(csDesigning in ComponentState)) and

%26nbsp;%26nbsp;%26nbsp; (MouseIn=true) then%26nbsp; //如果鼠标进入

%26nbsp;%26nbsp;%26nbsp; begin

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; //画一个矩形框,用BorderBrush画笔

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; FrameRect(DC, R, BorderBrush);

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; //R缩小一个象素

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; InflateRect(R, -1, -1);

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; //画一个矩形框,用outerBrush画笔

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; FrameRect(DC, R, outerBrush);

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; InflateRect(R, -1, -1);

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; FrameRect(DC, R, EnterBrush);

%26nbsp;%26nbsp;%26nbsp; end

%26nbsp;%26nbsp;%26nbsp; else%26nbsp; //如果鼠标没有进入

%26nbsp;%26nbsp;%26nbsp; begin

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; FrameRect(DC, R, BorderBrush);

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; InflateRect(R, -1, -1);

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; FrameRect(DC, R, outerBrush);

%26nbsp;%26nbsp;%26nbsp;%26nbsp;%26nbsp; InflateRect(R, -1, -1);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值