请参阅附件屏幕截图,其中显示了我的一个程序中的TToolBar:
注意工具栏的最后两个图像,它们被禁用。他们被绘制为禁用的方式并不是非常有吸引力,实际上在Delphi IDE中,一些图像看起来是一样的。
我的问题是,我希望我的应用程序看起来更清洁。禁用物品的绘制方式看起来不是很好。 TToolBar允许设置一个禁用的TImageList,我试图让我的图像为黑色&白色,但他们看起来不正确,宁可不必总是使图像成为黑白(时间和精力)。此问题也显示在我的菜单和弹出菜单中,这些菜单不允许禁用图像。
有没有办法画出残疾的物品看起来更好看?
如果可能,我宁可不要使用第三方控制。我知道绝地组件允许禁用的图像的菜单等,但更喜欢一种方式不要采取太多的第三方组件,如果可能我更喜欢使用标准问题VCL,特别是有时我使用TActionMainMenuBar绘制Office样式菜单,当DrawingStyle设置为渐变时,与TToolBar匹配。
编辑
我已经接受了RRUZ的答复,是否可以接受David的答案,两者都是非常好的答案,如果可能,他们希望在他们之间共享答案。
谢谢。
解决方法
有时我写了一个补丁来解决这个问题。关键是修补了
TCustomImageList.DoDraw
功能的代码,所使用的技术与
delphi-nice-toolbar
应用程序使用的技术相似,但是在这种情况下,我们将修补内存中的功能,而不是修补bpl IDE。
只需将此单元包含在您的项目中
unit uCustomImageDrawHook; interface uses Windows,SysUtils,Graphics,ImgList,CommCtrl,Math; implementation type TJumpOfs = Integer; PPointer = ^Pointer; PXRedirCode = ^TXRedirCode; TXRedirCode = packed record Jump: Byte; Offset: TJumpOfs; end; PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp; TAbsoluteIndirectJmp = packed record OpCode: Word; Addr: PPointer; end; TCustomImageListHack = class(TCustomImageList); var DoDrawBackup : TXRedirCode; function GetActualAddr(Proc: Pointer): Pointer; begin if Proc <> nil then begin if (Win32Platform = VER_PLATFORM_WIN32_NT) and (PAbsoluteIndirectJmp(Proc).OpCode = $25FF) then Result := PAbsoluteIndirectJmp(Proc).Addr^ else Result := Proc; end else Result := nil; end; 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,@Code,SizeOf(Code),n); end; end; procedure UnhookProc(Proc: Pointer; var BackupCode: TXRedirCode); var n: Cardinal; begin if (BackupCode.Jump <> 0) and (Proc <> nil) then begin Proc := GetActualAddr(Proc); Assert(Proc <> nil); WriteProcessMemory(GetCurrentProcess,n); BackupCode.Jump := 0; end; end; procedure Bitmap2GrayScale(const BitMap: TBitmap); type TRGBArray = array[0..32767] of TRGBTriple; PRGBArray = ^TRGBArray; var x,y,Gray: Integer; Row : PRGBArray; begin BitMap.PixelFormat := pf24Bit; for y := 0 to BitMap.Height - 1 do begin Row := BitMap.ScanLine[y]; for x := 0 to BitMap.Width - 1 do begin Gray := (Row[x].rgbtRed + Row[x].rgbtGreen + Row[x].rgbtBlue) div 3; Row[x].rgbtRed := Gray; Row[x].rgbtGreen := Gray; Row[x].rgbtBlue := Gray; end; end; end; //from ImgList.GetRGBColor function GetRGBColor(Value: TColor): DWORD; begin Result := ColorToRGB(Value); case Result of clNone: Result := CLR_NONE; clDefault: Result := CLR_DEFAULT; end; end; procedure New_Draw(Self: TObject; Index: Integer; Canvas: TCanvas; X,Y: Integer; Style: Cardinal; Enabled: Boolean); var MaskBitMap : TBitmap; GrayBitMap : TBitmap; begin with TCustomImageListHack(Self) do begin if not HandleAllocated then Exit; if Enabled then ImageList_DrawEx(Handle,Index,Canvas.Handle,X,Y,GetRGBColor(BkColor),GetRGBColor(BlendColor),Style) else begin GrayBitMap := TBitmap.Create; MaskBitMap := TBitmap.Create; try GrayBitMap.SetSize(Width,Height); MaskBitMap.SetSize(Width,Height); GetImages(Index,GrayBitMap,MaskBitMap); Bitmap2GrayScale(GrayBitMap); BitBlt(Canvas.Handle,Width,Height,MaskBitMap.Canvas.Handle,SRCERASE); BitBlt(Canvas.Handle,GrayBitMap.Canvas.Handle,SRCINVERT); finally GrayBitMap.Free; MaskBitMap.Free; end; end; end; end; procedure HookDraw; begin HookProc(@TCustomImageListHack.DoDraw,@New_Draw,DoDrawBackup); end; procedure UnHookDraw; begin UnhookProc(@TCustomImageListHack.DoDraw,DoDrawBackup); end; initialization HookDraw; finalization UnHookDraw; end.
结果将是