2.8 案例分析8 ComboBox控件的综合使用

2.8.1 案例描述

本节介绍常用控件ComboBox的综合使用。

2.8.2 案例分析

ComboBox控件的使用方法。

2.8.3 案例实现与技巧

① 首先,运行Visual Studio 2005,新建一个Windows应用程序,并命名为ComboBoxctl。

② 向设计窗口中的Form1窗体上的适当位置拖曳两个ComboBox控件,分别修改其属性如下表所示:

③ 向设计窗口中的Form1窗体上的适当位置拖曳两个Label控件,分别修改其属性如下表所示:

④ 完成上面步骤后,设计视图中的窗体示例如图2-18所示。

⑤ 向窗体的右侧拖曳一个GroupBox控件,并修改其Text属性为“组合框的使用”。

⑥ 在groupBox1控件里拖放三个ComboBox控件,使其上下整齐排列于groupBox1控件中,如图2-19所示。

图2-18 设计视图中的窗体示例

图2-19 控件布局与设计(一)

⑦ 修改三个ComboBox控件的属性如下表所示:

⑧ 在groupBox1控件里拖放6个Label控件,4个ComboBox控件,一个Panel控件,如图2-20所示。

图2-20 控件布局与设计(二)

⑨ 修改上述控件的属性如下表所示:

⑩ 向groupBox1控件的底部拖曳一个Panel控件,修改其BorderStyle属性为“Fixed3D”。

⑪ 切换到源代码编辑视图,在窗口类中加入以下成员变量并进行初始化。

private Size cmbsize ;
private Hashtable brushMap = new Hashtable();
private Color gradientBegin = Color.Red;
private Color gradientEnd = Color.Blue;

⑫ 在窗口类的构造函数中加入以下初始化代码,其中的部分方法将在随后实现。

public ComboBoxCtl () {
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
InitControlState();
FillItems(comboBegin);
FillItems(comboEnd);
comboBegin.SelectedIndex = 0;
comboEnd.SelectedIndex = comboEnd.Items.Count-1;
cmbsize = comboBegin.Size;
}

⑬ InitControlState方法的详细内容如下所示:

private void InitControlState() {
// 同步复选框
chkSorted.Checked = comboBegin.Sorted;
chkEnabled.Checked = comboBegin.Enabled;
chkIntegralHeight.Checked = comboBegin.IntegralHeight;
// 同步组合框样式与 ComboBoxStyle.DROPDOWN
StringIntObject[] aStyle = new StringIntObject[3];
aStyle[0] = new StringIntObject("简单",(int)ComboBoxStyle.Simple);
aStyle[1] = new StringIntObject("下拉",(int)ComboBoxStyle.DropDown);
aStyle[2] = new StringIntObject("下拉列表",(int)ComboBoxStyle. DropDownList);
cmbStyle.Items.AddRange(aStyle);
comboBegin.DropDownStyle = (ComboBoxStyle)aStyle[1].i;
comboEnd.DropDownStyle = (ComboBoxStyle)aStyle[1].i;
cmbStyle.SelectedIndex = 1;
// 同步组合框绘制模式与 DrawMode.NORMAL
StringIntObject[] aDMO = new StringIntObject[3];
aDMO[0] = new StringIntObject("正常",(int)DrawMode.Normal);
aDMO[1] = new StringIntObject("Ownerdrawfixed",(int)DrawMode. OwnerDrawFixed);
aDMO[2] = new StringIntObject("Ownerdrawvariable",(int)DrawMode. OwnerDrawVariable);
cmbDrawMode.Items.AddRange(aDMO);
comboBegin.DrawMode = (DrawMode)aDMO[0].i;
comboEnd.DrawMode = (DrawMode)aDMO[0].i;
cmbDrawMode.SelectedIndex = 0;
}

⑭ 在窗体类中加入下面的成员方法,该方法的作用是将颜色项目加入到ComboBox列表。

