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

33 篇文章 0 订阅
5 篇文章 0 订阅
经过上面的几篇文章的介绍,相信大家已经会自己做一个透明皮肤窗口了,但是要记住,上文因为是基础教程,所以很多细节仍然是需要处理的,例如:
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控件,用于存储图片:




 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值