Edit: Scroll to question bottom to see answered working code.
I am trying to change the colour of the menu bar on a Form.
I found this site with some advice:
https://www.experts-exchange.com/questions/20150240/Color-on-the-MainMenu.html
I will paste the code itself below.
Unfortunately, it doesn't quite work as I would like. The shortcomings are:
The colour only applies to the menu items, the remaining space to the right of the last menu item is grey. I have set the Form colour to be the same as the menu, but it doesn't change this.
Some of the entries in each menu drop-down should be disabled, and if I don't apply the colouring code they are correctly shown disabled. Applying the colour changes removes this visual effect, and their colour is the same as all the other entries in the menu drop-down.
My questions are:
Is there a pre-rolled menu object out there that will allow me to easily colour the menu bar, including the empty space to the right, and that preserves properties like showing disabled?
If not, could someone point me in the right direction as to what additional changes I need to make to the code that could fix the problems above?
I am a total newbie to Delphi (and coding, really) but if I can get the names of things to look up then I can Google and take it from there.
I'm using Delphi 10.3.
Code copied from the link above:
type
TForm1 = class(TForm)
.....
procedure FormCreate(Sender: TObject);
public
procedure DrawMenuItem(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; Selected: Boolean);
end;
...
procedure TForm1.DrawMenuItem(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; Selected: Boolean);
var
S: String;
begin
with ACanvas do
begin
S := TMenuItem(Sender).Caption;
if Selected then
Brush.Color := clHighLight
else
Brush.Color := clLime;
FillRect(ARect);
DrawText(ACanvas.Handle, PChar(S), Length(S), ARect, DT_SINGLELINE or DT_VCENTER);
end;
end;
procedure AllOnDrawTo(M: TMenuItem; P: TMenuDrawItemEvent);
var
I: Integer;
begin
M.OnDrawItem := P;
for I := 0 to M.Count-1 do
AllOnDrawTo(M.Items[I], P);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
begin
for I := 0 to MM.Items.Count -1 do
AllOnDrawTo(MM.Items[I], DrawMenuItem);
end;
UPDATE: @tom-brunberg gave me the required additions in a comment. Below is the updated code to implement both items I requested. I have kept the original code because I think it is interesting to see the contrast between the two options.
type
TForm1 = class(TForm)
.....
procedure FormCreate(Sender: TObject);
public
procedure AdvancedDrawMenuItem(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; State: TOwnerDrawState);
end;
...
procedure TForm1.AdvancedDrawMenuItem(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; State: TOwnerDrawState);
var
S: String;
begin
with ACanvas do
begin
S := TMenuItem(Sender).Caption;
// Set the highlight colour when the menu item is selected. Grey highlight if disabled.
if odSelected in State then
if odDisabled in State then
Brush.Color := clBtnFace
else
Brush.Color := clGradientActiveCaption
else
Brush.Color := clGradientInactiveCaption;
// Set the colour of the menu item textm, grey if disabled
if odDisabled in State then
Font.Color := clGray
else
Font.Color := clBlack;
// this line fill rest of the top of the form the same colour as the menu. If its the LAST menu item fill rect all way to the right. My example has 8 menu items
if (Parent = nil) and (TMenuItem(Sender).MenuIndex = 8) and not (odSelected in State) then
ARect.Right := Width;
FillRect(ARect);
DrawText(ACanvas.Handle, PChar(S), Length(S), ARect, DT_SINGLELINE or DT_VCENTER);
end;
end;
procedure AdvancedAllOnDrawTo(M: TMenuItem; P: TAdvancedMenuDrawItemEvent);
var
I: Integer;
begin
M.OnAdvancedDrawItem := P;
for I := 0 to M.Count-1 do
AdvancedAllOnDrawTo(M.Items[I], P);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
begin
for I := 0 to MM.Items.Count -1 do
AdvancedAllOnDrawTo(MM.Items[I], AdvancedDrawMenuItem);
end;
// this line fill rest of the top of the form
. To draw the items with different colors when disabled use theOnAdvancedDrawItem()
event instead ofOnDrawItem()
. It has a parameterState: TOwnerDrawState
which offers several different states, includingodDisabled
. See Delphi Help for details – Tom Brunberg