代码改变世界

.NET中实现自绘的ListBox

2006-10-30 21:16  Timothy Ye  阅读(631)  评论(0编辑  收藏  举报
      在平常的开发过程中,我们为了改善用户的体验,通常会在界面上花一些功夫。因为清爽的界面,通常给用户带来一些耳目一新的感觉,并且能增强用户满意度。前几周的一个项目中,就用到了ListBox,需要突出用户在ListBox中选中的项,而.NET自带的ListBox由于配色过于普通,无法满足我们的需要,这就需要我们重新对ListBox的配色进行一些修改。
    在Windows的消息机制中,有一个消息叫做WM_DRAWITEM,当控件(比如:Button,ComboBox,ListBox,Menu)需要被重新绘制的时候,会向该控件的父窗口发送这个消息。父窗口通过响应这个消息,就可以实现对该控件外观的绘制,也就是说,通过响应WM_DRAWITEM消息,我们可以接管系统对控件的绘制,这样,我们就可以随心所欲,用我们喜欢的方式,来绘制这个控件了。听起来不错吧?
    .NET的WinForm程序,也是基于Windows的GUI界面的窗口,而.NET追溯到最底层,其实也是对Win32 API的更高一个层次的封装。所以,.NET的WinForm程序同样也逃脱不了消息机制。于是我们就可以在程序中,通过设置控件为Owner Draw属性,然后加入对WM_DRAWITEM的处理,就可以在OnDrawItem函数中,定制控件外观了。
    理论上就是这样,我们开始动手吧,打造一个具有个性的ListBox控件!需要说明的是,当我们把控件属性中的DrawMode改为OwnerDrawFixed过后,.NET以及将绘制这个控件的责任交给了我们,因此我们必须要实现DrawItem函数,否则ListBox会是一片白,什么也看不到。
    1.建立一个简单的工程,在工具箱拖放ListBox到Form上,然后将ListBox属性中的DrawMode改为OwnerDrawFixed,或者在Form_Load中,设置控件的属性:
    this.listBox1.DrawMode = DrawMode.OwnerDrawFixed;
      2.在事件窗口中,为DrawItem添加处理函数。
    3.配色方案:这里,我们设定被选中的项目有一个蓝色的外框,并且选中的项中,内容呈亮绿色显示,背景色呈灰色显示,这样就更醒目一些了。
    4.最后一步,就是加入OnDrawItem的代码,如下:
    
    private void listBox1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
        {
            //定义背景色,选中为灰色,未选中为白色
            Brush brNoSelectedBack=Brushes.White;
            Brush brSelectedBack=Brushes.Gray;
            //定义前景色,选中为亮绿色,未选中为黑色
            Brush brSelectedFore=Brushes.LightGreen;
            Brush brNoSelectedFore=Brushes.Black;
            
            //定义焦点,有焦点状态下绘制蓝色外框(蓝色)
            Pen penFocus=new Pen(Brushes.Blue);


            e.Graphics.FillRectangle(Brushes.White,e.Bounds);

            //绘制Item被选中的情况
            if((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                e.Graphics.FillRectangle(brSelectedBack,e.Bounds);
                //绘制焦点外框
                e.Graphics.DrawRectangle(penFocus,e.Bounds.X,e.Bounds.Y,e.Bounds.Width,e.Bounds.Height-1);
                e.Graphics.DrawString(this.listBox1.Items[e.Index].ToString(),
                                      this.listBox1.Font,brSelectedFore,e.Bounds);    
                //e.DrawFocusRectangle();
                return;
            }

            //绘制没有被选中的情况
            e.Graphics.FillRectangle(brNoSelectedBack,e.Bounds);
            e.Graphics.DrawString(this.listBox1.Items[e.Index].ToString(),
                                 this.listBox1.Font,brNoSelectedFore,e.Bounds);            
        }


      到这里,一个简单的自绘ListBox就实现了,不过这里的代码都是直接加载父窗体的里面,不是很美观。其实我们可以自己实现一个这样的类,并把这个ListBox编译为一个.NET控件,这样,在其他的项目中就可以很简单的重用这个控件了。:)
    下面是这个自绘控件的效果,左边是我们的自绘ListBox,右边是普通的ListBox。等有时间,我会把这些封装成为一个dll控件 :)。这里提供源代码的下载,有兴趣的朋友可以再根据自己的需求进行一些自己的修改。



下载文件 点击下载此文件