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

标签 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;

最佳答案

在自定义绘制处理程序中将工具栏的绘制样式设置为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

关于delphi - Delphi 工具按钮(TToolbutton)的剥离效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8493024/

相关文章:

Delphi Firemonkey DX Seattle TTabControl 在 TVertScrollBox 内时无法正确重印

delphi - 是否可以获得类属性的索引?

java - Listview的HashMap背景颜色值

swift - 更改默认的黑色背景颜色

ios - 工具栏在转场后消失 - Swift

android - 如何在 Android 工具栏操作栏中为 Spinner 设置正确的文本大小

forms - 在主窗体之前创建辅助窗体,同时保持 FormMain 作为主窗体?

regex - 使用正则表达式从源代码中提取逗号分隔的单元

Python Bokeh饼图颜色,如何更改

Firefox 扩展在安装时打开一个页面