首先,我已经知道当你实现a时TSpeedButton,当你分配它时Glyph,如果你没有多个字形,那么NumGlyphs应该是1,当它被禁用时,它将自动使用相同的图像自动生成一个禁用版本的字形.
但是,在我的情况下,我正在为此速度按钮分配一个动作.在TActionManager既有的Images和DisabledImages指向非常相同TImageList.我还测试了没有任何DisabledImages分配,以及使用全黑蒙版创建图像的副本,并通过分配DisabledImages.
启用时,字形显示正常(基于操作上设置的图像).但是当它被禁用时,图像中只有纯黑色将用于禁用的图像.任何具有除纯黑色之外的任何颜色,甚至略微偏黑的颜色都被完全忽略,并且在渲染禁用图像时不包括在内.
以下是测试启用图像与自动生成的禁用图像之间的比较.图像只是一个16x16位图,有一些垂直线.从最右边开始,一条完全黑色的线条,然后是它左边略微更亮的线条.
如您所见,禁用时,它只考虑完全黑线.下一条线只比完全黑色轻一点.
我不能自己分配Glyph属性,因为它将被分配给它的动作覆盖.我也无法在图像列表上设置双字形宽图像,因为这些图像广泛用于许多其他没有多个字形概念的地方.我也不想对我的图像使用全黑.
当分配了一个动作时,如何禁用TSpeedButton(由于禁用TAction)以显示禁用(灰显)图像?
注意:同样的情况发生在TBitBtn或依赖于任何控制依赖于Glyph.
u44169002.pas
unit u44169002;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Buttons, System.ImageList,
Vcl.ImgList, System.Actions, Vcl.ActnList, Vcl.PlatformDefaultStyleActnCtrls, Vcl.ActnMan, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Actions: TActionManager;
actTest: TAction;
ImageList: TImageList;
SpeedButton1: TSpeedButton;
BitBtn1: TBitBtn;
procedure actTestExecute(Sender: TObject); …Run Code Online (Sandbox Code Playgroud) 我不想问关于组件外观的太多问题,但是现在在应用程序中出现看起来同样重要.
无论如何,请看下面的图像:

两者都使用TActionManager和TActionMainMenuBar来创建我的主菜单.图像左侧的菜单使用平台默认样式,右侧的菜单使用我的TActionManager定义的XP样式.
注意当左侧菜单突出显示时,字形保持不变,这是完美的.
现在看看右边的XP风格菜单,字形绘制一个阴影,稍微弹出,你可以看到透明度使得字形看起来有些奇怪.
我想为我的UI启用XP风格,但我不喜欢绘制字形的方式.我还想将我的TToolbar更改为TActionToolBar并应用相同的XP样式,但这也会使字形也相同.
如何在TActionManager中定义XP样式菜单,而不是像这样渲染字形?
谢谢.
编辑
现在结果是,应用了以下答案中的一些技术:

克雷格.
我尝试用我自己的版本即时替换Delphi内置函数.
function ShortCutToTextOverride(ShortCut: TShortCut): string;
begin
if SomeCondition then
Result := Menus.ShortCutToText // after patching the pointer equals ShortCutToTextOverride
else
begin
// My own code goes here
end;
end;
FastcodeAddressPatch(@Menus.ShortCutToText, @ShortCutToTextOverride);
Run Code Online (Sandbox Code Playgroud)
修补后,无法再访问原始功能.无论如何都可以访问它?
我需要将目录中的文件显示到 TVirtualStringTree。所以,我使用 SHGetFileInfo 来获取文件的图标。但似乎我只能获得“正常”图标(以下屏幕截图的左侧)。如果是这样,TVirtualStringTree 可以将图标绘制为“禁用”吗?就像您禁用了 a 节点一样。请看屏幕截图:

更新
Soft Gems 论坛中有一个类似的帖子。我可以获得图标的矩形,然后自己绘制图标。我正在使用 TcxImageList,它可以轻松绘制“禁用”图标。我首先在 GetImageIndex 事件中分配了一个不存在的图像索引,所以我有一个空间来绘制图标。然后使用以下代码进行绘制。
procedure TfrmMain.tvSharesAfterItemPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect);
var
rImage: TRect;
OffsetLeft: Integer;
begin
rImage := ItemRect;
with TVirtualStringTree(Sender) do begin
if (toShowRoot in TreeOptions.PaintOptions) then
OffsetLeft := Indent * (GetNodeLevel(Node) + 1)
else
OffsetLeft := Indent * GetNodeLevel(Node);
Inc(rImage.Left, Margin + OffsetLeft);
Inc(rImage.Top, (NodeHeight[Node] - Images.Height) div 2);
rImage.Right := rImage.Left + Images.Width;
rImage.Bottom := rImage.Top + Images.Height;
end;
// draw the …Run Code Online (Sandbox Code Playgroud) 我使用RRUZ的解决方案来改善禁用图像的外观.以下摘录,例如:
procedure HookProc(Proc, Dest: Pointer; var BackupCode: TXRedirCode);
var
n: DWORD;
Code: TXRedirCode;
begin
Proc := GetActualAddr(Proc);
Assert(Proc <> nil);
if ReadProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n) then
begin
Code.Jump := $E9;
Code.Offset := PAnsiChar(Dest) - PAnsiChar(Proc) - SizeOf(Code);
WriteProcessMemory(GetCurrentProcess, Proc, @Code, SizeOf(Code), n);
end;
end;
Run Code Online (Sandbox Code Playgroud)
与Delphi 2007一起工作得很好,但是当我在Delphi XE10中使用它时,我得到了
E2033实际和正式var参数的类型必须相同
在调用ReadProcessMemory和WriteProcessMemory时
据我所知,类型是相同的.任何人都可以告诉我什么'需要改变?