千里独行

国虽大,黩武必亡;天下虽安,忘战必危★★ 准备并期待着中日决战||本站文章可以全部转载

博客园 首页 新随笔 联系 订阅 管理

虚控件在GUI编程中的应用

南京千里独行2005 yyf9989@hotmail.com

在图形化用户界面编程中,用户控件是一个很重要的概念。本质上我们的图形化用户界面是由各种控件构成,这些控件有些是IDE开发商提供的,有些是第三方提供的,若这些控件都不能完成功能则需要自己编写控件了。在C#中编写一个控件很简单,以下代码就能实现一个用户控件。

   public class UserControl1 : System.Windows.Forms.UserControl
 {
  protected override void OnMouseMove(MouseEventArgs e)
  {
   // 处理鼠标移动代码
  }
  protected override void OnPaint(PaintEventArgs e)
  {
   // 绘制用户界面的代码
  }
  // 用户控件的其他代码
 }
   

在此小弟提出“虚控件”的概念,所谓虚控件就是在控件和操作控件的代码之间放置一个代理层,所有的代码通过这个代理来操作控件,而控件的事件也通过这个代理层来调用相关的控制代码,控件和代码不直接发生关系。以下代码实现了一个简单的“虚控件”中的代理层

   public class VirtualControlBase
 {
  protected System.Windows.Forms.Control   myControl = null;
  public System.Windows.Forms.PaintEventHandler  _Paint  = null;
  public System.Windows.Forms.MouseEventHandler  _MouseMove = null;
  
  public VirtualControlBase()
  {
   _Paint  = new System.Windows.Forms.PaintEventHandler(myControl_Paint);
   _MouseMove = new System.Windows.Forms.MouseEventHandler(myControl_MouseMove);
  
  }
  // 绑定的控件
  public System.Windows.Forms.Control BindControl
  {
   get{ return myControl ;}
   set
   {
    if( value != myControl )
    {
     if( myControl != null)
     {
      myControl.Paint   -= _Paint;
      myControl.MouseMove  -= _MouseMove;
     }
     myControl = value ;
     if( myControl != null)
     {
      myControl.Paint   += _Paint;
      myControl.MouseMove  += _MouseMove;
     }
    }
   }
  }//public System.Windows.Forms.Control BindControl
  private void myControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
  { HandlePaint( e.Graphics , e.ClipRectangle ); }
  private void myControl_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
  { HandleMouseMove(e.X , e.Y , e.Button ); }  
  protected virtual void HandlePaint( System.Drawing.Graphics Graphics , System.Drawing.Rectangle ClipRectangle ){}
  protected virtual void HandleMouseMove( int x , int y , System.Windows.Forms.MouseButtons Button ){}
  public System.Drawing.Size ClientSize
  {
   get{ return System.Drawing.Size.Empty ;}
  }
  public System.Drawing.Rectangle Bounds
  {
   get{ return myControl.Bounds ;}
  }
  public System.Drawing.Graphics CreateGraphics()
  {
   return myControl.CreateGraphics();
  }
  public System.Windows.Forms.Cursor Cursor
  {
   get{ return myControl.Cursor ;}
   set{ myControl.Cursor = value;}
  }
  public System.Drawing.Font Font
  {
   get{ return myControl.Font ;}
   set{ myControl.Font = value;}
  }
  public void Refresh()
  {
   myControl.Refresh();
  }
  public void Invalidate( System.Drawing.Rectangle Rect )
  {
   myControl.Invalidate( Rect , true );
  }
  public void Update()
  {
   myControl.Update();
  }
 }//public class VirtualControlBase

有了这个代理层,以后开发用户控件就不是基于System.Windows.Form.UserControl继承了。而是基于VirtualControlBase的继承了,此时开发的虚控件只有重载HandlePaint和HandleMouseMove来绘制控件用户界面并处理鼠标移动事件。此时用户控件的代码如下
   public class UserControl2 : VirtualControlBase
 {
  protected override void HandleMouseMove(int x, int y, MouseButtons Button)
  {
   // 处理鼠标移动的代码
  }
  protected override void HandlePaint(Graphics Graphics, Rectangle ClipRectangle)
  {
   // 绘制用户界面的代码
  }
  // 用户控件的其他代码
 }
这种模式我称为“虚控件”模式,而传统的控件称为“实控件”模式。

