2

Delphi Xe4. Form, ActionManager, ImageList (with 32x32 Icons), ActionMainMenuBar.

I can not ensure that the icons are displayed correctly. What should you do?

Pic1

At the same time, if I apply any vcl style of decoration, it displays fine. But if the style of "Windows" by default, the text moves out of the icon. Help.

Pic2

Pic3

Pic4

Sorry for the bad English.

Gu.
  • 1,947
  • 4
  • 30
  • 49
  • 2
    Your icons are too big. You need to use square icons with size equal to `GetSystemMetrics(SM_CXSMICON)` – David Heffernan Jul 04 '13 at 14:06
  • In TMainMenu can use the icons in 32x32. And then you can not? – Gu. Jul 05 '13 at 05:35
  • I cannot understand that. – David Heffernan Jul 05 '13 at 05:36
  • form. main menu. imagelist (32x32). work fine. http://s1.ipicture.ru/uploads/20130705/zbxq3aHT.jpg and "if I apply any vcl style of decoration, it displays fine" – Gu. Jul 05 '13 at 05:57
  • Your images are only for owner draw XP main menus. What about themed vista menus? Anyway, you are asking for pain here. Menu code in Delphi is flaky. Your problems vanish if you use standard sized icons. – David Heffernan Jul 05 '13 at 06:01
  • 1
    Standard I do not need. And then 32x32 also apply to the standard. Again. In TMainMenu they appear normal. Normally displayed and the application of styles. And there is not normally want drawn. – Gu. Jul 05 '13 at 06:09

1 Answers1

6

This is a valid question, the TActionMainMenuBar is meant to be designed to be able to handle custom icon sizes as menu images, just as the native menus can handle them fine. One indication of that can be found in the comments in the code, f.i. in the below VCL code you can find the comment 16 is standard image size so adjust for larger images.

The faulty code, I believe, is in TCustomMenuItem.CalcBounds in 'ActnMenus.pas'. Below excerpt is from D2007. Notice the line below I commented with some exclamation marks. After the ascendant class TCustomActionControl calculates the positioning of text and image in its CalcLayout method, the TCustomMenuItem ruins it with the hard-coded 24 in the said statement.

procedure TCustomMenuItem.CalcBounds;
var
  AWidth, AHeight: Integer;
  NewTextBounds: TRect;
  ImageSize: TPoint;
  ImageOffset: Integer;
begin
  inherited CalcBounds;
  ImageSize := GetImageSize;
  AHeight := FCYMenu;
  if Separator then
    AHeight := FCYMenu div 3 * 2
  else
    // 16 is standard image size so adjust for larger images
    if ImageSize.Y > 16 then
      AHeight := ImageSize.Y + 4;
  if ActionClient = nil then exit;
  if ImageSize.X <= 16 then
    ImageOffset := 24
  else
    ImageOffset := ImageSize.X + 6;  // Leave room for an image frame
  NewTextBounds := TextBounds;
  OffsetRect(NewTextBounds, 24 - TextBounds.Left,          // <- !!!!!
    AHeight div 2 - TextBounds.Bottom div 2 - 1);
  TextBounds := NewTextBounds;
  ShortCutBounds := Rect(0,0,0,0);
  if ActionClient.ShortCut <> 0 then
  begin
    Windows.DrawText(Canvas.Handle, PChar(ActionClient.ShortCutText), -1,
      FShortCutBounds, DT_CALCRECT);
    // Left offset is determined when the item is painted to make it right justified
    FShortCutBounds.Top := TextBounds.Top;
    FShortCutBounds.Bottom := TextBounds.Bottom;
    AWidth := TextBounds.Right + FShortCutBounds.Right + ImageOffset + Spacing;
  end
  else
    AWidth := TextBounds.Right + TextBounds.Left;
  SetBounds(Left, Top, AWidth, AHeight);
end;


The 24 is an assumption based on images having 16 or less pixels width. What should be used instead is the ImageOffset value calculated just a few lines above. Replace

  OffsetRect(NewTextBounds, 24 - TextBounds.Left,
    AHeight div 2 - TextBounds.Bottom div 2 - 1);

with

  OffsetRect(NewTextBounds, ImageOffset - TextBounds.Left,
    AHeight div 2 - TextBounds.Bottom div 2 - 1);

and you'll have something like this:

dropped menu

You'll notice some other weirdness though, items not having images are still settling for a small image layout. IMO all menu items should have the same basic layout, but the design of action menus allow different layouts for individual items. One other weird thing is the checked state of an item with an image ('Action6'), although I'm not sure if I'm missing a setting here or if it would qualify as a bug otherwise.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169