很多東西我們已經(jīng)在上面說過了,這里不多說了,我要直入圖形控件的重點(diǎn)。圖形控件不是封裝Windows的控件,而是Delphi自己畫出來的,那么它肯定有一個(gè)畫控件的函數(shù)。這個(gè)函數(shù)就是:
那么是誰調(diào)用了這個(gè)函數(shù)來引起畫控件呢。Windows有一個(gè)WM_PAINT;消息,當(dāng)一切引起重畫的條件發(fā)生,則會發(fā)送這條消息,再看看TGraphicControl,果然有截獲這個(gè)消息:
而它的子類覆蓋了Paint函數(shù),所以消息處理函數(shù)調(diào)用的實(shí)際上是某個(gè)子類的Paint方法,這個(gè)就是多態(tài)的應(yīng)用了,這里不多說。
既然Paint函數(shù)可以畫圖形控件,那么它是以什么來畫的呢,VCL有一個(gè)Canvas類,它就是用這個(gè)來畫的,在TGraphicControl果然也定義了這個(gè)成員:
可以看出這是一個(gè)只讀的成員,因?yàn)樗幌胪饨鐏碛绊懰?/DIV>
好了,一切已經(jīng)具備了,現(xiàn)在就可以畫上去了。源代碼有詳細(xì)解釋,這里不多說。
在ShapeEx中有兩個(gè)對象屬性,為Pen和Brush。對應(yīng)于他的兩個(gè)對象成員。設(shè)置了這兩個(gè)屬性之后,在對象察看器中就可以展開他們來設(shè)置他們的屬性了。這個(gè)也是對象屬性的一般用法。
似乎沒有什么可說的了,下面看源代碼吧,其中也有很詳細(xì)的說明:
unit shapeExUnit;
interface
uses
SysUtils,Classes,Graphics,Controls,ExtCtrls;
type
//定義了幾種形狀:矩形,正方形,圓角矩形,圓角正方形,橢圓形,圓形,
//增加的圖形:橫線,堅(jiān)線,上三角形,菱形
TShapeType = (stRectangle, stSquare, stRoundRect, stRoundSquare,
stEll
ipse, stCircle,stHLine,stVLine,stTriangle,stDiamond);
TShapeEx = class(TGraphicControl)
private
FPen: TPen;
FBrush: TBrush;
FShape: TShapeType;
procedure SetBrush(Value: TBrush);
procedure SetPen(Value: TPen);
procedure SetShape(Value: TShapeType);
protected
//最重要的函數(shù),在父類TGraphicControl中定義的一個(gè)
//虛函數(shù),當(dāng)?shù)玫絎M_PAINT消息時(shí),調(diào)用該函數(shù)引起重畫
//父類是一個(gè)空函數(shù),以便TGraphicControl的子類復(fù)蓋它。
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
//這個(gè)函數(shù)當(dāng)圖形中的畫筆和畫刷改變時(shí)引起重畫,在設(shè)計(jì)器中最為明顯
procedure StyleChanged(Sender: TObject);
property Align;
property Anchors;
property Brush: TBrush read FBrush write SetBrush;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property Constraints;
property ParentShowHint;
property Pen: TPen read FPen write SetPen;
property Shape: TShapeType read FShape write SetShape default stRectangle;
property ShowHint;
property Visible;
property OnContextPopup;
property OnDragDrop;
property OnDragOver;
property OnEndDock;
property OnEndDrag;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDock;
property OnStartDrag;
end;
implementation
//構(gòu)造函數(shù),ControlStyle確定控件的特征,這里是加上csReplicatable
//使該控件可以用PaintTo方法把它畫到一個(gè)任意的畫布中
//另外還指定Pen和Brush對象的OnChange事件的方法指針給StyleChanged;
constructor TShapeEx.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle + [csReplicatable];
Width := 65;
Height := 65;
FPen := TPen.Create;
FPen.OnChange := StyleChanged;
FBrush := TBrush.Create;
FBrush.OnChange := StyleChanged;
end;
destructor TShapeEx.Destroy;
begin
FPen.Free;
FBrush.Free;
inherited Destroy;
end;
//最重要函數(shù),控件就是以這個(gè)函數(shù)畫出來的。
procedure TShapeEx.Paint;
var
//X:左上角X, Y:左上角Y, W:寬, Y:高 S:寬高中大的值
X, Y, W, H, S: Integer;
begin
//Canvas是父類TGraphicControl的屬性,用于畫控件
//在畫圖之前,要進(jìn)行一些坐標(biāo)點(diǎn)的確定,
with Canvas do
begin
//如果以控件的四個(gè)角來畫圖形,當(dāng)Pen太大時(shí),圖形的邊線
//將比Pen的寬要小一些,所以要進(jìn)行點(diǎn)的重定位。
Pen := FPen;
Brush := FBrush;
X := Pen.Width div 2;
Y := X;
W := Width - Pen.Width + 1;
H := Height - Pen.Width + 1;
//Pen.width的值為0和為1時(shí)是一樣的等于一個(gè)象素
//如果上面Pen.width等于1,則圖形的寬高剛好等于控件的寬高
//如果為0,則圖形寬高要大于控件寬高一個(gè)象素了,所以有了下面的語句
if Pen.Width = 0 then
begin
Dec(W);
Dec(H);
end;
if W < H then S := W else S := H;
//當(dāng)圖形為正方類型的圖形時(shí),需要對圖形的位置進(jìn)行一些調(diào)整
if FShape in [stSquare, stRoundSquare, stCircle] then
begin
Inc(X, (W - S) div 2);
Inc(Y, (H - S) div 2);
W := S;
H := S;
end;
case FShape of
stRectangle, stSquare:
Rectangle(X, Y, X + W, Y + H);
stRoundRect, stRoundSquare:
RoundRect(X, Y, X + W, Y + H, S div 4, S div 4);
stCircle, stEllipse:
Ellipse(X, Y, X + W, Y + H);
//以下是增加的部分。
stHLine:
begin
MoveTo(X, Height div 2);
LineTo(X+W,Height div 2);
end;
stVLine:
begin
MoveTo(Width div 2,Y);
LineTo(Width div 2,Y+H);
end;
stTriangle:
Polygon([Point(X,Y+H-1),Point(X+W-1,Y+H-1),Point(Width div 2,Y)]);
stDiamond:
Polygon([Point(Width div 2,Y),Point(X,Height div 2),
Point(Width div 2,Y+H-1),Point(X+W-1, Height div 2)]);
end;
end;
end;
//Invalidate這個(gè)函數(shù)將使系統(tǒng)發(fā)送WM_PAINT給TGraphicControl
//TGraphicControl的處理函數(shù)將調(diào)用Paint,而它的子類覆蓋了它
//所以實(shí)際就調(diào)用了ShapeEx的Paint函數(shù),從而達(dá)到了重畫的效果
procedure TShapeEx.StyleChanged(Sender: TObject);
begin
Invalidate;
end;
procedure TShapeEx.SetBrush(Value: TBrush);
begin
FBrush.Assign(Value);
end;
procedure TShapeEx.SetPen(Value: TPen);
begin
FPen.Assign(Value);
end;
//設(shè)置圖形,同時(shí)引起重畫,以達(dá)到圖形變化,
//最明顯的效果是在設(shè)計(jì)器時(shí)改變Shape屬性時(shí)看到的變化
procedure TShapeEx.SetShape(Value: TShapeType);
begin
if FShape <> Value then
begin
FShape := Value;
Invalidate;
end;
end;
end.
安裝等方法在上一章已經(jīng)說過了,這里不多說。這一次知道了圖形控件的大概做法,其實(shí)無非就是覆蓋Paint來畫自己的圖形控件,而其他,則和我們上一章的說過的一樣。其實(shí)也很簡單。
以上兩個(gè)控件算是比較簡單,但已經(jīng)講清了很多
組件制作的概念和技巧,看不看得懂就由你了,我也沒有辦法。有一個(gè)有用的技巧就是多看看VCL的源碼,你會學(xué)到更多的東西。
接下來,應(yīng)該要做一個(gè)難一點(diǎn)了吧。想知道是什么,且聽下回分解。