Owner Draw Menus in C#

很多Windows 應用程序中的控件可以手工繪製,來達到更加生動的效果,可以使用窗體組件的ownerdraw屬性來達到這個目的。Menu就是一個這樣的組件,它允許我們手工繪製其界面。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

這篇文章的主要目的在於向你解釋如何用特定的字體,圖片,背景顏色以及其他的圖形對象來繪製自己定製的菜單。

第一步:創建一個簡單的Windows Form應用程序
點擊文件 - > 新建 -> 項目 - > 創建一個新的CWindowsForm應用程序OwnerDrawMenu

在默認的窗體上,添加一個MainMenu控件, 創建如下形式的菜單

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

在這裏我們需要手工繪製的菜單不僅僅是頂級菜單,而且包括子菜單
對每個菜單項,設置其OwnerDraw屬性爲“True”

對每個菜單項而言,手工繪製將調用如下兩個函數..

DrawItem . 這個函數裏將加入實際的繪圖邏輯
Measure Item .
這個函數被調用於設置菜單項的高度和寬度值.
在菜單項的事件列表裏,我們將爲其添加這兩個事件函數.

選擇File菜單的屬性頁.

點擊Event標籤頁.

雙擊DrawItem選項.這將爲File菜單添加一個默認的繪製事件處理函數.
private void mi_TopMenuItem_DrawItem(

object sender, System.Windows.Forms.DrawItemEventArgs e)

雙擊MeasureItem選項。這將爲File菜單添加一個默認的測量事件處理函數 
private void mi_TopMenuItem_MeasureItem(

object sender, System.Windows.Forms.MeasureItemEventArgs e) 

現在我們需要爲子菜單添加DrawItem MeasureItem 事件處理函數. 對所有子菜單,我們創建不同的事件函數
選中“Open”子菜單,同樣的添加兩個事件處理函數
private void mi_SubMenuItem_MeasureItem(

object sender, System.Windows.Forms.MeasureItemEventArgs e) 
private void mi_SubMenuItem_DrawItem(

object sender, System.Windows.Forms.DrawItemEventArgs e) 

注意:這裏我們並不是對每個菜單項都創建一個相應的事件處理函數,儘管你可以這樣做。相反的,我們通過一個通用的事件處理函數(mi_TopMenuItem_DrawItem)來處理所有頂級菜單項(File/Options/Help)的DrawItem事件,一個通用的事件處理函數來處理所有頂級菜單項的MeasureItem事件;一個通用的事件處理函數(mi_SubMenuItem_DrawItem)來處理所有的子菜單項(Open/Close…About)的DrawItem事件,一個通用的事件處理函數(mi_SubMenuItem_MeasureItem)來處理所有的子菜單的MeasureItem事件。

下面是詳細步驟..

對其他的兩個頂級菜單項“Options”“Help”,在窗體設計器中選中它,選其屬性頁,選到事件頁
.

點擊DrawItem 事件右邊的下拉列表,選中
mi_TopMenuItem_DrawItem.

點擊MeasureItem 事件右邊的下拉列表,選中mi_TopMenuItem_ MeasureItem. 


對於每個子菜單,例如“Close / Exit / Security / Network / About”,選其屬性頁,選到事件頁.

點擊DrawItem 事件右邊的下拉列表,選中
mi_SubMenuItem_DrawItem.

點擊MeasureItem 事件右邊的下拉列表,選中mi_SubMenuItem_ MeasureItem. 


現在對於每個菜單項我們都爲其添加了DrawItem MeasureItem的事件處理函數

下面是頂級菜單的事件處理函數

private void mi_TopMenuItem_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)

