时常想,如果一个组件能够按自己想要的外观显示,那该是件多么COOL的事啊,这一篇就要来做一个精美外观的组件,但是,做什么好呢.Button? <delphi span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">高手突破</span><span lang="EN-US">></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">有关于自己定义外观的</span><span lang="EN-US">Button,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以及</span><span lang="EN-US">CheckBox</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">等的做法</span><span lang="EN-US">,Button</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">从</span><span lang="EN-US">CustomPanel</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">继承</span><span lang="EN-US">,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">重载</span><span lang="EN-US">Paint</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法来画外观</span><span lang="EN-US">.</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果你有兴趣</span><span lang="EN-US">,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以去找来看</span><span lang="EN-US">,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这里就不做</span><span lang="EN-US">Button</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">了</span><span lang="EN-US">,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">做一个</span><span lang="EN-US">Memo</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如何呢</span><span lang="EN-US">.</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">?是个不错的主意。</span></delphi>
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
我们先起个名字叫做TCoolMemo。以上篇已经讲了很多组件的技术,这里就只说出几个重点。其余不多说了。
首先,该Memo从CustomMemo继承,它有这样外观:属于平面的,边框是可以设置颜色的线,对应的颜色变量为FEdgeColor,另外,离边框以内的两个象素处,还有另一个框,当鼠标进入Memo时,这个框会显示,当鼠标离开时,为个框消失,同样也可以设置颜色,对应变量为FEnterColor。
那么鼠标进入和离开怎么判断呢,这里Memo将截获两个Delphi的内部消息:
//下面两个获得Delphi的内部消息,鼠标进入和离开时发生
procedure CMMouseEnter (var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave (var Message: TMessage); message CM_MOUSELEAVE;
其实父类已经截获了这两个消息,并作了相应处理,所以TCoolMemo中的消息处理函数要
Inherited;再作自己的处理。这里又用到了一个变量
MouseIn:Boolean;//标识鼠标是否进入组件
接下来TCoolMemo还要截获两个消息:
procedure WMPaint (var Message: TMessage); message WM_PAINT;
procedure WMNCCalcSize (var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
第一个很熟悉,当需要重画时,触发该消息,
第二个是当窗体需要计算位置和尺寸时触发,消息中包含了窗口客户区的大小,我们用这个的目的主要是将客户区缩小三个象素,以便画组件时不会画到客户区。
procedure TCoolMemo.WMNCCalcSize (var Message: TWMNCCalcSize);
begin
inherited;
InflateRect(Message.CalcSize_Params^.rgrc[0], -3, -3);
end;
而上面几个消息处理函数,CM_MOUSEENTER和CM_MOUSELEAVE;将引起TCoolMemo的外观变化,WM_PAINT保存其外观不被擦去。所以要用到一个画组件的函数,即:
drawBorder;
里面用到了几个API的GDI函数。我在代码中有详细的说明,加上自己看帮助,应该是可以看懂的。
另外,相比于Memo,它的扩展了这样的功能:设置边距和获得光标的位置。这两个对应的性属为Margin,Position。他们都是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));
光标的位置:
property Position:TPosition read getPosition;
TPostion是一个结构,其中有行和列两个值:
TPosition=record //指定光标的行和列
row:longint;
col:longint;
end;
getPosition;中还要处理中文的问题,代码有详细说明,如果文本中有中文,一样也可以得到正确的行和列。
最后增加了两个事件
property OnEnter;
property OnExit;
都是从父类中显化出来的,其实就是CM_MOUSEENTER和CM_MOUSELEAVE;消息引起的。,当你想作一个三态按钮,这两个事件很有作用。
好了,重点就是上面那几个了,以下是源代码,其中也有详细的说明:
unit CoolMemo;
interface
uses
Windows, Messages, Classes, Forms,Controls, Graphics, StdCtrls;
type
//用设定边缘的空白
TPosition=record //指定光标的行和列
row:longint;
col:longint;
end;
TCoolMemo=class(TCustomMemo)
private
FMargin:byte; //边距的大小
FEdgeColor:TColor;//边框的颜色
FEnterColor:TColor;//鼠标进入时边框内侧的框颜色
MouseIn: Boolean; //标识鼠标是否进入
function getPosition:TPosition;//光标的行和列
procedure setMargin(value:byte);
procedure setEdgeColor(Value:TColor);
procedure setEnterColor(Value:TColor);
//下面两个获得Delphi的内部消息,鼠标进入和离开时发生
procedure CMMouseEnter (var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave (var Message: TMessage); message CM_MOUSELEAVE;
//当一个窗口的外观必须被画时,应用程序发送这个消息给该窗口
procedure WMPaint (var Message: TMessage); message WM_PAINT;
//窗体需要计算位置和尺寸时触发
//我们用这个的目的主要是将客户区缩小三个象素,以便画组件时不会画到客户区。
procedure WMNCCalcSize (var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
protected
//画窗体的边框,使其看起来更美观.
procedure drawBorder;
public
constructor Create (AOwner: TComponent); override;
property Position:TPosition read getPosition;
property Margin:byte read FMargin write setMargin default 0;
published
property EdgeColor:TColor read FEdgeColor write SetEdgeColor default $ff0000;
property EnterColor:TColor read FEnterColor write SetEnterColor default $0000ff;
//显式化父类的属性
property Align;
property Alignment;
property DragCursor;
property DragMode;
property Enabled;
property Color;
property Font;
property Lines;
property MaxLength;
property OEMConvert;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ReadOnly;
property ShowHint;
property ScrollBars;
property TabOrder;
property TabStop;
property Visible;
property WantReturns;
property WantTabs;
property WordWrap;
property OnChange;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
//增加这两个事件,处理鼠标进入和离开
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDrag;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TCoolMemo]);
end;
constructor TCoolMemo.Create(AOwner:TComponent);
begin
inherited Create(Aowner);
ControlStyle := ControlStyle - [csFramed];
ParentFont := True;
FEdgeColor := $ff0000;
FEnterColor := $0000ff;
//设定外观,平面无边形
Ctl3D := False;
FMargin:=0;
BorderStyle:=bsNone;
height:=150;
width:=200;
end;
procedure TCoolMemo.setMargin(Value:byte);
var
Rect: TRect;
begin
//该消息取得客户区的尺寸
SendMessage(Handle, EM_GETRECT, 0, Longint(@Rect));
//以下是重新确定尺寸
Rect.Top := Value;
Rect.Left := Value;
Rect.Right := Width -Value;
Rect.Bottom := Height -Value;
//该消息设定客户区的大小
SendMessage(Handle, EM_SETRECT, 0, Longint(@Rect));
Fmargin:=value;
end;
function TCoolMemo.getPosition:TPosition;
var
row,<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /><place w:st="on"><state w:st="on">Col</state></place>:longint;
CBLines:longint;
str:WideString;
begin
//该消息取得光标所在的行,
row:= SendMessage(Handle,EM_LINEFROMCHAR,SelStart,0);
//该消息取得光标所在行开始的位置,位置从第一行的0开始计数,
//每过一个字符增加1,
CBLines:=SendMessage(Handle,EM_LINEINDEX,row,0);
//得到光标的所在行的所在列
<place w:st="on"><state w:st="on">Col</state></place>:=SelStart-CBLines;
//为了解决中文的问题,需要用宽字符型来取得光标所在行
//,行中光标所在列之前的字符串,这样可以解决中文列数的确定问题.
str:=Copy(Lines[row],1,col);
col:=Length(Str)+1;
result.row:=row+1;
result.col:=col;
end;
procedure TCoolMemo.setEdgeColor(Value:TCOlor);
begin
if FEdgeColor<>value then
begin
FEdgeColor:=value;
drawBorder;
end;
end;
procedure TCoolMemo.setEnterColor(Value:TColor);
begin
if FEnterColor<>value then
begin
FEnterColor:=value;
drawBorder;
end;
end;
procedure TCoolMemo.CMMouseEnter(var Message: TMessage);
begin
inherited;
MouseIn:= True;
drawBorder;
end;
procedure TCoolMemo.CMMouseLeave(var Message:TMessage);
begin
inherited;
MouseIn:=False;
drawBorder;
end;
procedure TCoolMemo.WMPaint (var Message: TMessage);
begin
inherited;
drawBorder;
end;
procedure TCoolMemo.WMNCCalcSize (var Message: TWMNCCalcSize);
begin
inherited;
InflateRect(Message.CalcSize_Params^.rgrc[0], -3, -3);
end;
procedure TCoolMemo.drawBorder;
var
DC: HDC; //设备描述表
R: TRect; //客户区
EnterBrush,OuterBrush,BorderBrush:HBRUSH; //画笔句柄,API
begin
DC:= GetWindowDC(Handle); //取得该组件的设备描述表
try
GetWindowRect(Handle, R); //取得该组件的客户区尺寸
OffsetRect(R, -R.Left, -R.Top); //左上偏移
//创建画笔,两个,分别代码边框,边框内,白色画笔
BorderBrush := CreateSolidBrush(ColorToRGB(FEdgeColor));
EnterBrush:= CreateSolidBrush(ColorToRGB(FEnterColor));
OuterBrush:=CreateSolidBrush(ColorToRGB(clWhite));
//not(csDesigning in ComponentState保证在设计期不变
if (not(csDesigning in ComponentState)) and
(MouseIn=true) then //如果鼠标进入
begin
//画一个矩形框,用BorderBrush画笔
FrameRect(DC, R, BorderBrush);
//把R缩小一个象素
InflateRect(R, -1, -1);
//画一个矩形框,用outerBrush画笔
FrameRect(DC, R, outerBrush);
InflateRect(R, -1, -1);
FrameRect(DC, R, EnterBrush);
end
else //如果鼠标没有进入
begin
FrameRect(DC, R, BorderBrush);
InflateRect(R, -1, -1);
FrameRect(DC, R, outerBrush);
InflateRect(R, -1, -1);
FrameRect(DC, R, outerBrush);
end;
finally
ReleaseDC(Handle, DC); //释放设备描述表
end;
DeleteObject(BorderBrush); //释放画笔
DeleteObject(EnterBrush);
DeleteObject(OuterBrush);
end;
end.
安装上去试试吧,比Memo1好看多了,功能也强多了。是吗。
至此已经做了三个组件了,其实不算很复杂,只要理清思绪。到这里似乎可以结束这次的组件制作之旅了,但是还没有。我们似乎还没有做过非可视化组件。所以我想最后一个,就是做一个非可视化组件。想知道是什么,往下看吧。
分享到:
相关推荐
React <AwesomeButton> UI组件 react-awesome-button是一种高性能,可扩展,高度可定制,可用于生产环境的React组件,可呈现一组动画3D UI按钮。 与社交共享和进度支持组件捆绑在一起。主要特点60fps 3D动画按钮动画...
奥杰CMS(奥杰内容管理...无需编写代码也能在外观和功能上对组件进行自由定制;用户可以自行开发功能模块已满足扩展功能模块的需要;能够通过站点管理功能进行SAAS运营业务。 通过账号:admin;密码:123456进入系统
该软件包是为Windows制作的,尽管希望任何人修改此软件包以使其与Linux或Mac的外观和风格保持一致,并鼓励这样做。 源很小,因此进行任何修改或增强应该很简单。 屏幕截图 特征 窗户 提供最大化,最小化,还原和关闭...
*轴组件具有自定义材料和外观,日期标签,格式化标签,沿轴线纹理平铺。轴的所有方面都可以使用您自己的参数进行设置,包括:除法计数和间隙,厚度,标签定位等。 *带标签和轴的2D / 3D响应条形图。支持多个类别和...
不要一个接一个地改变对象,而是在几秒钟内改变整个用户界面的外观--所有这些都使用了用户界面管理器! *可完全定制 您可以使用统一检查器添加或更改几乎所有的东西,无需处理代码或外部工具。各种定制编辑器工具...
不要一个接一个地改变对象,而是在几秒钟内改变整个用户界面的外观--所有这些都使用了用户界面管理器! *可完全定制 您可以使用统一检查器添加或更改几乎所有的东西,无需处理代码或外部工具。各种定制编辑器工具...
0002 如何定制组件面板 2 0003 如何定制代码编辑器 3 0004 保存自定义开发环境桌面 4 1.2 组件安装 4 0005 安装ActiveX组件 4 0006 安装不同类型的第三方组件 5 0007 在Delphi中加载QReport报表组件 7...
0002 如何定制组件面板 2 0003 如何定制代码编辑器 3 0004 保存自定义开发环境桌面 4 1.2 组件安装 4 0005 安装ActiveX组件 4 0006 安装不同类型的第三方组件 5 0007 在Delphi中加载QReport报表组件 7...
控件的方法和属性能方便的存储和加载报表布局,监测和控制设计环境,并可根据终端用户的需要定制外观。 与ASP.NET集成 Web浏览器控件为您提供了web上的快速浏览ActiveReports 以及打印功能,并具有ActiveX,...
设计、建筑、工程和许多其他行业的专业人士之所以选择 SketchUp Pro,是因为其灵活易用,适用于任何类型的 3D 建模和通讯。最新中文特别版。支持 Yosemite 10.10。共包括8种语言下载(简体中文,繁体中文,英文,...
在获得我们从JLCPCB订购的定制PCB 以改善我们机器的外观以及本指南中有足够的文档和代码以便您轻松创建midi控制器之后,该项目非常方便。 我们仅用了3天时间完成了这个项目,只用了三天就完成了所有需要的部件并完成...
体验.net2.0的优雅(四):Provider、策略、控制反转和依赖注入 泛型最佳实践 asp.net 2.0下嵌套masterpage页的可视化编辑 C# 2.0与泛型 动态调用对象的属性和方法——性能和灵活性兼备的方法 泛型技巧系列:用泛型...
此外,《ASP.NET 4高级程序设计(第4版)》专门提供了两章的内容来教你如何用Ajax 技术制作快速响应的页面,以及如何使用微软的ASP.NETAJAX平台。另外,还专门介绍了ASP.NET4 新增的功能,如MVC 和动态数据等。 ...
ParamQuery Grid Pro是ParamQuery Grid的商业级版本,并且已成为台式机,移动设备和触摸设备的专业企业应用程序的首选工具。...所有主要浏览器IE(9 +),Firefox,Chrome,Opera等的外观和功能都一致
我们为这种新的Material-UI外观以及定制的可能性感到自豪。 使用它非常简单,它将使您能够刷新经典外观的应用程序。 为了获得理想的效果,您还需要集成需要付出更多努力的ReactJS插件。 最后的结果将是值得的。 ...