设计良好的虚控件的代理层能使得代码的编写和实控件的代码的编写没有多大的区别。

虚控件是不能直接使用的,它得依附在其他控件使用,首先在窗体中放置一个标准控件,比如Panel等等。然后实例化一个虚控件,调用VirtualControlBase.BindControl 属性来进行控件绑定,如此才可使用。

为何开发一个用户控件需要如此多此一举。其实这样做有不少好处,可列举的有

  • 有利于代码的分离和模块化
  • 实控件只能使用于图形化用户界面程序,而虚控件除了应用于图形化用户界面程序外还可使用于其他任何类型的程序,包括命令行程序,ASP.NET,WebService,Windows服务。这个特性可以适用于某些程序的移植。例如将GUI程序移植到ASP.NET中,GUI程序中编制了虚控件绘制的复杂图形,而后在ASP.NET程序中,它创建一个BMP图片,然后使用库函数System.Drawing.Graphics.FromImage创建一个Graphics对象,然后调用虚控件的HandlePaint来绘制这个复杂图形,然后就可以发布出去了。这样虚控件既可用于GUI程序又可用于ASP.NET程序,实现了代码的重用。利用这个特性还能比较好的修改旧的GUI代码,保持原有功能并向ASP.NET等非GUI程序提供图形支持。
  • 虚控件可以减少控件的个数,在某些GUI应用中,窗体中可能堆积很多一样的控件,例如窗体有一个TabControl,有很多页,每页中放一个相同类型的用户控件,用户需要在这些控件来回切换。大家知道.NET的控件是基于Win32的窗体的,创建一个控件比较费力,消耗资源。而虚控件本质上只是一个类,在.NET中创建一个类是很简单的。这样在窗体中只要放置一个控件,然后生成很多虚控件,在各个控件来回切换就转换为各个虚控件绑定和取消绑定实控件的操作。而且在窗体中放置大量的控件不利于窗体设计器的工作。若某个控件在设计状态下发生错误则会影响窗体设计器的正常工作。(在VB中若用户控件加载错误会自动转换为一个PictureBox控件,所有的设计属性都会丢失)
  • 使用某个控件前需要在VS.NET的工具箱中加入这个控件的图标,这个操作比较麻烦,而且打开其他不需要该控件的工程中,工具箱还会显示该控件的图标。而使用虚控件则不会出现这种情况

其实虚控件的概念还能用VB来实现,以下代码就是一个简单的例子

' 类 myControl.cls 的内容
Private WithEvents myControl As VB.PictureBox
Public Sub SetBindControl(ByVal p As VB.PictureBox)
    Set myControl = p
End Sub
Private Sub myControl_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' 处理鼠标移动事件
End Sub
Private Sub myControl_Paint()
    ' 绘图图形的操作
End Sub
我用C#编写的一个虚控件代理层的完整代码,望高手完善之
/// <summary>
    
/// 绑定控件的模块
    
/// </summary>

    public class ControlBinder
    
{
        
protected System.Windows.Forms.Control                myControl    = null;

        
public System.Windows.Forms.PaintEventHandler        _Paint        = null;
        
public System.Windows.Forms.MouseEventHandler        _MouseDown    = null;
        
public System.Windows.Forms.MouseEventHandler        _MouseMove    = null;
        
public System.Windows.Forms.MouseEventHandler        _MouseUp    = null;
        
public System.EventHandler                            _MouseEnter    = null;
        
public System.EventHandler                            _MouseLeave    = null;
        
public System.Windows.Forms.MouseEventHandler        _MouseWheel    = null;
        
public System.Windows.Forms.KeyEventHandler            _KeyDown    = null;
        
public System.Windows.Forms.KeyPressEventHandler    _KeyPress    = null;
        
public System.Windows.Forms.KeyEventHandler            _KeyUp        = null;
        
public System.EventHandler                            _GotFocus    = null;
        
public System.EventHandler                             _LostFocus    = null;
        
public System.EventHandler                             _Click        = null;
        
public System.EventHandler                             _DoubleClick= null;
        
public System.EventHandler                             _Resize        = null;

        
/// <summary>
        
/// 初始化对象
        
/// </summary>

