开发者

drawing applications mainmenu using Delphi [duplicate]

This question already has an answer here: Closed 11 years ago.

Possible Duplicate:

Owner Drawing TMainMenu over Aero Glass Form?

Hi,

I am interested in having an application's main menu drawn on the application's caption bar ? A bit like iTunes and Songbird (Windows 7).

Any hints would be helpful - I can draw a button or panel, but no开发者_StackOverflow社区 a menu.

CHeers


It is not possible to relocate a standard Windows menu, Windows places it always right under the caption. Indeed a search with "iTunes" and "WS_CAPTION" shows up some references that say the iTunes window does not have the WS_CAPTION style. I would guess the same to be true with 'Songbird' also. So what these applications doing is to remove the caption to have the menu at the top and simulate having a caption (they might even not have a standard menu and their own menu implementation, but I don't know about that).

You can remove the caption of a Delphi form by removing the style:

  SetWindowLong(Handle, GWL_STYLE,
      GetWindowLong(Handle, GWL_STYLE) and not WS_CAPTION);
  SetWindowPos(Handle, 0, 0, 0, 0, 0,
      SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_FRAMECHANGED);

Then the menu will appear at the top (with no caption). You would then fake mouse clicks at the top of the window to be on the caption for being able to move around the window with the mouse. You can achieve this by handling WM_NCHITTEST message. But you have to exclude the area that the menu items occupy;

type
  TForm1 = class(TForm)
    [...]
  private
    procedure WmNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
  public

[...]

procedure TForm1.WmNCHitTest(var Msg: TWMNCHitTest);
var
  Pt: TPoint;
  MenuBarInfo: TMenuBarInfo;
  i, MenuWidth: Integer;
begin
  inherited;

  // calculate the total width of top menu items
  MenuBarInfo.cbSize := SizeOf(MenuBarInfo);
  MenuWidth := 0;
  for i := 0 to MainMenu1.Items.Count - 1 do begin
    GetMenuBarInfo(Handle, OBJID_MENU, 1, MenuBarInfo);
    MenuWidth := MenuWidth + MenuBarInfo.rcBar.Right - MenuBarInfo.rcBar.Left;
  end;

  Pt := ScreenToClient(SmallPointToPoint(Msg.Pos));
  Pt.Y := Pt.Y + MenuBarInfo.rcBar.Bottom - MenuBarInfo.rcBar.Top;
  if (Pt.Y <= GetSystemMetrics(SM_CYCAPTION)) and (Pt.Y >= 0) and
      (Pt.X > MenuWidth) and (Pt.X < ClientWidth) then
    Msg.Result := HTCAPTION;
end;

Depending on the Delphi version you use, you might not succeed with the GetMenuBarInfo call. F.i. D2007 incorrectly declares the TMenuBarInfo structure packed. So you might have to redeclare it and the function before you call the function.

type
  TMenuBarInfo = record
    cbSize: DWORD;
    rcBar: TRect;
    hMenu: HMENU;
    hwndMenu: HWND;
    fBarFocused: Byte;
    fFocused: Byte;
  end;

function GetMenuBarInfo(hend: HWND; idObject, idItem: ULONG;
  var pmbi: TMenuBarInfo): BOOL; stdcall; external user32;

Finally you would probably put some buttons to the far right side for users to be able to minimize, restore etc.. the window.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