Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 系统菜单:如何隐藏/移动标准菜单项_Delphi_Winapi_Systemmenu - Fatal编程技术网

Delphi 系统菜单:如何隐藏/移动标准菜单项

Delphi 系统菜单:如何隐藏/移动标准菜单项,delphi,winapi,systemmenu,Delphi,Winapi,Systemmenu,在系统菜单(标题栏左上角)中,我可以添加自己的菜单项。 我还可以删除,例如,DeleteMenu(SysMenu、SC\u MINIMIZE、MF\u BYCOMMAND) 但是,如果我删除标准按钮[恢复、最小化、最大化、大小、关闭],它们的功能将丢失(即最大化按钮不再工作) 有没有办法隐藏这些菜单项或将它们移出系统菜单的第一级? a) 使它们不可见 b) 移动到子菜单 c) 删除但仍获取按钮消息: 最初,窗口标题在右上角只有两个按钮,即最小化和最大化按钮,它们由窗口样式控制。Windows95

在系统菜单(标题栏左上角)中,我可以添加自己的菜单项。 我还可以删除,例如,
DeleteMenu(SysMenu、SC\u MINIMIZE、MF\u BYCOMMAND)

但是,如果我删除标准按钮[恢复、最小化、最大化、大小、关闭],它们的功能将丢失(即最大化按钮不再工作)

有没有办法隐藏这些菜单项或将它们移出系统菜单的第一级? a) 使它们不可见 b) 移动到子菜单 c) 删除但仍获取按钮消息

最初,窗口标题在右上角只有两个按钮,即最小化和最大化按钮,它们由窗口样式控制。Windows95添加了关闭按钮,但接下来的问题是知道何时启用和禁用它。但是等等,我们已经知道何时启用和禁用它:应用程序告诉我们何时启用和禁用SC_CLOSE菜单项。宾果,只需将关闭按钮连接到现有的菜单项(应用程序已经习惯于维护该菜单项),然后神奇地,它就可以工作了。应用程序无需编写特殊代码来支持关闭按钮

现在你知道为什么SC_CLOSE被绑定到按钮上了。因此,防止用户在某些操作期间关闭的正确方法是禁用菜单项

如果出于任何原因坚持删除它,但仍允许关闭窗口,则必须在即将显示系统菜单时删除该项(
WM_INITMENU
),并在菜单关闭后删除系统菜单(
WM_UNINITMENUPOPUP
)。

最初,窗口标题在右上角只有两个按钮,即最小化和最大化按钮,它们由窗口样式控制。Windows95添加了关闭按钮,但接下来的问题是知道何时启用和禁用它。但是等等,我们已经知道何时启用和禁用它:应用程序告诉我们何时启用和禁用SC_CLOSE菜单项。宾果,只需将关闭按钮连接到现有的菜单项(应用程序已经习惯于维护该菜单项),然后神奇地,它就可以工作了。应用程序无需编写特殊代码来支持关闭按钮

现在你知道为什么SC_CLOSE被绑定到按钮上了。因此,防止用户在某些操作期间关闭的正确方法是禁用菜单项

如果出于任何原因坚持删除该项,但仍允许关闭窗口,则必须在系统菜单即将显示时删除该项(
WM_INITMENU
),并在菜单关闭后删除系统菜单(
WM_UNINITMENUPOPUP

a) 使它们不可见

API没有隐藏/不可见菜单项的概念

b) 移动到子菜单

您可以在不影响功能的情况下将项目移动(或者更确切地说是删除和添加)到子菜单中

例如,将“最小化”移动到子菜单:

var
  SysMenu, SubMenu: HMENU;
  StrMin: string;
  StrMinLen: Integer;
begin
  SysMenu := GetSystemMenu(Handle, False);
  StrMinLen := GetMenuString(SysMenu, SC_MINIMIZE, nil, 0, MF_BYCOMMAND);
  if StrMinLen > 0 then begin
    Inc(StrMinLen);
    SetLength(StrMin, StrMinLen);
    GetMenuString(SysMenu, SC_MINIMIZE, PChar(StrMin), StrMinLen, MF_BYCOMMAND);
    SubMenu := CreateMenu;
    if SubMenu <> 0 then begin
      DeleteMenu(SysMenu, SC_MINIMIZE, MF_BYCOMMAND);
      AppendMenu(SubMenu, MF_STRING, SC_MINIMIZE, PChar(StrMin));
      InsertMenu(SysMenu, 0, MF_BYPOSITION or MF_POPUP, SubMenu, 'Minimize->');
      InsertMenu(SysMenu, 1, MF_BYPOSITION or MF_SEPARATOR, 0, nil);
    end;
  end;
c) 删除但仍获取按钮消息

如果删除f.i.“最小化”项,系统不会向窗口发送最小化命令的
WM_SYSCOMMAND
消息。所以没有任何命令可以响应