        public ControlBinder()
        
{
            _Paint        
= new System.Windows.Forms.PaintEventHandler(myControl_Paint);
            _MouseDown    
= new System.Windows.Forms.MouseEventHandler(myControl_MouseDown);
            _MouseMove    
= new System.Windows.Forms.MouseEventHandler(myControl_MouseMove);
            _MouseUp    
= new System.Windows.Forms.MouseEventHandler(myControl_MouseUp);
            _MouseEnter    
= new System.EventHandler(myControl_MouseEnter);
            _MouseLeave    
= new System.EventHandler(myControl_MouseLeave);
            _MouseWheel    
= new System.Windows.Forms.MouseEventHandler(myControl_MouseWheel);
            _KeyDown    
= new System.Windows.Forms.KeyEventHandler(myControl_KeyDown);
            _KeyPress    
= new System.Windows.Forms.KeyPressEventHandler(myControl_KeyPress);
            _KeyUp        
= new System.Windows.Forms.KeyEventHandler(myControl_KeyUp);
            _GotFocus    
= new System.EventHandler(myControl_GotFocus);
            _LostFocus    
= new System.EventHandler(myControl_LostFocus);
            _Click        
= new System.EventHandler(myControl_Click);
            _DoubleClick
= new System.EventHandler(myControl_DoubleClick);
            _Resize        
= new System.EventHandler(myControl_Resize);
        }


        
/// <summary>
        
/// 绑定的控件
        
/// </summary>

        public System.Windows.Forms.Control BindControl
        
{
            
getreturn myControl ;}
            
set
            
{
                
if( value != myControl )
                
{
                    
if( myControl != null)
                    
{
                        myControl.Paint            
-= _Paint;
                        myControl.MouseDown        
-= _MouseDown;
                        myControl.MouseMove        
-= _MouseMove;
                        myControl.MouseUp        
-= _MouseUp;
                        myControl.MouseEnter    
-= _MouseEnter;
                        myControl.MouseLeave    
-= _MouseLeave;
                        myControl.MouseWheel    
-= _MouseWheel;
                        myControl.KeyDown        
-= _KeyDown;
                        myControl.KeyPress        
-= _KeyPress;
                        myControl.KeyUp            
-= _KeyUp;
                        myControl.GotFocus        
-= _GotFocus;
                        myControl.LostFocus        
-= _LostFocus;
                        myControl.Click            
-= _Click;
                        myControl.DoubleClick    
-= _DoubleClick;
                        myControl.Resize        
-= _Resize;
                    }

                    myControl 
= value ;
                    
if( myControl != null)
                    
{
                        myControl.Paint            
+= _Paint;
                        myControl.MouseDown        
+= _MouseDown;
                        myControl.MouseMove        
+= _MouseMove;
                        myControl.MouseUp        
+= _MouseUp;
                        myControl.MouseEnter    
+= _MouseEnter;
                        myControl.MouseLeave    
+= _MouseLeave;
                        myControl.MouseWheel    
+= _MouseWheel;
                        myControl.KeyDown        
+= _KeyDown;
                        myControl.KeyPress        
+= _KeyPress;
                        myControl.KeyUp            
+= _KeyUp;
                        myControl.GotFocus        
+= _GotFocus;
                        myControl.LostFocus        
+= _LostFocus;
                        myControl.Click            
+= _Click;
                        myControl.DoubleClick    
+= _DoubleClick;
                        myControl.Resize        
+= _Resize;
                    }

                }

            }

        }
//public System.Windows.Forms.Control BindControl
        
        
private void myControl_KeyDown        (object sender, System.Windows.Forms.KeyEventArgs e) {    HandleKeyDown( e.KeyCode , e.Alt , e.Shift , e.Control );    }
        
private void myControl_KeyPress        (object sender, System.Windows.Forms.KeyPressEventArgs e)    {    HandleKeyPress( e.KeyChar );    }
        
private void myControl_KeyUp        (object sender, System.Windows.Forms.KeyEventArgs e)        {    HandleKeyUp( e.KeyCode , e.Alt , e.Shift , e.Control );    }
        
private void myControl_MouseLeave    (object sender, System.EventArgs e)        {    HandleMouseLeave( );    }
        
private void myControl_MouseWheel    (object sender, System.Windows.Forms.MouseEventArgs e)        {    HandleMouseWheel( e.X , e.Y , e.Button );    }
        
private void myControl_GotFocus        (object sender, System.EventArgs e)        {    HandleGotFocus ();    }
        
private void myControl_LostFocus    (object sender, System.EventArgs e)        {    HandleLostFocus();    }
        
