-- 1
将菜单项移到菜单栏的最右边

  在一些应用程序中,常把一些特殊的菜单项放在菜单栏的最右边(如WPS2000

中的"定制界面"菜单,一些应用程序的帮助菜单),这些菜单项放在菜单栏

(menu bar)的右边比较好。Delphi中虽然没有直接提供(呵呵,也许是我没找

到)把菜单放在菜单栏右边的函数,但是Delphi的Windows单元封装了可以实现这

种效果的Windows API函数(ModifyMenu、GetMenuItemInfo)。因此,我们在

Delphi中可以直接使这些函数来实现这种效果。
  使用ModifyMenu和GetMenuItemInfo都可以将菜单项移到菜单栏的最右边,那

么选那个较好呢?据 Windows SDK 文档:
  ModifyMenu函数可以改变一个已经存在的菜单项的设置,这个函数用于指定

一个菜单的标题、显示外观等项目,不过,ModifyMenu函数现在已经被功能更强

大的SetMenuItemInfo函数取代。虽然如此,如果你的程序不需要

SetMenuItemInfo函数提供的扩展功能,你仍旧可以继续使用ModifyMenu函数。
  ModifyMenu函数支持 Windows 32、9x、NT/2000。
  SetMenuItemInfo函数支持 Windows 9x、NT/2000,不支持windows 32(较早

版本也不支持NT/2000)。
  另外,SetMenuItemInfo函数功能比ModifyMenu函数强大,不过使用函数

SetMenuItemInfo需要的参数也比ModifyMenu函数复杂的多。所以这里我依然使用

比较简单的ModifyMenu函数来实现。
  ModifyMenu函数原型为:
  BOOL ModifyMenu(
    HMENU hMnu, // handle of menu
    UINT uPosition, // menu item to modify
    UINT uFlags, // menu item flags
    UINT uIDNewItem, // menu item identifier or handle of drop-down

menu or submenu
    LPCTSTR lpNewItem // menu item content
    );
  第一个参数hMENU 指的是要修改的菜单的句柄(如:MainMenu1.Handle);
  第二个参数uPosition 指的是要修改的菜单项索引值(菜单栏左边第一个其

值为零,从左向右递增,最大值为菜单项的总数减一);
  第三个参数uFlags指的是(第二个参数所指的菜单项修改后的)新菜单项的

状态;
  第四个参数uIDNewItem 是指向新菜单的句柄;
  第五个参数lpNewItem指的是新菜单的标题。
  举例如下:
  创建一个带有菜单的新工程,设其MainMenu组件的名字为MainMenu1,其中要

移到菜单栏的最右边的那个菜单的名字为Help1。
  在窗体的OnCreate时间的处理程序中加入以下代码
  procedure TForm1.FormCreate(Sender: TObject);
  begin
   ModifyMenu(MainMenu1.Handle,2,
       MF_BYPOSITION or MF_HELP,
       Help1.Handle,Pchar(Help1.Caption));
      //其中:MF_HELP 参数决定菜单项(Help1)在窗口的最右端显示。
  end;
  然后运行,看看效果如何

-- 2
定制系统菜单

  常见的应用程序的主窗体中,利用鼠标左键点击左上角的图标,会弹出一个

系统菜单,这个菜单一定程度上给了我们很大方便,问题是那些都是缺省的系统

菜单命令,对于我们来说没有太大的帮助。当然,我们可以自己定制系统菜单,

加上我们需要的东西,在Delphi 中,窗体组件并没有提供系统菜单对应的组件,

所以定制系统菜单时就有我们自己动手用Windows API函数来实现。Windows API

函数中,常用于对菜单操作的函数有:
  AppendMenu 在现有的菜单项尾部插入一个新菜单项;
  DeleteMenu 删除菜单中一个现有的菜单项,并清除该项;
  RemoveMenu 在现有的菜单项中删除某一项;
  InsertMenu 在现有的菜单项中插入一个新项;
  ModifyMenu 修改一个现有菜单项;
  这些函数用法都是类似的上面已经说了ModifyMenu函数的用法,下面仅用

AppendMenu函数在系统菜单中添加一个关于菜单来说明,虽然它本身是没有什么

