Is it possible to made a TCombo edit caret 'wider' or to 'bold' it? - delphi-xe2

I have an mode that uses TComboBox.SelStart to indicate progress along the edit text string. In this mode I would like to make some kind of change to the edit caret, for example to widen it to 2 pixels or 'bold' it in some way to indicate this mode and to have it grab more attention. Is this possible?

Yes, as Alex mentioned in his comment, this can be done using API calls. Example:
procedure SetComboCaretWidth(ComboBox: TComboBox; Multiplier: Integer);
var
EditWnd: HWND;
EditRect: TRect;
begin
ComboBox.SetFocus;
ComboBox.SelStart := -1;
Assert(ComboBox.Style = csDropDown);
EditWnd := GetWindow(ComboBox.Handle, GW_CHILD);
SendMessage(EditWnd, EM_GETRECT, 0, LPARAM(#EditRect));
CreateCaret(EditWnd, 0,
GetSystemMetrics(SM_CXBORDER) * Multiplier, EditRect.Height);
ShowCaret(EditWnd);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetComboCaretWidth(ComboBox1, 4); // bold caret
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
SetComboCaretWidth(ComboBox1, 1); // default caret
end;

Related

Firemonkey tEdit OnPaint

I have a tEdit and I want to paint it's rect with a different set of Fill and Stroke colors. I coded as follows:
procedure TForm1.FormCreate (Sender: TObject);
begin
Edit1.OnPaint := HandleEditPaint;
end;
procedure TForm1.HandleEditPaint (Sender: tObject; Canvas: tCanvas; const aRect: tRectF);
begin
Canvas.BeginScene;
Canvas.Fill .Color := TAlphaColorRec.Aqua;
Canvas.Fill .Kind := TBrushKind.bkSolid;
Canvas.Stroke.Color := TAlphaColorRec.Red;
Canvas.Stroke.Kind := TBrushKind.bkSolid;
Canvas.FillRect (aRect, 0, 0, AllCorners, 1, TCornerType.Bevel);
Canvas.DrawRect (aRect, 0, 0, AllCorners, 1, TCornerType.Bevel);
Canvas.EndScene;
end;
It paints the control's rect properly, but it cannot be focused because when clicking on the Control, it enters in a loop that trigger's HandleEditPaint non stop. How can I avoid this to happen? I know that in painting the control's rect, I must take care of the control's text too, but I should concern about the mouse cursor either? Is there a way to achieve this behavior using styles?

TShape - drawing issue on Paint event

I'm stuck in a class derived from TShape.
In the Paint method, I use the Canvas to draw a rectangle. In the Form, I have a TTrackBar that allows to change Left and Top coordinates of the TShape.
It does not matter what values I set to the Left and Top using the TTrackBar, the rectangle does not move accordingly. Instead, when I set those values via code, the rectangle appears in the correct position.
I'm coding a FireMonkey app with Delphi 10.1 Berlin on Windows 10.
unit frmShapeStudy;
interface
type
tMy_Shape = class (tShape)
protected
procedure Paint; override;
public
constructor Create (aOwner: tComponent); override;
procedure Draw;
end;
tformShapeStudy = class (tForm)
trkBarLeft: TTrackBar;
trkBarTop: TTrackBar;
procedure FormCreate (Sender: tObject);
procedure TrackBarChange (Sender: tObject);
end;
var
formShapeStudy: tformShapeStudy;
implementation
{$R *.fmx}
var
My_Shape : tMy_Shape;
lvShapeRect : tRectF ;
procedure tformShapeStudy.FormCreate (Sender: tObject);
begin
My_Shape := tMy_Shape.Create (Self);
with My_Shape do begin
Parent := Self;
TrackBarChange (Self);
end;
end;
procedure tformShapeStudy.TrackBarChange (Sender: TObject);
begin
My_Shape.Draw;
end;
constructor tMy_Shape.Create (aOwner: tComponent);
begin
inherited;
with lvShapeRect do begin
Left := Self.Left;
Top := Self.Top ;
Height := 20;
Width := 20;
end;
end;
procedure tBS_Shape.Draw;
begin
l := formShapeStudy.trkBarLeft.Value;
t := formShapeStudy.trkBarTop .Value;
{`Left & Top` are set with `l & t` or with `120 & 150`
and tested separately, by commenting the propper code lines}
lvShapeRect.Left := l; // this does no work
lvShapeRect.Top := t; // this does no work
lvShapeRect.Left := 120; // this works
lvShapeRect.Top := 150; // this works
Repaint;
end;
procedure tMy_Shape.Paint;
begin
inherited;
with Canvas do begin
Fill .Color := tAlphaColorRec.Aqua;
Stroke.Color := tAlphaColorRec.Blue;
BeginScene;
FillRect (lvShapeRect, 0, 0, Allcorners, 1, tCornerType.Bevel);
DrawRect (lvShapeRect, 0, 0, Allcorners, 1, tCornerType.Bevel);
EndScene;
end;
end;
end.
Sorry Folks! Is the old habit of using Left & Top instead of Position.X & Position.Y. I agree with the new Position way to set Left & Top, but it doesn't make sense that Embarcadero still makes available this properties, but they do nothing in terms of setting Left & Top of the control. Saying it in other words, since those old properties are still available, they should set the Left & Top properties same as Position.X & Position.Y, otherwise it leads to this kind of mistake, where you sware you are setting Left & Top, but the control does not move.
The correct way to set Left & Top is:
Position.X := aLeft;
Position.Y := aTop;
unless Embarcadero changes the behavior of Left & Top properties (wich is very unlikely).

How can I smooth minimize a window before removing the taskbar button when minimize/restore animations are on?

I am minimizing a form to system tray (display a tray icon) while keeping its taskbar button when it is not minimized. This implies removing the taskbar button when the form is minimized and restoring it otherwise.
The simplest way to achieve this is to hide/show the form, a minimized window does not show anyway.
type
TForm1 = class(TForm)
TrayIcon1: TTrayIcon;
procedure TrayIcon1DblClick(Sender: TObject);
protected
procedure WMSize(var Message: TWMSize); message WM_SIZE;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.WMSize(var Message: TWMSize);
begin
inherited;
case Message.SizeType of
SIZE_MINIMIZED:
if not TrayIcon1.Visible then begin
TrayIcon1.Visible := True;
Hide;
end;
SIZE_RESTORED, SIZE_MAXIMIZED:
if TrayIcon1.Visible then begin
Show;
Application.BringToFront;
TrayIcon1.Visible := False;
end;
end;
end;
procedure TForm1.TrayIcon1DblClick(Sender: TObject);
begin
Show;
WindowState := wsNormal;
end;
The above application introduces a visual glitch when "Animate windows when minimizing and maximizing" setting of the OS is on (accessible through 'SystemPropertiesPerformance.exe'). The minimize window animation is skipped. It appears that the animation actually takes place after the window is minimized. In the code, the window is already hidden by then.
One solution could be to have a notification when the window manager is done with the animation and hiding the form after that. I can't find any. When, for instance, you use the taskbar button minimizing the window, the last message sent is the WM_SYSCOMMAND, which doesn't lead to any progress if I move the code (not to mention that a window can be minimized through a ShowWindow and others).
Another solution might involve to know how long the animation takes place. SystemParametersInfo doesn't have it. Similar question here tries to deal with the animation displayed when a window is first shown, although that animation seems to be related with DWM and minimize/maximize animation precedes DWM. No conclusive solution there either. Like in that question, a 250ms delay seems to work fine. But I'm not sure this is a universally sound delay. I'm not even sure a discrete delay would be definitive, perhaps a stutter would cause it to extent (not that it would matter much, but anyway...).
I also tried to actually remove the taskbar button, without hiding the form. But it's more clumsy and it doesn't change the output: the animation is skipped.
Comment about DrawAnimatedRects (which draws no animation when Aero is on) convinced me to go slightly undocumented until I have a better alternative. Methods using DrawAnimatedRects have to determine where to minimize, that's where they use undocumented system tray window class name.
The below code goes undocumented when removing the taskbar button of the form, in particular with the use of the GWLP_HWNDPARENT index of SetWindowLongPtr. In any case, removing the taskbar button is not clumsy as in transforming the window to a tool window and the animation goes smooth.
The code falls back to a timer which hides the form in case removing the taskbar button fails.
type
TForm1 = class(TForm)
TrayIcon1: TTrayIcon;
Timer1: TTimer;
procedure TrayIcon1DblClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
protected
procedure WMSize(var Message: TWMSize); message WM_SIZE;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function ShowTaskbarButton(Wnd: HWND; Show: Boolean = True;
OwnerWnd: HWND = 0): Boolean;
var
ExStyle, HWndParent: LONG_PTR;
IsToolWindow: Boolean;
begin
HwndParent := GetWindowLongPtr(Wnd, GWLP_HWNDPARENT);
ExStyle := GetWindowLongPtr(Wnd, GWL_EXSTYLE);
Result := Show = (HWndParent = 0) and (ExStyle and WS_EX_APPWINDOW <> 0);
if not Result then begin
IsToolWindow := ExStyle and WS_EX_TOOLWINDOW <> 0;
if IsToolWindow then begin
ShowWindow(Wnd, SW_HIDE);
ShowWindowAsync(Wnd, SW_SHOW);
end;
SetLastError(0);
if Show then
SetWindowLongPtr(Wnd, GWL_EXSTYLE, ExStyle or WS_EX_APPWINDOW)
else
SetWindowLongPtr(Wnd, GWL_EXSTYLE, ExStyle and not WS_EX_APPWINDOW);
if not IsToolWindow and (GetLastError = 0) then
SetWindowLongPtr(Wnd, GWLP_HWNDPARENT, OwnerWnd);
Result := GetLastError = 0;
end;
end;
procedure TForm1.WMSize(var Message: TWMSize);
begin
inherited;
case Message.SizeType of
SIZE_MINIMIZED:
if not TrayIcon1.Visible then begin
if not ShowTaskbarButton(Handle, False, Application.Handle) then
Timer1.Enabled := True; // fall back
TrayIcon1.Visible := True
end;
SIZE_RESTORED, SIZE_MAXIMIZED:
if TrayIcon1.Visible then begin
ShowTaskbarButton(Handle);
Application.BringToFront;
TrayIcon1.Visible := False;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Timer1.Interval := 250;
Timer1.Enabled := False;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Hide;
Timer1.Enabled := False;
end;
procedure TForm1.TrayIcon1DblClick(Sender: TObject);
begin
ShowTaskbarButton(Handle);
if not Showing then // used timer to hide
Show;
WindowState := wsNormal;
end;

Why does the image collision causes flashings?

Ok so first of all i'm just messing around in delphi, and still really new to it, but i noticed that whenever i try to make some kind of game , where W,A,S, and D are the buttons which moves an object (TImage) , it starts flashing randomly, i noticed that it happens if the speed is fast, or when it's moving and there is another image (background) behind it...
Most of my "moving" code looks like this:
if key = 's' then begin
for I := 1 to 5 do
sleep(1);
x:=x-2;
Image1.Top := x;
end;
Maybe that causes it, but still it's really annoying. I would be really pleased if you could help with this.
Something like this is better handled using TPaintBox instead.
Have the keystrokes set variables as needed and then call TPaintBox.Invalidate() to trigger a repaint when the OS is ready for it.
The TPaintBox.OnPaint event handler can then draw a TGraphic at the appropriate coordinates specified by the current variable values as needed.
var
X: Integer = 0;
Y: Integer = 0;
procedure TMyForm.KeyPress(Sender: TObject; var Key: Char);
begin
case Key of
'W': begin
Dec(Y, 2);
PaintBox.Invalidate;
end;
'A': begin
Dec(X, 2);
PaintBox.Invalidate;
end;
'S': begin
Inc(Y, 2);
PaintBox.Invalidate;
end;
'D': begin
Inc(X, 2);
PaintBox.Invalidate;
end;
end;
end;
procedure TMyForm.PaintBoxPaint(Sender: TObject);
begin
PaintBox.Canvas.Draw(X, Y, SomeGraphic);
end;

Make Disabled Menu and Toolbar Images look better?

Please see the attached screenshot which illustrates a TToolBar from one of my programs:
Notice the last two images of the Toolbar, they are disabled. The way they have been drawn to appear disabled is not very appealing, in fact in the Delphi IDE some of the images look the same.
The issue I have with it is I want my application to look a lot cleaner. The way the disabled items are drawn doesn't look very good. The TToolBar allows to set a disabled TImageList, I tried making my images black & white but they didn't look right, and would rather not have to always make the images black and white (time and effort). This problem also shows in my menus and popup menus, which don't allow for disabled images anyway.
Is there a way to paint the disabled items to look better on the eye?
If possible I would rather not look to use 3rd Party Controls. I know the Jedi Components allow disabled images for the menu etc, but would prefer a way to not resort too 3rd Party Components, when possible I would much prefer to use the standard issue VCL, especially as sometimes I use the TActionMainMenuBar to draw Office Style menus, which match the TToolBar when DrawingStyle is set to gradient.
EDIT
I have accepted RRUZ's answer, is it possible though to accept David's answer as well, both are very good answers and would like the answer to be shared between them if possible.
Thanks.
Sometime Ago i wrote a patch to fix this behavior. the key is patch the code of the TCustomImageList.DoDraw function, the technique used is similar to the used by the delphi-nice-toolbar app, but instead of patch a bpl IDE in this case we patch the function in memory.
Just include this unit in your project
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, Proc, #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, Proc, #BackupCode, SizeOf(BackupCode), 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, 0, 0, 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, X, Y, Width, Height, MaskBitMap.Canvas.Handle, 0, 0, SRCERASE);
BitBlt(Canvas.Handle, X, Y, Width, Height, GrayBitMap.Canvas.Handle, 0, 0, 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.
and the result will be
I submitted a QC report for a related issue over a year ago, but that was for menus. I've never seen this for TToolbar since it is a wrapper to the common control and the drawing is handled by Windows.
However, the images you are seeing are clearly as result of the VCL calling TImageList.Draw and passing Enabled=False – nothing else looks that bad! Are you 100% sure this really is a TToolbar?
The fix will surely be to avoid TImageList.Draw and call ImageList_DrawIndirect with the ILS_SATURATE.
You may need to modify some VCL source. First find the location where the toolbar is being custom drawn and call this routine instead of the calls to TImageList.Draw.
procedure DrawDisabledImage(DC: HDC; ImageList: TCustomImageList; Index, X, Y: Integer);
var
Options: TImageListDrawParams;
begin
ZeroMemory(#Options, SizeOf(Options));
Options.cbSize := SizeOf(Options);
Options.himl := ImageList.Handle;
Options.i := Index;
Options.hdcDst := DC;
Options.x := X;
Options.y := Y;
Options.fState := ILS_SATURATE;
ImageList_DrawIndirect(#Options);
end;
An even better fix would be to work out why the toolbar is being custom drawn and find a way to let the system do it.
EDIT 1
I've looked at the Delphi source code and I'd guess that you are custom drawing the toolbar, perhaps because it has a gradient. I never even knew that TToolbar could handle custom drawing but I'm just a plain vanilla kind of guy!
Anyway, I can see code in TToolBar.GradientDrawButton calling the TImageList.Draw so I think the explanation above is on the right track.
I'm fairly sure that calling my DrawDisabledImage function above will give you better results. If could find a way to make that happen when you call TImageList.Draw then that would, I suppose, be the very best fix since it would apply wholesale.
EDIT 2
Combine the function above with #RRUZ's answer and you have an excellent solution.
Solution from #RRUZ dosn't work if you use LargeImages in ActionToolBar. I made changes to the #RRUZ code to work with LargeImages in ActionToolBar.
unit unCustomImageDrawHook;
interface
uses
Windows,
SysUtils,
Graphics,
ImgList,
CommCtrl,
Math,
Vcl.ActnMan,
System.Classes;
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);
TCustomActionControlHook = class(TCustomActionControl);
var
DoDrawBackup : TXRedirCode;
DoDrawBackup2 : 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: SIZE_T;
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;
procedure UnhookProc(Proc: Pointer; var BackupCode: TXRedirCode);
var
n: SIZE_T;
begin
if (BackupCode.Jump <> 0) and (Proc <> nil) then
begin
Proc := GetActualAddr(Proc);
Assert(Proc <> nil);
WriteProcessMemory(GetCurrentProcess, Proc, #BackupCode, SizeOf(BackupCode), 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, 0, 0, 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, X, Y, Width, Height, MaskBitMap.Canvas.Handle, 0, 0, SRCERASE);
BitBlt(Canvas.Handle, X, Y, Width, Height, GrayBitMap.Canvas.Handle, 0, 0, SRCINVERT);
finally
GrayBitMap.Free;
MaskBitMap.Free;
end;
end;
end;
end;
procedure New_Draw2(Self: TObject; const Location: TPoint);
var
ImageList: TCustomImageList;
DrawEnabled: Boolean;
LDisabled: Boolean;
begin
with TCustomActionControlHook(Self) do
begin
if not HasGlyph then Exit;
ImageList := FindImageList(True, LDisabled, ActionClient.ImageIndex);
if not Assigned(ImageList) then Exit;
DrawEnabled := LDisabled or Enabled and (ActionClient.ImageIndex <> -1) or
(csDesigning in ComponentState);
ImageList.Draw(Canvas, Location.X, Location.Y, ActionClient.ImageIndex,
dsTransparent, itImage, DrawEnabled);
end;
end;
procedure HookDraw;
begin
HookProc(#TCustomImageListHack.DoDraw, #New_Draw, DoDrawBackup);
HookProc(#TCustomActionControlHook.DrawLargeGlyph, #New_Draw2, DoDrawBackup2);
end;
procedure UnHookDraw;
begin
UnhookProc(#TCustomImageListHack.DoDraw, DoDrawBackup);
UnhookProc(#TCustomActionControlHook.DrawLargeGlyph, DoDrawBackup2);
end;
initialization
HookDraw;
finalization
UnHookDraw;
end.
Take a look at this Delphi IDE fix. Maybe you can mimic it's implementation.
Use TActionToolbar , TActionmanager , Timagelist
Set action managers image list to a Timagelist. and set Disabledimages to another imagelist

Resources