Delphi工具按钮的剥离效果(TToolbutton)

时间:2011-12-13 16:56:24

标签: delphi colors toolbar highlighting

我正在尝试从使用Toolbar2000切换到常规工具栏,因为似乎没有Delphi XE2版本,看起来它使用了一些程序集,我真的不想处理它,如果我不必。 (我真的很喜欢使用Delphi工具栏的淡入效果)

但是,我不喜欢的是按钮的背景会得到常规的蓝色按钮处理。我知道如何改变颜色,但是我可以不改变颜色并且按钮周围没有边框吗?

我已经实现了'OnAdvancedCustomDrawButton',但是可用的标志看起来似乎不正常,我不确定它们如何与渐变颜色和热门轨道颜色相互作用,我最终会有一些奇怪的闪烁或怪异黑色背景。

以下是我创建工具栏的方法

ToolBar1 := TToolBar.Create(Self);
ToolBar1.DoubleBuffered := true;
ToolBar1.OnAdvancedCustomDrawButton := Toolbar1CustomDrawButton;
ToolBar1.Transparent := false;
ToolBar1.Parent := Self;
ToolBar1.GradientEndColor := $7ca0c2; //RGB(194, 160, 124);
ToolBar1.GradientStartColor := $edeeed; //RGB(237, 238, 124);
ToolBar1.Indent := 5;
ToolBar1.Images := Normal;
ToolBar1.DrawingStyle := dsGradient;
ToolBar1.HotImages := Over;
ToolBar1.AutoSize := True;
ToolBar1.Visible := False;

以下是我如何创建按钮(循环中):

ToolButton := TToolButton.Create(ToolBar1);
ToolButton.Parent := ToolBar1;
ToolButton.ImageIndex := ToolButtonImages[Index].ImageIndex;
ToolButton.OnClick := ToolButtonClick;

这是我的AdvancedCustomDrawButton函数

procedure TMyForm.Toolbar1CustomDrawButton(Sender: TToolBar; Button: TToolButton;
    State: TCustomDrawState; Stage: TCustomDrawStage;
    var Flags: TTBCustomDrawFlags; var DefaultDraw: Boolean);
begin
  Flags := [tbNoEdges, tbNoOffset];
  DefaultDraw := True;
end;

1 个答案:

答案 0 :(得分:2)

将工具栏的绘图样式设置为dsNormal,并在自定义绘制处理程序中将Flags设置为[tbNoEdges]。

<强>更新

虽然以上适用于2K和XP,但Vista和7似乎在没有绘制按钮背景时不绘制边框。不幸的是,用VCL提供TTBCustomDrawFlags来实现这一点是不可能的,所以我们无法摆脱自定义绘图处理程序中的边框。

如果工具栏位于表单本身,我们可以为WM_NOTIFY设置处理程序,因为通知消息将发送到父窗口:

type
  TForm1 = class(TForm)
    ..
  private
    procedure WMNotify(var Msg: TWMNotify); message WM_NOTIFY;
    ..
  ..

procedure TForm1.WMNotify(var Msg: TWMNotify);
begin
  inherited;
  if (Msg.NMHdr.code = NM_CUSTOMDRAW) and
      Assigned(Toolbar1) and (Toolbar1.HandleAllocated) and
      (Msg.NMHdr.hwndFrom = ToolBar1.Handle) then

    case PNMTBCustomDraw(Msg.NMHdr).nmcd.dwDrawStage of
      CDDS_PREPAINT: Msg.Result := Msg.Result or CDRF_NOTIFYITEMDRAW;
      CDDS_ITEMPREPAINT: Msg.Result := TBCDRF_NOEDGES or TBCDRF_NOBACKGROUND;
                             // NOEDGES for 2K, XP, // NOBACKGROUND for Vista 7
    end;
end;

如果工具栏是另一个窗口(如面板)的父级,那么我们需要子类化工具栏:

type
  TForm1 = class(TForm)
    ..
  private
    FSaveToolbarWndProc: TWndMethod;
    procedure ToolbarWndProc(var Msg: TMessage);
    ..
..

uses
  commctrl;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ..
  FSaveToolbarWndProc := ToolBar1.WindowProc;
  ToolBar1.WindowProc := ToolbarWndProc;
end;

procedure TForm1.ToolbarWndProc(var Msg: TMessage);
begin
  FSaveToolbarWndProc(Msg);

  if (Msg.Msg = CN_NOTIFY) and
      (TWMNotify(Msg).NMHdr.hwndFrom = ToolBar1.Handle) and
      (TWMNotify(Msg).NMHdr.code = NM_CUSTOMDRAW) then begin

    case PNMTBCustomDraw(TWmNotify(Msg).NMHdr)^.nmcd.dwDrawStage of
      CDDS_PREPAINT: Msg.Result := CDRF_NOTIFYITEMDRAW;
      CDDS_ITEMPREPAINT: Msg.Result := TBCDRF_NOEDGES or TBCDRF_NOBACKGROUND;
    end;
  end;
end;

(请注意,绘图风格仍需dsNormal。)


使用此解决方案,您无需为自定义绘图添加处理程序。但是如果你还是需要/想要的话,你可能需要'或'Msg.Result和一个VCL的窗口程序返回,即'case'看起来像:

  CDDS_PREPAINT: Msg.Result := Msg.Result or CDRF_NOTIFYITEMDRAW;
  CDDS_ITEMPREPAINT: Msg.Result :=
                    Msg.Result or TBCDRF_NOEDGES or TBCDRF_NOBACKGROUND;

当我们在表单上处理WM_NOTIFY时也一样。


可能还有其他方法可以实现相同,自定义绘图是一个广泛的主题。如果你想深入研究它,我建议你从下面的链接开始解决手头的问题:

About Custom Draw
NM_CUSTOMDRAW (toolbar) notification code
NMCUSTOMDRAW structure
NMTBCUSTOMDRAW structure