意义的,但希望可以起到抛砖引玉的作用。
  AppendMenu 函数原型:
  BOOL AppendMenu(
     HMENU hMenu, // 要定制的菜单句柄
     UINT uFlags, // 怎样定制菜单项
     UINT uIDNewItem, // 要定制的菜单项标识或子菜单句柄
     LPCTSTR lpNewItem // 要定制的菜单项(字串)
    );
  在 AppendMenu 函数里,lpNewItem 和 uIDNewItem 参数依赖 uFlags 的不

同标志而有所变化。
  唯一限制:系统菜单中添加的菜单项的ID值(uIDNewItem)必须小于 $F000(

十进制:61440);否则会与Windows系统菜单命令所使用的ID值相冲突。还要记住

当为这些新菜单在窗口过程中处理WM_SYSCOMMAND消息时,必须把其它的

WM_SYSCOMMAND消息发给DefWindowsProc(在Delphi中秩序在事件处理程序最后加

入一句 Inherited;),否则,嘿嘿,你试试就知道了。
  首先创建一个新工程,因为要用到Menus单元中的内容,故在文件Unit1.pas的

uses语句中加入Menus。
  uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls, ComCtrls,  Menus;
  然后在窗体Form1的OnCreate事件处理过程加入以下代码:
  procedure TForm1.FormCreate(Sender: TObject);
  var hSysMenu:hMENU;
  begin
   hSysMenu:=GetSystemMenu(Handle,False);//得到系统菜单句柄
   AppendMenu(hSysMenu,MF_SEPARATOR,0,'');//添加一个分隔符
   AppendMenu(hSysMenu,MF_STRING,3,'关于(&A)');
  end;
  在TForm1的类型定义中,添加系统菜单中新建菜单项的onClick事件的处理过

程的声明(即对消息WM_SYSCOMMAND的处理声明):
  type
   TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
   private
    procedure SysMenuCommand(var Msg:TWMMENUSELECT);
     message WM_SYSCOMMAND;
    { Private declarations }
   public
    { Public declarations }
   end;
  接着按Shift+Ctrl+C完成类声明。在其中填入以下代码:
  procedure TForm1.SysMenuCommand(var Msg: TWMMENUSELECT);
  begin
   if Msg.IDItem=3 then
     MessageBox(0,'A Poor-Person''s Menu Program'+#13+
          ' Copyright Skyey ,2000','Skyey',
         MB_OK+MB_ICONINFORMATION);
   Inherited;
  end;
  编译、运行程序,测试其效果。
  附:uFlags 一些定义值://选译自Delphi 5带的Windows SDK 帮助
  MF_BITMAP 指明该菜单项是一位图,在 lpNewItem 参数代表位图句柄
  MF_CHECKED 在菜单项的前面放上一个"选中"标记
  MF_DISABLED 屏蔽该菜单项,但不使它变成灰色
  MF_ENABLED 使该菜单项有效,与 MF_DISABLED 相反
  MF_GRAYED 除了有 MF_DISABLED 的作用以外,还把该菜单项变灰
  MF_MENUBREAK 把该菜单与现有菜单并排放在一起
  MF_MENUBARBREAK 与MF_MENUBREAK 相同,除了在中间放一条竖线外
  MF_OWNERDRAW 表明该菜单项为自绘菜单项,还必须处理一切的显示、更新问


  MF_POPUP 该菜单项为一子菜单,uIDNewItem 参数代表其句柄
  MF_SEPARATOR 在菜单项画上一分割线
  MF_STRING 该菜单项是一文本字串,lpNewItem 是其内容
  MF_UNCHECKED 取消该菜单项前面的"选中"标记
  以下几组标志中每组的标志不能同时使用:
  < 1> MF_DISABLED, MF_ENABLED, and MF_GRAYED
  < 2> MF_BITMAP, MF_STRING, and MF_OWNERDRAW
  < 3> MF_MENUBARBREAK and MF_MENUBREAK
  < 4> MF_CHECKED and MF_UNCHECKED

-- 3
为菜单动态定义快捷键

  其实就是改变菜单的ShortCut属性,在程序中加入一个HotKey组件,然后把

其HotKey属性赋给菜单的ShortCut属性即可。如:
  procedure TForm1.BtnChange1Click(Sender: TObject);
  begin
   New1.ShortCut:=Hotkey1.HotKey;
  end;
  如果你只需要程序自行更改有限的几个快捷键而不需要用户自己改变,那么