private void InitControlState() {
// 同步复选框
chkSorted.Checked = comboBegin.Sorted;
chkEnabled.Checked = comboBegin.Enabled;
chkIntegralHeight.Checked = comboBegin.IntegralHeight;
// 同步组合框样式与 ComboBoxStyle.DROPDOWN
StringIntObject[] aStyle = new StringIntObject[3];
aStyle[0] = new StringIntObject("简单",(int)ComboBoxStyle.Simple);
aStyle[1] = new StringIntObject("下拉",(int)ComboBoxStyle.DropDown);
aStyle[2] = new StringIntObject("下拉列表",(int)ComboBoxStyle. DropDownList);
cmbStyle.Items.AddRange(aStyle);
comboBegin.DropDownStyle = (ComboBoxStyle)aStyle[1].i;
comboEnd.DropDownStyle = (ComboBoxStyle)aStyle[1].i;
cmbStyle.SelectedIndex = 1;
// 同步组合框绘制模式与 DrawMode.NORMAL
StringIntObject[] aDMO = new StringIntObject[3];
aDMO[0] = new StringIntObject("正常",(int)DrawMode.Normal);
aDMO[1] = new StringIntObject("Ownerdrawfixed",(int)DrawMode. OwnerDrawFixed);
aDMO[2] = new StringIntObject("Ownerdrawvariable",(int)DrawMode. OwnerDrawVariable);
cmbDrawMode.Items.AddRange(aDMO);
comboBegin.DrawMode = (DrawMode)aDMO[0].i;
comboEnd.DrawMode = (DrawMode)aDMO[0].i;
cmbDrawMode.SelectedIndex = 0;
}

⑮ 在窗体类中加入下面的成员方法,该方法的作用是返回组合框中当前选定项的整型值。

private int SelectedValue(ComboBox cmb) {
int ret;
object obj = cmb.SelectedItem;
if (obj == null) {
    return -1;
}
try {
    ret = Int32.Parse(obj.ToString());
}
catch (FormatException) {
    return -1;
}
return ret;
}

⑯ 在窗体类中加入下面的成员方法,该方法的作用是对给定的组合框进行随机无序播放。

private void RandomShuffle(ComboBox cmb) {
object[] items = new object[cmb.Items.Count];
cmb.Items.CopyTo(items,0);
int swapItem;
Random rand = new Random();
for (int i = 0; i < items.Length; ++i) {
    swapItem = Math.Abs(rand.Next()) % items.Length;
    if (swapItem != i) {
        object tempObject = items[swapItem];
        items[swapItem] = items[i];
        items[i] = tempObject;
    }
}
cmb.Items.Clear();
cmb.Items.AddRange(items);
}

⑰ 下面开始向程序加入事件处理程序来响应用户的选择。如果组合框为Owner DrawDrawMode,则调用此DrawItem事件处理程序在组合框中绘制项。方法的内容如下所示:

private void combo_DrawItem(object sender,DrawItemEventArgs die) {
ComboBox cmb = (ComboBox) sender;
if (die.Index == -1)
    return;
if (sender == null)
    return;
//字符串 brushName = (string)cmb.Items[die.Index]
//SolidBrush selectedBrush = (SolidBrush)brushMap[brushName]
SolidBrush selectedBrush = (SolidBrush)cmb.Items[die.Index];
Graphics g = die.Graphics;
// 如果选择了项,则绘制正确的背景颜色
die.DrawBackground();
die.DrawFocusRectangle();
// 绘制颜色的预览框
Rectangle rectPreviewBox = die.Bounds;
rectPreviewBox.Offset(2,2);
rectPreviewBox.Width = 20;
rectPreviewBox.Height -= 4;
g.DrawRectangle(new Pen(die.ForeColor),rectPreviewBox);
// 获取选定颜色的相应 Brush 对象
// 并填充预览框
rectPreviewBox.Offset(1,1);
rectPreviewBox.Width -= 2;
rectPreviewBox.Height -= 2;
g.FillRectangle(selectedBrush,rectPreviewBox);
// 绘制选定颜色的名称
g.DrawString(selectedBrush.Color.ToString(),Font,new SolidBrush(die. ForeColor),die.Bounds.X+30,die.Bounds.Y+1);
}

