C#仿QQ皮肤-ComboBox 控件实现

原文:http://www.sufeinet.com/thread-2082-1-1.html

导读部分
-------------------------------------------------------------------------------------------------------------
C#仿QQ皮肤-实现原理系列文章导航 最新版源码下载

http://www.sufeinet.com/thread-2-1-1.html   

 

    这个控件是在系统控件ComboBox的基础之上来实现的,我们先来看一下实现后的效果

                                    

 

 

    这是实现 后的效果,与普通的不同之处有,颜色有所变化,倒三角有所变化,再就是有一个鼠标跟随的效果。下面我来看看是怎么样实现的吧。

  我们第一步要打开我们的项目,然后右击项目,新添加一个Component组件。然后继承一下Combox类

 代码如下

  public   class  ComboBox : System.Windows.Forms.ComboBox

下面我们先定义几个变量

   // 鼠标Move事件时图片
         private  Image _mouseMoveImage  =   null ;

        
// 鼠标mouseDown事件时图片
         private  Image _mouseDownImage  =   null ;
        
//
         private  Image _normalImage  =   null ;

下面我看看再在构造方法里设置一下些固定的属性

代码

        
public  ComboBox()
            : 
base ()
        {
            
this .SetStyle(ControlStyles.OptimizedDoubleBuffer,  true );
            
// 设置为手动绘制
             this .DrawMode  =  DrawMode.OwnerDrawFixed;
            
// 设置固定的DropDownList样式
             this .DropDownStyle  =  ComboBoxStyle.DropDownList;
            
this .UpdateStyles();
        }

 

 

 为了让控件里的项目大小一至方便绘制和添加效果我们要重写一下OnCreateControl方法来固定一下Item的大小

 

代码
   protected   override   void  OnCreateControl()
        {
            
base .OnCreateControl();
            
if  ( ! DesignMode  &&   this .Items.Count  !=   0 )
            {
                
this .DropDownHeight  =   this .Items.Count  *   17 ;
            }
            ResetBitmap();
        }

 

ResetBitmap()方法就是用来设置不同情况下的颜色的

 

代码
  public   void  ResetBitmap()
        {
            
this .NormalImage  =  Shared.NomalDrawButton;
            
this .MouseDownImage  =  Shared.MouseDownDrawButton;
            
this .MouseMoveImage  =  Shared.MouseMoveDrawButton;
        }

 

 

Shared类的方法和属性请大家参考源代码里的 ,源代码的下载在  http://www.sufeinet.com/thread-2-1-1.html   

   这里都有提供。

下面还是老规矩重写一下WndProc方法吧,

 

代码
   protected   override   void  WndProc( ref  Message m)
        {
            IntPtr hDC 
=  IntPtr.Zero;
            Graphics gdc 
=   null ;

            
switch  (m.Msg)
            {
                
case   133 :
                    hDC 
=  Win32.GetWindowDC(m.HWnd);
                    gdc 
=  Graphics.FromHdc(hDC);
                    Win32.SendMessage(
this .Handle, WM_ERASEBKGND, hDC.ToInt32(),  0 );
                    SendPrintClientMsg();
                    Win32.SendMessage(
this .Handle, WM_PAINT,  0 0 );
                    OverrideControlBorder(gdc);
                    m.Result 
=  (IntPtr) 1 ;     //  indicate msg has been processed
                    Win32.ReleaseDC(m.HWnd, hDC);
                    gdc.Dispose();
                    
break ;
                
case  WM_PAINT:
                    
base .WndProc( ref  m);
                    hDC 
=  Win32.GetWindowDC(m.HWnd);
                    gdc 
=  Graphics.FromHdc(hDC);

                    OverrideDropDown(gdc);
                    OverrideControlBorder(gdc);
                    Win32.ReleaseDC(m.HWnd, hDC);
                    gdc.Dispose();
                    
break ;
                
default :
                    
base .WndProc( ref  m);
                    
break ;
            } 
        }

 

 

因为我们的图片颜色是手动绘制上去的所以我们应该在OverrideDropDown方法里进行绘制,也就是说当我们出现下拉列表的时候要绘制一下效果。

 