也可以不用HotKey组件,直接把一个TShortCut类型的数值赋给菜单的ShortCut属

性即可。如:
  procedure TForm1.BtnChange1Click(Sender: TObject);
  begin
   New1.ShortCut:= 32833;//就是Alt+A
  end;
  一个快捷键的值可以按下面的方法在设计时得到:先在设计时改变菜单的

ShortCut属性的为你需要的快捷键,然后在窗体上-> 右键-> View as Text,在

DFM文件中找到那个组件,那个ShortCut后面的就是。如:需要Ctrl+Alt+N
  object New1: TMenuItem
   Caption = '&New'
   ShortCut = 49230 //就是这个
   onClick = New1Click
  end

-- 4
动态改变菜单

  就是改变菜单项的Enabled属性和Visible属性。这两个属性既可以在设计时

改变,也可以在运行时改变。
  如果将Enabled属性设置为False,则菜单项呈灰色状态,不可用;如果设置

为True,则菜单项处于正常能用的状态。
  如果将Visible属性设置为False,则该菜单项在运行时不显示;如果设置为

True,则该菜单项显示。
  如:New1.Enabled:=False;//New菜单项变成灰色,菜单现在不可用
  New1.Enabled:=True; //New菜单项现在可以使用
  New1.Visible:=False //New菜单项现在不显示
  New1.Visible:=True; //New菜单项现在显示
  唯一需要注意的是:Visible和Enabled属性时两个互相独立的属性,二者互

不干扰,如果一个菜单拥有一个快捷键且其Enabled属性为True,即使其Visible

属性为False(即运行时不可见),仍可以用快捷键来访问。
  在程序运行期间,修改菜单项的这两个属性,即可以动态地改变菜单显示。

-- 5
获取用户错误按键信息

  如果用户按Alt和一个与菜单项不匹配的字符时,或者当显示弹出式菜单而用

户按下一个与弹出式菜单里的项不匹配的字符键时。我们怎么知道用户按错了键

,又怎么知道用户按了那个键呢?
  事实上,当发生上面假设的情况时,Windows会发出一个WM_MENUCHAR消息,

通常我们不需要处理这个消息,Windows程序通常会把它传给DefWindowProc,它一

般给Windows返回0,即使Windows发出一个短的蜂鸣声。如果我们需要处理上面假

设的情况时,只要拦截这个消息就可以了。
  让我们先了解一下这个消息的参数:
  WM_MENUCHAR
   LOWORD(wParam); //即用户按键的ASCII码
   HIWORD(wParam); //选择码
   lParam; // 菜单句柄
  选择码含义:
  0: 不显示弹出菜单;
  MF_POPUP: 显示下拉菜单、子菜单、快捷菜单(弹出式菜单)
  MF_SYSMENU: 显示系统弹出式菜单
  消息返回值:
  0: 通知Windows丢弃用户按的这个字符并发出一个短的蜂鸣声;
  1: 通知Windows应该关闭当前活动菜单;
  2: 通知Windows返回一个相对于菜单项的零基点的低位字,它由Windows决

定。
  了解这一点后,让我们具体做一下:
  创建一个带有菜单的新工程,在窗体上放一个Memo组件(Name:Memo1)在窗

体的公有变量后加入消息的声明部分:
  public
   procedure MMenuChar(var Msg:TMessage);message WM_MENUCHAR;
   { Public declarations }
  end;
  按Shift+Ctrl+C完成类声明。在其中填入以下代码:
  procedure TForm1.MMenuChar(var Msg: TMessage);
  begin
   Memo1.Lines.Add(Chr(LOWORD(Msg.WParam)));
   Memo1.Lines.Add(IntToStr(HIWORD(Msg.WParam)));
   Msg.Result:=0;
  end;
  编译、链接并运行程序,测试其效果。