private void myControl_MouseEnter    (object sender, System.EventArgs e)        {    HandleMouseEnter();    }
        
private void myControl_Click        (object sender, System.EventArgs e)        
        
{
            System.Drawing.Point p 
= System.Windows.Forms.Control.MousePosition ;
            p 
= myControl.PointToClient( p );
            HandleClick( p.X , p.Y , System.Windows.Forms.Control.MouseButtons );    
        }

        
private void myControl_DoubleClick    (object sender, System.EventArgs e)        
        
{
            System.Drawing.Point p 
= System.Windows.Forms.Control.MousePosition ;
            p 
= myControl.PointToClient( p );
            HandleDoubleClick( p.X , p.Y , System.Windows.Forms.Control.MouseButtons );    
        }

        
private void myControl_Paint        (object sender, System.Windows.Forms.PaintEventArgs e)        {    HandlePaint( e.Graphics , e.ClipRectangle );    }
        
private void myControl_MouseDown    (object sender, System.Windows.Forms.MouseEventArgs e)        {    HandleMouseDown( e.X , e.Y , e.Button );    }
        
private void myControl_MouseMove    (object sender, System.Windows.Forms.MouseEventArgs e)        {    HandleMouseMove( e.X , e.Y , e.Button );    }
        
private void myControl_MouseUp        (object sender, System.Windows.Forms.MouseEventArgs e)        {    HandleMouseUp( e.X , e.Y , e.Button );    }
        
private void myControl_Resize        (object sender, System.EventArgs e)        {    HandleResize( );    }

        
控件事件处理过程群

        
/// <summary>
        
/// 控件工作区的大小
        
/// </summary>

        public System.Drawing.Size ClientSize
        
{
            
get
            
{
                
if( myControl != null)
                    
return myControl.ClientSize ;
                
else
                    
return System.Drawing.Size.Empty ;
            }

        }

        
/// <summary>
        
/// 控件的大小和位置
        
/// </summary>

        public System.Drawing.Rectangle Bounds
        
{
            
get
            
{
                
if( myControl == null)
                    
return System.Drawing.Rectangle.Empty ;
                
else
                    
return myControl.Bounds ;
            }

        }

        
/// <summary>
        
/// 创建绘图对象
        
/// </summary>
        
/// <returns></returns>

        public System.Drawing.Graphics CreateGraphics()
        
{
            
if( myControl == null)
                
return null;
            
else
                
return myControl.CreateGraphics();
        }

        
/// <summary>
        
/// 设置输入焦点
        
/// </summary>

        public void Focus()
        
{
            
if( myControl != null)
                myControl.Focus();
        }

        
/// <summary>
        
/// 鼠标光标
        
/// </summary>

        public System.Windows.Forms.Cursor Cursor
        
{
            
get
            
{
                
if( myControl == null)
                    
return System.Windows.Forms.Cursors.Default ;
                
else
                    
return myControl.Cursor ;
            }

            
set
            
{
                
if( myControl != null)
                    myControl.Cursor 
= value;
            }

        }

        
/// <summary>
        
/// 是否获得焦点
        
/// </summary>

        public bool Focused
        
{
            
getreturn myControl == null ? false : myControl.Focused ;}
        }

        
/// <summary>
        
/// 字体
        
/// </summary>

        public System.Drawing.Font Font
        
{
            
getreturn myControl == null ? null : myControl.Font ;}
            
set
            
{
                
if( myControl != null)
                    myControl.Font 
= value;
            }

        }


        
public void Refresh()
        
{
            
if( myControl != null)
                myControl.Refresh();
        }


        
public System.Windows.Forms.Control.ControlCollection Controls
        
{
            
get
            
{
                
return myControl == null ? null : myControl.Controls ;
            }

        }

        
public void Invalidate( System.Drawing.Rectangle Rect )
        
{
            
if( myControl != null)
                myControl.Invalidate( Rect , 
true );
        }

        
public bool Capture
        
{
            
getreturn myControl == null ? false : myControl.Capture ;}
        }

        
public void Update()
        
{
            
if( myControl != null)
                myControl.Update();
        }

        
public int Height
        
{
            
getreturn myControl == null ? 0 : myControl.Height ;}
            
set
            
{
                
if( myControl != null)
                    myControl.Height 
= value;
            }

        }

    }
//public class ControlBinder
posted on 2005-09-17 18:16  千里独行  阅读(1645)  评论(2)    收藏  举报