代码

        
private   void  OverrideDropDown(Graphics g)
        {
            
if  (DesignMode)  return ;

            Rectangle rect 
=   new  Rectangle( this .Width  -  DropDownButtonWidth,  0 , DropDownButtonWidth,  this .Height);

            g.FillRectangle(
new  SolidBrush(Color.White), rect);

            
if  ( this .Enabled)
            {
                
if  (_mouseEnter)
                {
                    g.DrawImage(
this .MouseMoveImage,  new  Rectangle( this .Width  -   20 3 16 16 ));
                }
                
else
                {
                    g.DrawImage(
this .NormalImage,  new  Rectangle( this .Width  -   20 3 16 16 ));
                }
            }
            
else
            {
                g.DrawImage(Shared.NotEnableDrawButton, 
new  Rectangle( this .Width  -   20 3 16 16 ));
            }
        }

 

根据鼠标的状态不同绘制出不同的效果,大家看一下If语句 就明白 了

还有一个更重的方法就是OnDrawItem方法这是在加载时绘制一下初始化的效果

 

代码

        
protected   override   void  OnDrawItem(DrawItemEventArgs e)
        {
            Graphics g 
=  e.Graphics;
            
// 绘制区域
            Rectangle r  =  e.Bounds;

            Font fn 
=   null ;
            
if  (e.Index  >=   0 )
            {
                
if  (e.State  ==  DrawItemState.None)
                {
                    
// 设置字体、字符串格式、对齐方式
                    fn  =  e.Font;
                    
string  s  =   this .Items[e.Index].ToString ();
                    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.White), r);
                        e.Graphics.DrawString(s, fn, 
new  SolidBrush(Shared.FontColor), r, sf);
                        e.DrawFocusRectangle();
                    }
                }
                
else
                {
                    fn 
=  e.Font;
                    StringFormat sf 
=   new  StringFormat();
                    sf.Alignment 
=  StringAlignment.Near;
                    
string  s  =   this .Items[e.Index].ToString ();
                    e.Graphics.FillRectangle(
new  SolidBrush(Shared.ControlBackColor), r);
                    e.Graphics.DrawString(s, fn, 
new  SolidBrush(Shared.FontColor), r, sf);
                    
                }
            }
        }

 

 

有了这些我们现在要做的就是在OnMouseEnter事件OnMouseLeave事件里处理一下绘制的效果和参数就算是完工了

我们一起来看看这两个事件的处理方法吧

 

代码
   protected   override   void  OnMouseEnter(EventArgs e)
        {
            _mouseEnter 
=   true ;

            IntPtr hDC 
=  IntPtr.Zero;
            Graphics gdc 
=   null ;
            hDC 
=  Win32.GetWindowDC( this .Handle);
            gdc 
=  Graphics.FromHdc(hDC);

            gdc.DrawImage(Shared.MouseMoveDrawButton, 
new  Rectangle( this .Width  -   20 3 16 16 ));

            Win32.ReleaseDC(
this .Handle, hDC);
            gdc.Dispose();

            
base .OnMouseEnter(e);
        }

        
protected   override   void  OnMouseLeave(EventArgs e)
        {
            _mouseEnter 
=   false ;
            IntPtr hDC 
=  IntPtr.Zero;
            Graphics gdc 
=   null ;
            hDC 
=  Win32.GetWindowDC( this .Handle);
            gdc 
=  Graphics.FromHdc(hDC);

            gdc.DrawImage(Shared.NomalDrawButton, 
new  Rectangle( this .Width  -   20 3 16 16 ));

            Win32.ReleaseDC(
this .Handle, hDC);
            
base .OnMouseLeave(e);
        }

 

到这里其实就可以完工了,其它的方法和事件都是一相辅助,等下可以看一下全部代码。

具体的使用方法和系统的Combox控件没有任何的分别。直接绑定数据就OK了。

为了方便以后的改动我把三个效果时产生的图片都定义成属性大家使用起来会方便一些

 

代码
   public  Image MouseMoveImage
        {
            
get
            {
                
return  _mouseMoveImage;
            }
            
set
            {
                _mouseMoveImage 
=  value;
            }
        }

        