Delphi中关于菜单的几个技巧的更多相关文章

  1. 用SPCOMM 在 Delphi中实现串口通讯 转

      用Delphi 实现串口通讯,常用的几种方法为:使用控件如MSCOMM和SPCOMM,使用API函数或者在Delphi 中调用其它串口通讯程序.利用API编写串口通信程序较为复杂,需要掌握大量通信 ...

  2. 转Delphi中Memo显示行号列号

    http://www.alonely.com.cn/Delphi/20160814/8912.html 实例说明本例是个光标应用的简单技巧,希望通过这个例子的学习后能举一反三.Delphi中像这样简单 ...

  3. Delphi中根据分类数据生成树形结构的最优方法

    一. 引言:    TreeView控件适合于表示具有多层次关系的数据.它以简洁的界面,表现形式清晰.形象,操作简单而深受用户喜爱.而且用它可以实现ListView.ListBox所无法实现的很多功能 ...

  4. Delphi中SendMessage使用说明(所有消息说明) good

    Delphi中SendMessage使用说明 SendMessage基础知识 函数功能:该函数将指定的消息发送到一个或多个窗口.此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回.而函数Po ...

  5. 在Delphi中静态调用DLL

    在Delphi中静态调用DLL top 调用一个DLL比写一个DLL要容易一些.首先给大家介绍的是静态调用方法,稍后将介绍动态调用方法,并就两种方法做一个比较.同样的,我们先举一个静态调用的例子. u ...

  6. delphi中SendMessage使用说明

    SendMessage基础知识 函数功能:该函数将指定的消息发送到一个或多个窗口.此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回.而函数PostMessage不同,将一个消息寄送到一个线 ...

  7. Delphi中的异常处理

    转载:http://www.cnblogs.com/doit8791/archive/2012/05/08/2489471.html 以前写Delphi程序一直不注意异常处理,对其异常处理的机制总是一 ...

  8. Delphi中DLL的创建和使用

    参考:http://blog.csdn.net/ninetowns2008/article/details/6311663 结合这篇博客:http://www.cnblogs.com/xumenger ...

  9. Delphi中设置条件断点

    写了这么长时间的代码,一直认为调试程序比写程序要重要,上次有人问俺,如何调试一个循环中某个循环条件位置下断点.本来想来在Delphi的断点设置中应该是有一个类似条件断点的东西的,不过我也一直不知道怎么 ...

随机推荐

  1. Jmeter实现百分比业务比例

    Jmeter实现百分比业务比例   相较于LoadRunner,jmeter在复杂场景方式貌似略有欠缺.前一段时间,想实现一个功能,如有两个采样器a与b,a采样器与b采样器被执行的概率分别为1/4与3 ...

  2. 【leetcode】969. Pancake Sorting

    题目如下: Given an array A, we can perform a pancake flip: We choose some positive integer k <= A.len ...

  3. JVM调优学习 【更新中】

    JVM调优(jdk1.8) 老生常谈,面试吹牛的的最佳谈资,在接下来的几天里,我找了点资料来对其进行一波学习: 本地环境是不需要对我们的虚拟机进行优化的,一般在生产环境下,也就是Linux下才有对JV ...

  4. PHP ftp_login() 函数

    定义和用法 ftp_login() 函数登录 FTP 服务器. 如果成功,该函数返回 TRUE.如果失败,则返回 FALSE 和一个警告. 语法 ftp_login(ftp_connection,us ...

  5. Eclipse 安装Activiti插件

    建议使用vpn或其他翻墙手段安装(否则下载速度可能很慢) 我的博客中有介绍如何自己搭建属于自己的ssr,https://www.cnblogs.com/zktww/p/10839347.html(由于 ...

  6. delphi 多线程3

     多线程程序设计 我们知道,win95或winNT都是“多线程”的操作系统,在DELPHI .中,我们可以充分利用这一特性,编写出“多线程”的应用程序. 对以往在DOS或16位windows下写程序的 ...

  7. BZOJ 3230: 相似子串(后缀数组)

    传送门 解题思路 其实题目挺好想的.首先子串排名可以由后缀数组求得,因为不算重复的,所以后缀数组的每个后缀排名的去掉\(lcp\)的前缀排名为当前后缀的子串排名.这样就可以预处理出每个后缀的\(l,r ...

  8. pandas中读取文件报错

    import pandas as pd fileName = "路径中带有中文/xxx.csv" tf_train = pd.read_csv(fileName) 会提示报错 OS ...

  9. RFS自动化测试工具安装与使用总结

    转载:http://blog.csdn.net/a5650892/article/details/77826021 一,调试1,在调试时,总时提示“无法打开浏览器”解决办法:1,把浏览器的代理关闭2, ...

  10. Elasticsearch介绍和安装与使用

    转载:https://blog.csdn.net/weixin_42633131/article/details/82902812 1.Elasticsearch介绍和安装 1.1.简介1.1.1.E ...