【问题标题】:Stripping effects on Delphi toolbuttons (TToolbutton)Delphi 工具按钮上的剥离效果 (TToolbutton)
【发布时间】:2012-01-19 13:13:50
【问题描述】:

我正在尝试从使用 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;

【问题讨论】:

  • 因为它是delphi,您可以从父对象继承,并且在initialize() 之后,您可以通过在其中覆盖它来设置值,如果您愿意的话,您是否有对象声明的代码示例或您如何实例化对象...?
  • 好的,我添加了我的代码,我认为它不一定有帮助,但是你覆盖了什么?我不认为制作我自己的 TToolButton 会有所帮助,因为现有的绘画功能甚至没有完成我想要摆脱的东西。也许我只需要设置defaultdraw := false 并自己做所有事情。
  • 你在哪里有这个 ToolBar1 := TToolBar.Create(Self);我想你会想要改变那个实例。我也看不到所有者是谁,我看到了 Parent .. 所以基本上你想创建对象,分配父对象,所有者将是控件所在的表单或面板,然后设置你的属性/创建它Initialize() 你想要一个 Inherited 行。我在这台笔记本电脑上没有 delphi,它在我的另一台笔记本电脑上。

标签: delphi colors toolbar highlighting


【解决方案1】:

在自定义绘制处理程序中将工具栏的绘制样式设置为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 的窗口过程,即“案例”看起来像:

  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

【讨论】:

  • 特别是,我想禁用边框,使用渐变的 IMO 实际上看起来比 dsNormal 更好,但这并不能解决问题。我要去掉的是边框。
  • 我试过了,看起来一模一样。也许这与带有真实标题的按钮而不是只是图片的按钮有关。
  • @Peter - 最初我在 XP 上测试并且它工作,现在在 Vista 和 7 上检查,你是对的。 AFAICS VCL 返回 NM_CUSTOMDRAW 的正确结果,但这些操作系统似乎忽略了 TBCDRF_NOEDGES。
  • @Peter - 我已经更新了答案,现在在 Vista 和 7 上也没有绘制按钮边框。
  • 太棒了,谢谢你们给了我一条鱼并教我钓鱼——这是我在 SO 上得到的最佳答案(自测试版以来我一直在使用它)
猜你喜欢
  • 2017-05-11
  • 2016-11-02
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-08
  • 1970-01-01
相关资源
最近更新 更多