public  Image MouseDownImage
        {
            
get
            {
                
return  _mouseDownImage;
            }
            
set
            {
                _mouseDownImage 
=  value;
            }
        }

        
public  Image NormalImage
        {
            
get
            {
                
return  _normalImage;
            }
            
set
            {
                _normalImage 
=  value;
            }
        }

 

整个类的代码如下

 

代码
using  System;
using  System.Collections.Generic;
using  System.Drawing;
using  System.Text;
using  System.Windows.Forms;
using  CRD.Common;

namespace  CRD.WinUI.Misc
{
    
public   class  ComboBox : System.Windows.Forms.ComboBox
    {
        
// 鼠标Move事件时图片
         private  Image _mouseMoveImage  =   null ;

        
// 鼠标mouseDown事件时图片
         private  Image _mouseDownImage  =   null ;
        
//
         private  Image _normalImage  =   null ;


        
public  ComboBox()
            : 
base ()
        {
            
this .SetStyle(ControlStyles.OptimizedDoubleBuffer,  true );
            
// 设置为手动绘制
             this .DrawMode  =  DrawMode.OwnerDrawFixed;
            
// 设置固定的DropDownList样式
             this .DropDownStyle  =  ComboBoxStyle.DropDownList;
            
this .UpdateStyles();
        }

        
protected   override   void  OnCreateControl()
        {
            
base .OnCreateControl();
            
if  ( ! DesignMode  &&   this .Items.Count  !=   0 )
            {
                
this .DropDownHeight  =   this .Items.Count  *   17 ;
            }
            ResetBitmap();
        }

        
const   int  WM_ERASEBKGND  =   0x14 ;
        
const   int  WM_PAINT  =   0xF ;
        
const   int  WM_NC_HITTEST  =   0x84 ;
        
const   int  WM_NC_PAINT  =   0x85 ;
        
const   int  WM_PRINTCLIENT  =   0x318 ;
        
const   int  WM_SETCURSOR  =   0x20 ;

        
protected   override   void  WndProc( ref  Message m)
        {
            IntPtr hDC 
=  IntPtr.Zero;
            Graphics gdc 
=   null ;

            
switch  (m.Msg)
            {
                
case   133 :
                    hDC 
=  Win32.GetWindowDC(m.HWnd);
                    gdc 
=  Graphics.FromHdc(hDC);
                    Win32.SendMessage(
this .Handle, WM_ERASEBKGND, hDC.ToInt32(),  0 );
                    SendPrintClientMsg();
                    Win32.SendMessage(
this .Handle, WM_PAINT,  0 0 );
                    OverrideControlBorder(gdc);
                    m.Result 
=  (IntPtr) 1 ;     //  indicate msg has been processed
                    Win32.ReleaseDC(m.HWnd, hDC);
                    gdc.Dispose();
                    
break ;
                
case  WM_PAINT:
                    
base .WndProc( ref  m);
                    hDC 
=  Win32.GetWindowDC(m.HWnd);
                    gdc 
=  Graphics.FromHdc(hDC);

                    OverrideDropDown(gdc);
                    OverrideControlBorder(gdc);
                    Win32.ReleaseDC(m.HWnd, hDC);
                    gdc.Dispose();
                    
break ;
                
default :
                    
base .WndProc( ref  m);
                    
break ;
            } 
        }

        
private   static   int  DropDownButtonWidth  =   17 ;

        
private   void  OverrideDropDown(Graphics g)
        {
            
if  (DesignMode)  return ;

            Rectangle rect 
=   new  Rectangle( this .Width  -  DropDownButtonWidth,  0 , DropDownButtonWidth,  this .Height);

            g.FillRectangle(
new  SolidBrush(Color.White), rect);

            
if  ( this .Enabled)
            {
                
if  (_mouseEnter)
                {
                    g.DrawImage(
this .MouseMoveImage,  new  Rectangle( this .Width  -   20 3 16 16 ));
                }
                
else
                {
                    g.DrawImage(
this .NormalImage,  new  Rectangle( this .Width  -   20 3 16 16 ));
                }
            }
            
else
            {
                g.DrawImage(Shared.NotEnableDrawButton, 
new  Rectangle( this .Width  -   20 3 16 16 ));
            }
        }

        
private  Pen BorderPen  =   new  Pen(Shared.ControlBorderBackColor,  2 );
        
private  Pen BorderPenControl  =   new  Pen(Shared.ControlBorderBackColor,  2 );

        
private   void  OverrideControlBorder(Graphics g)
        {
            g.DrawRectangle(
new  Pen(Shared.ControlBorderBackColor,  2 ),  new  Rectangle( 0 0 this .Width,  this .Height));

        }

        
private   void  SendPrintClientMsg()
        {
            
//  We send this message for the control to redraw the client area
            Graphics gClient  =   this .CreateGraphics();
            IntPtr ptrClientDC 
=  gClient.GetHdc();
            Win32.SendMessage(
this .Handle, WM_PRINTCLIENT, ptrClientDC.ToInt32(),  0 );
            gClient.ReleaseHdc(ptrClientDC);
            gClient.Dispose();
        }


        
protected   override   void  OnDrawItem(DrawItemEventArgs e)
        {
            Graphics g 
=  e.Graphics;
            
// 绘制区域
            Rectangle r  =  e.Bounds;

            Font fn 
=   null ;
            
if  (e.Index  >=   0 )
            {
                
if  (e.State  ==  DrawItemState.None)
                {
                    
// 设置字体、字符串格式、对齐方式
                    fn  =  e.Font;
                    
string  s  =   this .Items[e.Index].ToString ();
                    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.White), r);
                        e.Graphics.DrawString(s, fn, 
new  SolidBrush(Shared.FontColor), r, sf);
                        e.DrawFocusRectangle();
                    }
                }
                
else
                {
                    fn 
=  e.Font;
                    StringFormat sf 
=   new  StringFormat();
                    sf.Alignment 
=  StringAlignment.Near;
                    
string  s  =   this .Items[e.Index].ToString ();
                    e.Graphics.FillRectangle(
new  SolidBrush(Shared.ControlBackColor), r);
                    e.Graphics.DrawString(s, fn, 
new  SolidBrush(Shared.FontColor), r, sf);
                    
                }
            }
        }

        
