`
javasogo
  • 浏览: 1817555 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

阅读更多

时常想,如果一个组件能够按自己想要的外观显示,那该是件多么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">&gt;</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。以上篇已经讲了很多组件的技术,这里就只说出几个重点。其余不多说了。

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

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

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

procedure CMMouseEnter (var Message: TMessage); message CM_MOUSEENTER;

procedure CMMouseLeave (var Message: TMessage); message CM_MOUSELEAVE;

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

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

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

接下来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_MOUSEENTERCM_MOUSELEAVE;将引起TCoolMemo的外观变化,WM_PAINT保存其外观不被擦去。所以要用到一个画组件的函数,即:

drawBorder;

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

另外,相比于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));

光标的位置:

property Position:TPosition read getPosition;

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

TPosition=record //指定光标的行和列

row:longint;

col:longint;

end;

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

最后增加了两个事件

property OnEnter;

property OnExit;

都是从父类中显化出来的,其实就是CM_MOUSEENTERCM_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好看多了,功能也强多了。是吗。

至此已经做了三个组件了,其实不算很复杂,只要理清思绪。到这里似乎可以结束这次的组件制作之旅了,但是还没有。我们似乎还没有做过非可视化组件。所以我想最后一个,就是做一个非可视化组件。想知道是什么,往下看吧。
分享到:
评论

相关推荐

    flash组件的应用

    2. **在线教育**:利用Flash组件制作交互式教程,如模拟实验、知识问答等,提升学习体验。 3. **游戏开发**:游戏中的角色、菜单、控制面板等都可以用Flash组件构建。 4. **移动应用**:尽管现代移动平台不再广泛...

    电信设备-改变移动台外观的薄膜层、组件和方法.zip

    在电信设备领域,移动台(通常指手机)的外观设计是吸引消费者的重要因素之一。"改变移动台外观的薄膜层、组件和方法"的主题聚焦于如何通过创新的技术手段改进手机的外观,提升用户体验。这份资料可能包含了一系列的...

    vue刻度尺组件

    这个名为"vue刻度尺组件"的项目,很可能包含了一个自定义的Vue组件,用于在界面上显示可定制的刻度尺。 刻度尺组件通常由以下几个关键部分组成: 1. **结构(Structure)**:组件的基本HTML结构,包括尺子的主体、...

    iebook 组件皮肤

    iebook的强大之处在于它的可定制性,其中组件皮肤是关键的一部分。这些皮肤决定了出版物的外观和用户体验,为内容增添视觉吸引力。 **一、iebook组件皮肤的作用** iebook组件皮肤主要负责改变软件界面和读者在阅读...

    Axure9.0组件库.7z

    这个组件库是自定义的,意味着它包含了用户或社区制作的独特元素和控件,这些可能超越了默认库中的标准组件。 Axure RP 提供的组件库是设计过程中的重要工具,因为它们可以帮助设计师快速拖放构建页面,而无需从头...

    FLASH电子杂志组件带教程

    3. 示例文件(可能是SWF格式):展示组件实际效果的预览文件,用户可以先预览组件的功能和外观。 学习和使用这个“FLASH电子杂志组件带教程”能帮助设计师和开发者快速创建具有专业水准的电子杂志,无需从零开始...

    Flex高级组件详细介绍

    - **高级皮肤专题**:深入探讨如何使用Flex Skin框架为组件创建自定义外观。 - **自定义数据验证组件**:构建具有复杂数据验证逻辑的组件。 - **布局、导航、状态组件的实践**:详细介绍这些高级组件的使用场景和...

    易语言-易语言纯组件制作好看的软件界面

    每个组件都有自己的属性,如位置、大小、颜色、字体等,通过调整这些属性,我们可以定制组件的外观。例如,改变按钮的背景色和文字颜色,可以使其更符合软件的整体风格;调整文本框的字体和大小,可以使界面更加清晰...

    flash进度条加载组件【超简洁实用】

    标题中的“flash进度条加载组件”指的是在Flash环境中制作的一种用户界面元素,它通常用于显示文件、视频或动画的加载进度。这种组件在网页或应用程序中非常常见,为用户提供了一个可视化的反馈,让他们知道某个过程...

    delphi工控组件,带源程序

    通过研究源码,开发者可以深入理解组件的工作原理,对其进行定制和优化,甚至开发新的组件。这对于提升软件的性能和稳定性,以及解决特定应用场景下的问题,都具有极大的帮助。 在实际应用中,"delphi_gkzj"这个...

    sketchup娱乐设施组件

    在本压缩包中,每个子文件可能代表一个单独的旋转木马组件,比如马匹、车厢、支撑结构或是顶部装饰等,用户可以根据需要选择和组合这些组件,自由定制自己的旋转木马模型。 除了旋转木马之外,这个资源包可能还包含...

    《XP定制不完全攻略》

    4. **个性化定制**:《XP定制不完全攻略》——5、XP个性化定制.pdf专注于如何根据个人喜好和需求调整XP的外观和功能。这包括桌面主题、壁纸、屏保、系统声音、开始菜单等的自定义,以及系统性能优化。 5. **控制...

    电信设备-盖体组件、壳体组件、壳体组件的加工方法及移动终端[1].zip

    这些组件不仅是设备外观的重要组成部分,同时也起到保护内部电子元件、提供结构稳定性的作用。以下将详细介绍这些组件及其加工方法。 盖体组件是电信设备的外表面,它通常包括前盖、后盖以及其他辅助部件,如按键、...

    Android 自定义组件开发

    通过重写构造函数、onDraw()、onMeasure()和onLayout()等关键方法,可以定制组件的行为和外观。 2. 绘制原理:Android的绘图主要依赖于Canvas对象。Canvas提供了丰富的绘图API,如drawRect(), drawText(), draw...

    千千静听 皮肤制作器

    千千静听皮肤制作器则是专为那些喜欢个性化定制的用户设计的工具,允许他们根据自己的喜好来创建独一无二的播放器外观。下面将详细介绍这款皮肤制作器的功能和使用方法,以及制作皮肤过程中涉及的相关知识点。 1. *...

    Windows XP定制完全攻略

    本文档全面介绍了如何定制Windows XP系统,包括基础知识、无人值守安装、使用nLite和DPS工具、个性化定制、控制安装过程以及多合一光盘的制作等内容。通过对这些技术的学习和实践,可以大大提升XP系统的安装效率和...

    Axure web组件库.zip

    使用这个"Axure web组件库",设计师无需从零开始创建每个元素,只需挑选合适的组件并调整细节,就能快速搭建出具有专业外观和交互的Web应用原型。这不仅节省了时间,还使得设计过程更加标准化,提高了团队之间的沟通...

    flex3+component组件.pdf

    组件皮肤编写实际上是对组件外观和感觉的定制。开发者可以使用MXML或AS3来实现组件的皮肤。使用AS3来编写组件皮肤,则需要对Flex组件的内部结构和事件处理有更深入的了解。例如,在编写一个按钮组件的皮肤时,需要...

    微信小程序卡片滑动组件mp-swipe-card-master.zip

    5. **样式设计**:借助WXSS,开发者可以定制卡片的外观,包括尺寸、颜色、边框、阴影等。通过CSS样式,可以实现卡片的圆角、过渡效果,以及卡片之间的间距,提升用户体验。 6. **交互逻辑**:当卡片滑动到边缘时,...

Global site tag (gtag.js) - Google Analytics