C#組件技巧之ComboBox美容

來源:互聯網
上載者:User

Yesky 張偉

  組合框是組成Windows視窗常見的控制項之一,Windows程式員在應用軟體開發中經常要用到組合框。但隨微軟開發工具語言(如C/C++/C#/VB/VF)提供的標準組合框都是同一面孔:組合框中每一項都是字串,看起來有點灰頭土臉,不那麼賞心悅目(1)。


圖1

  今天我們就來給組合框美容一下,使組合框中每一項都帶有個性,組合框中每一項即可以讓字串格式變化多樣,也可以使每一項都帶有各種圖形,同樣也可以讓每一項都帶有映像等等。

  例1:本例中我們在一個表單上建立三個組合框,從上到下名字分別為comboBox1~comboBox3,通過編程分別讓它們的組合框條目字串格式發生變化、每項前都有圖形、每項前都有映像。

 

  第一步:建立項目

   建立一名為TestComboBox的Windows應用程式(註:應用程式名稱可以隨意)。

  第二步:介面設計

   本例介面比較簡單,三個label,三個組合框(2所示,從上到上組合框名依次為comboBox1、comboBox2、comboBox3),一個imageList控制項(當然表單上看不到,在表單設計圖的下方)請按照2排列。


圖2

  第三步:控制項屬性設定

  (1)把三個label的Text屬性按圖2設定;

  (2)三個comboBox的屬性進行如下設定:

   DrawMode:OwnerDrawFixed;
   DropDownStyle:DropDownList;

   註:這兩個屬性只有如此設定才能保證我們對組合框進行個人化改造,否則的話無論你的程式寫得多麼好,同樣還是"灰頭土臉,不是那麼賞心悅目。

  (3)通過imageList1的Item屬性向imageList增添幾個映像。
 

  第四步:編程

  說明:當我們通過組合框的Add方法向組合框添加item時,都會發生組合框的DrawItem事件處理函數來畫組合框item,因此如果我們想建立個人化的組合框只有在DrawItem事件處理函數中做文章了。在編程之前我們需要瞭解如下的基礎知識。

  (1)在組合框條目中顯示文本時都是利用grphics類的DrawString函數,此函數有多個變體,現把此函數各種形式簡介如下:

   ①public void DrawString(string, Font, Brush, PointF);

   在指定位置並且用指定的 Brush 和 Font 對象繪製指定的文本字串。

   ②public void DrawString(string, Font, Brush, RectangleF);

   在指定矩形並且用指定的 Brush 和 Font 對象繪製指定的文本字串。

   ③public void DrawString(string, Font, Brush, PointF, StringFormat);

   使用指定 StringFormat 對象的格式化屬性,用指定的 Brush 和 Font 對象在指定的位置繪製指定的文本字串。

   ④public void DrawString(string, Font, Brush, RectangleF, StringFormat);

   使用指定 StringFormat 對象的格式化屬性,用指定的 Brush 和 Font 對象在指定的矩形繪製指定的文本字串。

   ⑤public void DrawString(string, Font, Brush, float, float);

   在指定位置並且用指定的 Brush 和 Font 對象繪製指定的文本字串。

   ⑥public void DrawString(string, Font, Brush, float, float, StringFormat);

   使用指定 StringFormat 對象的格式化屬性,用指定的 Brush 和 Font 對象在指定的位置繪製指定的文本字串。

  在本例中我們注意使用第④種。

  (2)在組合框畫矩形時大都使用graphics類的FillRectangle()函數,本例中我們所用的格式如下:

   FillRectangle(brush_name,rectange);

  (3)comboBox1~comboBox3的DrawItem事件處理常式接收一個 DrawItemEventArgs 類型的參數,它包含與此事件相關的資料。下列 DrawItemEventArgs 屬性提供特定於此事件的資訊。

   BackColor:擷取所繪製的項的背景色。

   Bounds:擷取表示所繪製項的邊界的矩形。

   Font:擷取分配給所繪製項的字串格式。

   ForeColor: 擷取所繪製項的前景色彩。

   Graphics:擷取要在其上繪製項的圖形表面。

   Index:擷取所繪製項的索引值。

   State:擷取所繪製項的狀態。

  有了以上的"基礎知識"我們開始編程了。因為我們想在comboBox1改變字串格式,在comboBox2中改變每項前的圖形顏色顏色,所以我們需要建立多種字串格式、多種畫刷。因此我們必須建立兩個ArrayList類型的數組來儲存我們建立的字串格式與畫刷,於是在類的前面添加如下兩句:
 

 

ArrayList brushArray = new ArrayList() ;
ArrayList fontArray = new ArrayList() ;

  (4)我們什麼時候建立字串格式組、畫刷組比較合適呢?當然要在畫組合框之前了,不然的話如何用?因此只有在Form1_Load事件中前部建立字串格式、畫刷了。Form1_Load代碼如下:
 

private void Form1_Load(object sender, System.EventArgs e)
{
//建立字串格式
fontArray .Add(new Font("Ariel" , 8 , FontStyle.Bold ));
fontArray .Add(new Font("Courier" , 8 , FontStyle.Italic));
fontArray .Add(new Font("Veranda" , 8 , FontStyle.Bold));
fontArray .Add(new Font("System" , 8 , FontStyle.Strikeout));
fontArray .Add(new Font("Century SchoolBook" , 8 , FontStyle.Underline));
fontArray .Add(new Font("HeleVCtia" , 8 , FontStyle.Italic));
      //建立畫刷
brushArray.Add(new SolidBrush(Color.Red));
brushArray.Add(new SolidBrush(Color.Blue));
brushArray.Add(new SolidBrush(Color.Green));
brushArray.Add(new SolidBrush(Color.Yellow));
brushArray.Add(new SolidBrush(Color.Black));
brushArray.Add(new SolidBrush(Color.Azure));
brushArray.Add(new SolidBrush(Color.Firebrick));
brushArray.Add(new SolidBrush(Color.DarkMagenta));
brushArray.Add(new SolidBrush(Color.DarkTurquoise));
brushArray.Add(new SolidBrush(Color.Khaki));
      //畫comboBox1,注意它要調用comboBox1_DrawItem來畫
comboBox1.Items.Add("中國");
comboBox1.Items.Add("巴西");
comboBox1.Items.Add("哥斯達黎加");
comboBox1.Items.Add("土耳其");
comboBox1.Items.Add("韓國");
comboBox1.Items.Add("日本");
//畫comboBox2,注意它要調用comboBox2_DrawItem來畫
comboBox2.Items.Add("");
comboBox2.Items.Add("");
comboBox2.Items.Add("");
comboBox2.Items.Add("");
comboBox2.Items.Add("");
comboBox2.Items.Add("");
comboBox2.Items.Add("");
comboBox2.Items.Add("");
comboBox2.Items.Add("");
comboBox2.Items.Add("");
//畫comboBox3,注意它要調用comboBox3_DrawItem來畫
comboBox3.Items.Add("趙微");
comboBox3.Items.Add("舒淇");
}
 

  問題:僅從Form_Load的代碼來看三個comboBox,應該差別不大,因為它們的代碼幾乎完全一模一樣,實際情況如何呢?我們還是來看看最終的運行介面吧(3、圖4、圖5)。


圖3 comboBox1:格式變化的組合框


圖4 comboBox2:帶有圖形的組全框


圖5:comboBox3:帶有映像的組合框
 

  我們看看comboBox1的DrawItem事件處理函數,其代碼如下:
 

 

private void comboBox1_DrawItem(object sender,
System.Windows.Forms.DrawItemEventArgs e)
{
//確定畫布
Graphics g = e.Graphics ;
//繪製地區
Rectangle r = e.Bounds ;
Font fn = null ;
if ( e.Index >= 0 )
{
//設定字型、字串格式、對齊
fn = (Font)fontArray[e.Index];
string s = (string)comboBox1.Items[e.Index];
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Near;
//根據不同的狀態用不同的顏色表示
if ( e.State == ( DrawItemState.NoAccelerator | DrawItemState.NoFocusRect))
{
e.Graphics.FillRectangle(new SolidBrush(Color.Red) , r);
e.Graphics.DrawString( s , fn , new SolidBrush(Color.Black), r ,sf);
e.DrawFocusRectangle();
}
else
{
e.Graphics.FillRectangle(new SolidBrush(Color.LightBlue) , r);
e.Graphics.DrawString( s , fn , new SolidBrush(Color.Red), r ,sf);
e.DrawFocusRectangle();
}
}
}

  再來看看comboBox2的DrawItem事件處理函數,其代碼如下:
 

private void comboBox2_DrawItem(object sender,
System.Windows.Forms.DrawItemEventArgs e)
{
Graphics g = e.Graphics ;
Rectangle r = e.Bounds ;
if ( e.Index >= 0 )
{
//設定字串前矩形塊rd的大小
Rectangle rd = r ;
rd.Width = rd.Left + 20 ;
Rectangle rt = r ;
r.X = rd.Right ;
//用不同的顏色畫矩形塊
SolidBrush b = (SolidBrush)brushArray[e.Index];
g.FillRectangle(b , rd);
//設定字串的格式
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Near;
if ( e.State == ( DrawItemState.NoAccelerator | DrawItemState.NoFocusRect))
{
//字串背景
e.Graphics.FillRectangle(new SolidBrush(Color.White) , r);
//顯示字串
e.Graphics.DrawString( b.Color.Name, new Font("Ariel" ,8 , FontStyle.Bold ) , new SolidBrush(Color.Black), r ,sf);
//繪製取得焦點時的虛線框
e.DrawFocusRectangle();
}
else
{
e.Graphics.FillRectangle(new SolidBrush(Color.LightBlue) , r);
e.Graphics.DrawString( b.Color.Name, new Font("Veranda" , 8 , FontStyle.Bold ) , new SolidBrush(Color.Red), r ,sf);
e.DrawFocusRectangle();
}
}
}
 

  最後我們看看comboBox3的DrawItem事件處理函數,其原始碼如下:
 

private void comboBox3_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
Graphics g = e.Graphics ;
Rectangle r = e.Bounds ;
Size imageSize = imageList1.ImageSize;
Font fn = null ;
if ( e.Index >= 0 )
{
fn = (Font)fontArray[0];
string s = (string)comboBox3.Items[e.Index];
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Near;
if ( e.State == ( DrawItemState.NoAccelerator | DrawItemState.NoFocusRect))
{
//畫條目背景
e.Graphics.FillRectangle(new SolidBrush(Color.Red) , r);
//繪製映像
imageList1.Draw(e.Graphics, r.Left, r.Top,e.Index);
//顯示字串
e.Graphics.DrawString( s , fn , new SolidBrush(Color.Black), r.Left+imageSize.Width ,r.Top);
//顯示取得焦點時的虛線框
e.DrawFocusRectangle();
}
else
{
e.Graphics.FillRectangle(new SolidBrush(Color.LightBlue) , r);
imageList1.Draw(e.Graphics, r.Left, r.Top,e.Index);
e.Graphics.DrawString( s , fn , new SolidBrush(Color.Black),r.Left+imageSize.Width ,r.Top);
e.DrawFocusRectangle();
}
}
}

  看到這兒,聰明的讀者也許會說,其實為組合框"變臉"很簡單,只要修改各個組合框的DrawItem事件處理函數即可。如果你能明白這一點,我這篇文章的目的就達到了。

  在本文快要結果之前我們還是來看看應用程式入口函數的代碼:
 

static void Main()
{
Form frm=new Form1();
frm.ShowDialog();
}

  最後我要指出本文的局限性,那就是本文中組合框的"順序性"很強,即組合框中條目格式與我們定義的字串格式數組、畫刷數組、映像數組順序一樣,但如果要求順序不一樣,例如在下面的情況下:用紅黃綠三種顏色分別代表三個班級的顏色,即一班所學同學的姓名都用紅色表示、二班所有同學的姓名都用黃色表示、三班所有同學的姓名都用綠色表示,這又如何?呢?有些讀者可能會想到用if-else-if語句,但是如果班級有10、100個甚至1000個你還用if-else-if語句嗎?這個問題我們留在下一篇文章中解決。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.