private   bool  _mouseEnter  =   false ;

        
protected   override   void  OnMouseEnter(EventArgs e)
        {
            _mouseEnter 
=   true ;

            IntPtr hDC 
=  IntPtr.Zero;
            Graphics gdc 
=   null ;
            hDC 
=  Win32.GetWindowDC( this .Handle);
            gdc 
=  Graphics.FromHdc(hDC);

            gdc.DrawImage(Shared.MouseMoveDrawButton, 
new  Rectangle( this .Width  -   20 3 16 16 ));

            Win32.ReleaseDC(
this .Handle, hDC);
            gdc.Dispose();

            
base .OnMouseEnter(e);
        }

        
protected   override   void  OnMouseLeave(EventArgs e)
        {
            _mouseEnter 
=   false ;
            IntPtr hDC 
=  IntPtr.Zero;
            Graphics gdc 
=   null ;
            hDC 
=  Win32.GetWindowDC( this .Handle);
            gdc 
=  Graphics.FromHdc(hDC);

            gdc.DrawImage(Shared.NomalDrawButton, 
new  Rectangle( this .Width  -   20 3 16 16 ));

            Win32.ReleaseDC(
this .Handle, hDC);
            
base .OnMouseLeave(e);
        }

        
public  Image MouseMoveImage
        {
            
get
            {
                
return  _mouseMoveImage;
            }
            
set
            {
                _mouseMoveImage 
=  value;
            }
        }

        
public  Image MouseDownImage
        {
            
get
            {
                
return  _mouseDownImage;
            }
            
set
            {
                _mouseDownImage 
=  value;
            }
        }

        
public  Image NormalImage
        {
            
get
            {
                
return  _normalImage;
            }
            
set
            {
                _normalImage 
=  value;
            }
        }

        
public   void  ResetBitmap()
        {
            
this .NormalImage  =  Shared.NomalDrawButton;
            
this .MouseDownImage  =  Shared.MouseDownDrawButton;
            
this .MouseMoveImage  =  Shared.MouseMoveDrawButton;
        }


    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值