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

来源:互联网 发布:北方网络视频 编辑:程序博客网 时间:2024/06/05 05:18
经过上面的几篇文章的介绍,相信大家已经会自己做一个透明皮肤窗口了,但是要记住,上文因为是基础教程,所以很多细节仍然是需要处理的,例如:
1、为了加快速度,实际上可以先用MakeBmp函数制作好皮肤图片,平均颜色就是取图片右下角的一个点即可。例如QQ的皮肤包就是这么干的。
2、如果实在想运行时计算,那么可以先将图片缩小,再计算平均颜色。这样一来,循环的次数就减少了,而效果是一样的。
3、为了美观,边框可以画个线条上去,这样一来立体感就强很多:

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

做成控件形式的话,代码可以更加模块化。我们的控件是分为两个系列: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.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;
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控件,用于存储图片:




 
原创粉丝点击