你仍然可以收听按钮信息,f.i.左键按下。但是,按钮按下/按下消息实际上与按钮单击不同。点击按钮包括三个动作,鼠标下键、捕捉和再次向上点击按钮。如果您仍想这样做,可以举一个例子:

procedure TForm1.WMNCLButtonDown(var Message: TWMNCLButtonDown);
begin
  inherited;
  if (Message.HitTest = HTMINBUTTON) and not IsIconic(Handle) then
    ShowWindow(Handle, SW_MINIMIZE);
end;
a) 使它们不可见

API没有隐藏/不可见菜单项的概念

b) 移动到子菜单

您可以在不影响功能的情况下将项目移动(或者更确切地说是删除和添加)到子菜单中

例如,将“最小化”移动到子菜单:

var
  SysMenu, SubMenu: HMENU;
  StrMin: string;
  StrMinLen: Integer;
begin
  SysMenu := GetSystemMenu(Handle, False);
  StrMinLen := GetMenuString(SysMenu, SC_MINIMIZE, nil, 0, MF_BYCOMMAND);
  if StrMinLen > 0 then begin
    Inc(StrMinLen);
    SetLength(StrMin, StrMinLen);
    GetMenuString(SysMenu, SC_MINIMIZE, PChar(StrMin), StrMinLen, MF_BYCOMMAND);
    SubMenu := CreateMenu;
    if SubMenu <> 0 then begin
      DeleteMenu(SysMenu, SC_MINIMIZE, MF_BYCOMMAND);
      AppendMenu(SubMenu, MF_STRING, SC_MINIMIZE, PChar(StrMin));
      InsertMenu(SysMenu, 0, MF_BYPOSITION or MF_POPUP, SubMenu, 'Minimize->');
      InsertMenu(SysMenu, 1, MF_BYPOSITION or MF_SEPARATOR, 0, nil);
    end;
  end;
c) 删除但仍获取按钮消息

如果删除f.i.“最小化”项,系统不会向窗口发送最小化命令的
WM_SYSCOMMAND
消息。所以没有任何命令可以响应

你仍然可以收听按钮信息,f.i.左键按下。但是,按钮按下/按下消息实际上与按钮单击不同。点击按钮包括三个动作,鼠标下键、捕捉和再次向上点击按钮。如果您仍想这样做,可以举一个例子:

procedure TForm1.WMNCLButtonDown(var Message: TWMNCLButtonDown);
begin
  inherited;
  if (Message.HitTest = HTMINBUTTON) and not IsIconic(Handle) then
    ShowWindow(Handle, SW_MINIMIZE);
end;

塞塔克回答了这个问题:你只能移动它们

下面是使Sysmenu有用的完整最终解决方案,它可以: a) 移动除隐藏在分隔符后面的子菜单之外的所有标准项。 b) 将Form1.PopupMenu1中的菜单项添加到系统菜单 c) 删除它们(在使窗口全屏/无边框之前,因为这会破坏系统菜单) d) 显示系统菜单

