分类: C/C++
2008-08-01 17:07:22
//开始显示office 2003菜单 OfficeMenus1.Start( FormName ); 注:FormName为要改变菜单风格的窗口名称。同样,你也可以通过调用如下方法终止菜单的office2003风格,使之回到原始外观:
// 改变菜单的外观风格到原始状态 OfficeMenus1.End();为菜单顶添加图标也很简单,只须为工程添加一个ImageList(图像列表控件),然后将OfficeMenu组件的ImageList属性更改为你添加的ImageList,使用如下代码实现:
// 为菜单添加图像 // OfficeMenus.AddPicture( MenuItem MenuItemToAddPictureTo, int ImageIndex ); OfficeMenus1.ImageList = imageList1; OfficeMenus1.AddPicture(menuItem2, 1);
public class OfficeMenus : System.ComponentModel.Component然后在类中定义两静态变量:
static ImageList _imageList;// 存储图片细节的一个名称集合,NameValueCollection的详细说明请查阅MSDN,该类主要用来使每个菜单的句柄与每个图标形成一一对应的关系,以便后面绘制菜单顶的图标时快速地找到某个菜单所对应的图标。
static NameValueCollection picDetails = new NameValueCollection();接下来定义公共接口方法start和End。
public void Start(Form form) { 先从Start传入的参数中获得该窗口的主菜单。接下来为每一个主菜单下的MenuItem添加MeasureItem事件 处理mainMenuItem_MeasureItem和DrawItem事件处理mainMenuItem_DrawItem, 将MenuItem的OwnerDraw属性设置为true,并使用InitMenuItem(Menu mi)方法对每个MenuItem应用改变。 然后再从form参数中获取该窗口的上下文菜单对象,对其调用InitMenuItem(Menu mi)应用改变。 最后循环查找窗口中包含的每个子控件的上下文菜单,对其应用改变。 System.Windows.Forms.MainMenu menu = form.Menu; foreach ( MenuItem mi in menu.MenuItems ) { mi.MeasureItem = new System.Windows.Forms.MeasureItemEventHandler(mainMenuItem_MeasureItem); mi.DrawItem = new System.Windows.Forms.DrawItemEventHandler(mainMenuItem_DrawItem); mi.OwnerDraw = true; InitMenuItem(mi); } ContextMenu cmenu = form.ContextMenu; if ( cmenu != null ) {InitMenuItem(cmenu);} foreach ( Control c in form.Controls ) { if ( c.ContextMenu != null ) InitMenuItem(c.ContextMenu);} catch {} }
private void InitMenuItem(Menu mi) { 循环查找mi中的每个MenuItem,为其添加MeasureItem事件处理menuItem_MeasureItem和 DrawItem事件处理menuItem_DrawItem(注意,此处的事件处理方法名称与Start中对 主菜单的事件处理方法名称不同),并将OwnerDraw属性设置为true。使用递归调用对每个查找 到的MenuItem调用InitMenuItem方法,这样便可以对菜单项下的所有级别的子菜单项都应用到改变。 }UninitMenuItem的定义与此类似。
private void menuItem_MeasureItem(object sender, System.Windows.Forms.MeasureItemEventArgs e) { 先取得要进行消息处理的MenuItem对象(MenuItem item = (MenuItem) sender;)。 if (item为seperator ) { e.ItemHeight = 7;} else { 获取item的文字宽度,如果有快捷键,还要获取item中的快捷键所占用的宽度。 设置item的边界:e.ItemHeight = 文字高度 7; e.ItemWidth = 文字宽度 快捷键的宽度 图标宽度*2; } }menuItem_DrawItem的实现如下:
private void menuItem_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e) { MenuItemDrawing.DrawMenuItem(e, (MenuItem) sender); }该函数只是简单地调用了类MenuItemDrawing中的静态方法DrawMenuItem。
private void mainMenuItem_MeasureItem(object sender, System.Windows.Forms.MeasureItemEventArgs e) { MenuItem mi = (MenuItem) sender;//获得菜单项对象 SizeF miSize = e.Graphics.MeasureString(mi.Text, Globals.menuFont); //由于顶级菜单(如文件菜单)无快捷键和图标,所以绘制的宽度为文字的宽度。 e.ItemWidth = Convert.ToInt32(miSize.Width); } private void mainMenuItem_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e) { MainMenuItemDrawing.DrawMenuItem(e, (MenuItem) sender); }该方法只是调用了类MainMenuItemDrawing中的静态方法DrawMenuItem进行菜单绘制。
public void AddPicture(MenuItem mi, int index) { //将菜单项的句柄转化为字符串与图标的索引一一对应添加到picDetails集合中。 picDetails.Add(mi.Handle.ToString(), index.ToString()); } public static Bitmap GetItemPicture(MenuItem mi) { if ( _imageList == null ) return null; //将菜单项的句柄作为键查找该键对应的值,返回值为图标索引 string [] picIndex = picDetails.GetValues(mi.Handle.ToString()); if ( picIndex == null ) return null; else //根据索引取出位图对象并返回 return (Bitmap)_imageList.Images[Convert.ToInt32(picIndex[0])]; }
public class MainMenuItemDrawing { //静态方法,实现菜单项的绘制 public static void DrawMenuItem(System.Windows.Forms.DrawItemEventArgs e, MenuItem mi) { 首先检查menuItem的状态,如为鼠标悬浮在其上的状态,则调用DrawHoverRect绘制并填充悬浮矩形; 如为选定态,则调用DrawSelectionRect绘制并填充相应的选定态时的矩形; 如两者都不是,则用控件的填充色绘制并填充矩形。 最后利用e.Graphics.DrawString方法绘制菜单文字。 } …… }类MenuItemDrawing负责主菜单的子菜单和上下文菜单的绘制。
public class MenuItemDrawing { //静态方法,实现菜单项的绘制 public static void DrawMenuItem(System.Windows.Forms.DrawItemEventArgs e, MenuItem mi) { 检查菜单顶是否被选中,如被选中,则调用DrawSelectionRect绘制并填充选中后的矩形, 否则只用背景色绘制空白区域并调用DrawPictureArea绘制图片区域。 调用DrawCheckBox绘制复合框如果该菜单项被选中。 调用DrawMenuText绘制菜单项文字。最后调用DrawItemPicture绘制图标。 } …… }你对源码有兴趣。可以下载本文提供的源代码也可以从下载。