⑱ 响应用户改变的所有方法如下所示,在后面需要将多个事件处理程序分别注册到不用的ComboBox控件上,以完成对用户的响应。

   private void chkEnabled_CheckedChanged(object sender,EventArgs e) {
   comboBegin.Enabled = chkEnabled.Checked;
   comboEnd.Enabled = chkEnabled.Checked;
}
private void chkIntegralHeight_CheckedChanged(object sender,EventArgs e) {
   comboBegin.IntegralHeight = chkIntegralHeight.Checked;
   comboEnd.IntegralHeight = chkIntegralHeight.Checked;
}
private void chkSorted_CheckedChanged(object sender,EventArgs e) {
   bool sorted = chkSorted.Checked;
   comboBegin.Sorted = sorted;
   comboEnd.Sorted = sorted;
   if (!sorted) {
      RandomShuffle(comboBegin);
      RandomShuffle(comboEnd);
   }
}
private void cmbItemHeight_SelectedIndexChanged(object sender,EventArgs e) {
   int i = SelectedValue(cmbItemHeight);
   if (i == -1)
      return;
   comboBegin.ItemHeight = i;
   comboEnd.ItemHeight = i;
}
private void cmbStyle_SelectedIndexChanged(object sender,EventArgs e) {
   ComboBoxStyle i = (ComboBoxStyle)(((StringIntObject)cmbStyle. SelectedItem).i);
   comboBegin.DropDownStyle = i;
   comboEnd.DropDownStyle = i;
   if (i == ComboBoxStyle.Simple) {
      Size cmbsize2 = new Size(cmbsize.Width,cmbsize.Height * 3);
      comboBegin.Size = cmbsize2;
      comboEnd.Size = cmbsize2;
      cmbMaxDropDownItems.Enabled = false;
   }
   else {
      cmbMaxDropDownItems.Enabled = true;
   }
}
private void cmbDrawMode_SelectedIndexChanged(object sender,EventArgs e) {
   DrawMode i = (DrawMode)(((StringIntObject)cmbDrawMode.SelectedItem).i);
   comboBegin.DrawMode = i;
   comboEnd.DrawMode = i;
   if (i == DrawMode.OwnerDrawVariable) {
       cmbItemHeight.Enabled = true;
   }
   else {
       cmbItemHeight.Enabled = false;
   }
}
private void comboBegin_SelectedIndexChanged(object sender,EventArgs e) {
   if (comboBegin.SelectedIndex >= 0)
   {
      SolidBrush b = (SolidBrush)(comboBegin.SelectedItem);
      gradientBegin = b.Color;
      panel1.Invalidate();
   }
}
private void comboEnd_SelectedIndexChanged(object sender,EventArgs e) {
   if (comboBegin.SelectedIndex >= 0)
   {
      SolidBrush b = (SolidBrush)(comboEnd.SelectedItem);
      gradientEnd = b.Color;
      panel1.Invalidate();
   }
}
private void cmbMaxDropDownItems_SelectedIndexChanged(object sender,EventArgs e) {
   int i = SelectedValue(cmbMaxDropDownItems);
   if (i == -1)
      return;
   comboBegin.MaxDropDownItems = i;
   comboEnd.MaxDropDownItems = i;
}
private void combo_MeasureItem(object sender,MeasureItemEventArgs mie) {
   ComboBox cb = (ComboBox) sender;
   mie.ItemHeight = cb.ItemHeight - 2;
}
private void panel1_Paint(object sender,PaintEventArgs e) {
   Brush brush = new LinearGradientBrush (panel1.ClientRectangle,gradientBegin,gradientEnd,LinearGradientMode.ForwardDiagonal) ;
   e.Graphics.FillRectangle(brush,panel1.ClientRectangle);
}

⑲ 现在可以切换到设计视图下了,给各个ComboBox控件注册事件处理程序,首先找到窗体左面的两个ComboBox控件,分别为comboBegin和comboEnd;然后为这两个控件注册DrawItem事件的处理程序为combo_DrawItem,这个方法在上面的代码中已经给出了。

⑳ 可以按照下面的列表为ComboBox控件注册事件处理程序。

(21)按照下面的列表为CheckBox注册事件处理程序。

(22)按照下面的列表为控制外观样式的4个ComboBox添加注册事件处理程序。

(23)选择Visual Studio 2005 IDE主菜单“调试”|“开始执行(不调试)”菜单项来运行应用程序。程序运行结果如图2-21所示。

(24)通过控制外观可以显示不同的效果,如图2-22所示。

图2-21 程序运行结果(一)

图2-22 程序运行结果(二)