procedure TForm1.SysMenuAddRemoveExtraItems(Add:boolean=true);
//
    var
      SysMenu, SubMenu : HMenu;
      const NumItems:integer=0;

    procedure InsertM(Position,I:integer;J:integer=-1;S:string='');
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647987(v=vs.85).aspx
      var M:TMenuItem; H:thandle; Flags:cardinal;
    begin
      M:=PopupMenu1.Items;
      if I>=0 then M:=M.Items[I];
      Flags:=MF_BYPOSITION+MF_STRING;
      if M.Count>1 then Flags:=Flags+MF_POPUP;

      if J>=0 then M:=M.Items[J];
      H:=M.Handle;
      if S='' then S:=M.Caption;
      InsertMenu(SysMenu,Position,Flags,H,pwidechar(S));
      inc(NumItems);
    end;
    procedure InsertSeparator(Position:integer);
    begin
      InsertMenu(SysMenu,Position,MF_BYPOSITION,MF_SEPARATOR,0); {Add a seperator bar to main form-form1}
      inc(NumItems);
    end;
    procedure RemoveItems;
    var i:integer;
    begin
      for i := 1 to NumItems do  //remove items from top
        RemoveMenu(SysMenu,0,MF_BYPOSITION);
      NumItems:=0;
    end;

    procedure DeleteAppend(ID:cardinal); //to move standard menuitems to submenu
    var
      Caption: string;
      CaptionLen: Integer;
    begin
    CaptionLen := GetMenuString(SysMenu, ID, nil, 0, MF_BYCOMMAND);
    if CaptionLen > 0 then begin
      Inc(CaptionLen);
      SetLength(Caption, CaptionLen);
      GetMenuString(SysMenu, ID, PChar(Caption), CaptionLen, MF_BYCOMMAND);

      DeleteMenu(SysMenu, ID, MF_BYCOMMAND);
      AppendMenu(SubMenu, MF_STRING, ID, PChar(Caption));
      end;
    end;
    procedure MoveDefaultSysMenuItemsToSubmenu(Caption:string='';JustSeparator:boolean=false);
    //Can either have a a caption or JustSeparator (submenu will be inaccessible)
    // https://stackoverflow.com/questions/44735708/system-menu-how-to-hide-move-standard-menuitems/44743027#44743027
    begin
    SubMenu := CreateMenu; //make submenu to move them into
      if SubMenu <> 0 then begin
        DeleteAppend(SC_RESTORE);
        DeleteAppend(SC_MOVE);
        DeleteAppend(SC_SIZE);
        DeleteAppend(SC_MINIMIZE);
        DeleteAppend(SC_MAXIMIZE);
        if JustSeparator then begin
            DeleteMenu(SysMenu, 0, MF_BYPOSITION); //remove separator above CLOSE
            InsertMenu(SysMenu, 0, MF_BYPOSITION or MF_POPUP or MF_SEPARATOR, SubMenu, '');
          end else begin
            DeleteMenu(SysMenu, 0, MF_BYPOSITION); //remove separator above CLOSE
            InsertMenu(SysMenu, 0, MF_BYPOSITION or MF_POPUP, SubMenu, PChar(Caption));
            InsertMenu(SysMenu, 1, MF_BYPOSITION or MF_SEPARATOR, 0, nil);
        end;
      end;
    end;
    procedure DestroySubmenu;
      var Info: TMenuItemInfo;
    begin
      Info.cbSize := SizeOf(Info);
      Info.fMask := MIIM_SUBMENU;
      if GetMenuItemInfo(GetSystemMenu(Handle, False), 0, True, Info) then
        DestroyMenu(Info.hSubMenu);
      //GetSystemMenu(Handle, True);
    end;

begin
  SysMenu := GetSystemMenu(Handle, FALSE) ;   {Get system menu}
  //InsertMenu(SysMenu,1,MF_BYPOSITION+MF_STRING,SC_MyMenuItem2,'pqr');
  if Add then begin
    MoveDefaultSysMenuItemsToSubmenu('',true);
 //   InsertSeparator(0);
    InsertM(0,PopupMenu1.Items.Count-2);
    InsertM(0,-1,-1,'Menu'); //help
    InsertM(0,7);
    end
  else begin  //remove items
    RemoveItems;
    DestroySubmenu;
  end;
end;

//------------------------------------    
procedure TForm1.ShowSysMenu;
var P:TPoint;
begin
  P:=ClientToScreen(Point(0,0));
  TrackPopupMenu(GetSystemMenu(Handle, FALSE), TPM_LEFTALIGN+TPM_TOPALIGN+TPM_RETURNCMD+TPM_NONOTIFY,
                 P.X,P.Y,0,self.Handle,nil);
end;

//--------------------------------------------------------------

procedure TForm1.WMSysCommand(var Msg: TWMSysCommand);
//  https://www.delphipower.xyz/guide_7/customizing_the_system_menu.html
var Item: TMenuItem;
begin

Item := PopupMenu1.FindItem (Msg.CmdType, fkCommand);
if assigned(Item) then Item.Click
else
//  case Msg.CmdType of
//    //put any other specials in here
//  else
   inherited;
//  end;
end;
过程TForm1.SysMenuAddRemoveExtraItems(Add:boolean=true);
//
变量
系统菜单,子菜单:菜单;
常量NumItems:integer=0;
过程InsertM(位置,I:integer;J:integer=-1;S:string='';
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms647987(v=vs.85).aspx
VarM:TMenuItem;H:thandle;旗帜:红衣主教;
开始
M:=弹出菜单1.1项;
如果I>=0,则M:=M.Items[I];
标志:=MF\U BYPOSITION+MF\U字符串;
如果M.Count>1,则标志:=标志+MF\U弹出窗口;
如果J>=0,则M:=M.Items[J];
H:=M.Handle;
如果S='',则S:=M.Caption;
插入菜单(SysMenu、Position、Flags、H、pwidechar);
公司(NumItems);
结束;
过程插入分隔符(位置:整数);
开始
插入菜单(SysMenu,Position,MF_BYPOSITION,MF_分隔符,0);{将分隔条添加到主窗体-form1}
公司(NumItems);
结束;
程序删除项;
varⅠ:整数;
开始
对于i:=1到NumItems do//从顶部删除项
移除菜单(SysMenu,0,MF_BYPOSITION);
NumItems:=0;
结束;
过程DeleteAppend(ID:cardinal)//将标准菜单移到子菜单的步骤
变量
标题:字符串;
CaptionLen:整数;
开始
标题栏:=Ge