透明皮肤控件设计系列(四):皮肤窗口完结篇

12条评论 2013-08-11 admin

经过上面的几篇文章的介绍,相信大家已经会自己做一个透明皮肤窗口了,但是要记住,上文因为是基础教程,所以很多细节仍然是需要处理的,例如:

1、为了加快速度,实际上可以先用MakeBmp函数制作好皮肤图片,平均颜色就是取图片右下角的一个点即可。例如QQ的皮肤包就是这么干的。

2、如果实在想运行时计算,那么可以先将图片缩小,再计算平均颜色。这样一来,循环的次数就减少了,而效果是一样的。

3、为了美观,边框可以画个线条上去,这样一来立体感就强很多:

nc11

 

另外,还要其它一些细节,例如 Caption,如果平均颜色是黑色,那么字体应该自动换成白色。我在这里偷了个懒,直接使用了Blur算法,根据字体直接在下面画一个对应的浅色区域,这样一来,即使背景色偏暗,也不影响标题的字体颜色。

另外,还可以做成控件形式,例如我们的AQ控件:

nc12

 

做成控件形式的话,代码可以更加模块化。我们的控件是分为两个系列:NC系列和 CLIENT 系列。顾名思义,NC系列的控件就是工作于NC区的,CLIENT则是工作于CLIENT区。

看一下我们的鼠标信息函数:

function OnClientMouseMove(): Boolean;
var
P: TPoint;
begin
P.X := Short(LoWord(Message.lParam));
P.Y := short(HiWord(Message.lParam));
ClientToScreen(FForm.Handle, P);
Result := NCMouseMove(P.X, P.Y – 1)
end;

function OnClientMouseUp(): Boolean;
var
P: TPoint;
begin
P.X := Short(LoWord(Message.lParam));
P.Y := short(HiWord(Message.lParam));
ClientToScreen(FForm.Handle, P);
Result := NCMouseUp(P.X, P.Y)
end;

WM_NCMOUSEMOVE:
begin
if (not NCMouseMove(LoWord(Message.lParam), HiWord(Message.lParam))) then
FOldWinProc(Message)
else
Message.Result := 0;
end;

……

也就是说,窗口、NC的鼠标消息,都是直接传递给NC函数去处理,以鼠标移动为例,处理如下:

function TAQCustomForm.NCMouseDown(X, Y: Integer): Boolean;
var
i: Integer;
begin
with FForm do
for i := ComponentCount – 1 downto 0 do
if Components[i] is TAQCustomNCCtrlBase then
with TAQCustomNCCtrlBase(Components[i]) do
if PtInRect(GetWindowRect(), Point(X, Y)) then
begin
FIsMouseDown := True;
MouseDown(X, Y);
Result := True;
exit;
end;
Result := False;
end;

也就是说,如果鼠标位于NC控件上,则通知控件处理:

procedure TAQCustomNCCtrl.MouseDown(X, Y: Integer);
begin
if Assigned(FOnMouseDown) then
FOnMouseDown(Self, X, Y);
end;

procedure TAQCustomNCButton.Paint(Canvas: TCanvas);
begin
if SkinData = nil then
Exit;
if not Visible then Exit;
if IsMouseDown and IsMouseEnter and (GetPicDown().Graphic <> nil) then
Canvas.StretchDraw(Rect(FLeft, FTop, FLeft + FWidth, FTop + FHeight), GetPicDown.Graphic)
else
if IsMouseEnter and (GetPicHighLight().Graphic <> nil) then
Canvas.StretchDraw(Rect(FLeft, FTop – 1, FLeft + FWidth, FTop + FHeight – 1), GetPicHighLight.Graphic)
else
Canvas.StretchDraw(Rect(FLeft, FTop, FLeft + FWidth, FTop + FHeight), GetPicNormal.Graphic);
end;

TAQSysMinButton = class(TAQCustomSysButton)
private
protected
procedure Click(); override;
function GetPicNormal(): TPicture; override;
function GetPicDown(): TPicture; override;
function GetPicHighLight(): TPicture; override;
public
constructor Create(AOwner: TComponent); override;
published
end;

 

这样处理后,需要多增加一个NC控件的话,只要从基类继承,然后重载GetPicXXX函数,返回状态图片即可,而窗口代码不需要作任何修改。

我们的演示代码使用了一个Timer检测状态,改成控件后,是可以去掉的:

function TAQCustomForm.NCMouseMove(X, Y: Integer): Boolean;
procedure CheckPrev(New: TAQCustomNCCtrlBase);
var
i: Integer;
begin
with FForm do
for i := 0 to ComponentCount – 1 do
if (Components[i] is TAQCustomNCCtrlBase) and (Components[i] <> New) then
with TAQCustomNCCtrlBase(Components[i]) do
if FIsMouseEnter then
begin
FIsMouseEnter := False;
if not FIsMouseDown then
ReleaseCapture();
MouseLeave();
end;
end;
var
i: Integer;
begin
Result := False;
with FForm do
for i := ComponentCount – 1 downto 0 do
if Components[i] is TAQCustomNCCtrlBase then
with TAQCustomNCCtrlBase(Components[i]) do
if PtInRect(GetWindowRect(), Point(X, Y)) then
begin
MouseMove(X, Y);
if not FIsMouseEnter then
begin
CheckPrev(TAQCustomNCCtrlBase(FForm.Components[i]));
FIsMouseEnter := True;
SetCapture(FForm.Handle);
MouseEnter();
end;
Result := True;
exit;
end else
if FIsMouseEnter then
begin
FIsMouseEnter := False;
if not FIsMouseDown then
ReleaseCapture();
MouseLeave();
end;
end;

 

另外,为了多个窗口共享一张图片,可以制作一个DATA控件,用于存储图片:

nc13

nc14

 

 

后面我们将介绍透明控件、滚动条等的处理。

分类:界面设计

12条评论 发表评论

发表评论

(必填)

(必填), (Hidden)

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

TrackBack URL  |  这篇文章上的评论的RSS feed


近期文章

近期评论

文章归档

分类目录