{

    Brush sysBgBrush = new SolidBrush(SystemColors.Control);

    Brush focuseBgBrush = new SolidBrush(Color.CornflowerBlue);

    Font normalFont = new Font("Ariel", 10);

    Brush normalTxBrush = new SolidBrush(Color.Black);

    Pen bdrPen1 = new Pen(normalTxBrush, 2);

    Pen bdrPen2 = new Pen(normalTxBrush);

 

    Rectangle rc = new Rectangle(e.Bounds.X+1 , e.Bounds.Y+1, e.Bounds.Width-5, e.Bounds.Height-1);

    e.Graphics.FillRectangle(sysBgBrush , rc);

    MenuItem mOrigin = (MenuItem)sender ;

    string mItemText = mOrigin.Text ;

    StringFormat sf = new StringFormat();

    sf.Alignment = StringAlignment.Center ;

    e.Graphics.DrawString(mItemText , normalFont, normalTxBrush , rc , sf );

    //Console.WriteLine(e.State.ToString());

    if ( e.State ==  (DrawItemState.NoAccelerator | DrawItemState.Selected)

    ||  e.State ==  ( DrawItemState.NoAccelerator | DrawItemState.HotLight)  )

    {

       e.Graphics.FillRectangle( focuseBgBrush, rc);

              e.Graphics.DrawString( mItemText , normalFont ,normalTxBrush, rc ,sf);

       e.Graphics.DrawRectangle(bdrPen2, rc );

    }

    e.DrawFocusRectangle();

    e.Graphics.DrawRectangle(bdrPen1, rc );

}

 

private void mi_TopMenuItem_MeasureItem(object sender, System.Windows.Forms.MeasureItemEventArgs e)

{

    e.ItemHeight = 25;

    e.ItemWidth = 75;

}  


下面是子菜單的事件處理函數

private void mi_SubMenuItem_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)

{

    Rectangle rc = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);

    Brush sysBgBrush = new SolidBrush(SystemColors.Control);

    Brush focuseBrush = new SolidBrush(Color.CornflowerBlue);

    Font normalFont = new Font("Veranda", 10);

    Brush normalTxBrush = new SolidBrush(Color.Blue);

    Font focuseFont = new Font("Veranda", 10, FontStyle.Bold|FontStyle.Underline);

    Brush focuseTxBrush = new SolidBrush(Color.Yellow);

    Pen sysBdPen = new Pen(sysBgBrush);

    Pen focuseBdPen = new Pen(new SolidBrush(Color.Black));

    //erase the previous track

    e.Graphics.FillRectangle(sysBgBrush , rc);

 

    MenuItem mOrigin = (MenuItem)sender ;

    string mItemText = mOrigin.Text ;

    StringFormat textFormat = new StringFormat();

    textFormat.Alignment = StringAlignment.Far ;

    textFormat.LineAlignment  = StringAlignment.Center;

    Rectangle rcText = rc ;

    rcText.Width-=5 ;

    e.Graphics.DrawString(mItemText , normalFont, normalTxBrush, rcText, textFormat );

    e.Graphics.DrawRectangle(sysBdPen, rc );

 

    if ( e.State == ( DrawItemState.NoAccelerator | DrawItemState.Selected))

    {

       e.Graphics.FillRectangle(focuseBrush , rc);

       e.Graphics.DrawString( mItemText , focuseFont , focuseTxBrush, rcText,textFormat);

       e.Graphics.DrawRectangle(focuseBdPen, rc );

       e.DrawFocusRectangle();

    }

    Image useImage = null ;

    if ( mOrigin == mi_File_New )

    {

       useImage = this.imageList1.Images[0];

    }

    if ( mOrigin == mi_File_Open )

    {

       useImage = this.imageList1.Images[1];

    }

    if ( mOrigin == mi_File_Save )

    {

       useImage = this.imageList1.Images[2];

    }

    if ( useImage != null )

    {

       SizeF sz = useImage.PhysicalDimension;

       e.Graphics.DrawImage(useImage, e.Bounds.X+5,

( e.Bounds.Bottom + e.Bounds.Top ) /2 - sz.Height/2);

    }

}

 

private void mi_SubMenuItem_MeasureItem(object sender, System.Windows.Forms.MeasureItemEventArgs e)        

{

    e.ItemHeight = 25;

    e.ItemWidth = 75;

}

編譯並執行.

 

 

About the Author Shripad Kulkarni

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章