WinForm 分屏 [ WinForm | Panel | 视频监控分屏 ]

前言
      视频监控的分屏技术实际上就是通过动态Panel + 动态指定其Location和Size来实现的,还需要一个计算分屏数目的算法,本文将弥补视频监控系列中动态分屏的功能,权当续文吧 : )

正文
      1.      先“上菜”再讲做法:——上图~~
            

            
      2.      动态Panel

复制代码
        /// <summary>
        
/// 动态创建面板
         
/// </summary>
        
/// <param name="xy">Panel的XY坐标</param>
        
/// <param name="wh">Panel的大小</param>
        private Panel CreatePanel(Point xy, Size wh)
        {
            Panel panel 
= new Panel();
            panel.BackColor 
= System.Drawing.Color.Transparent;
            panel.BackgroundImageLayout 
= System.Windows.Forms.ImageLayout.Stretch;
            panel.Location 
= xy;
            panel.Name 
= string.Concat("pVideo");
            panel.Size 
= wh;
            panel.TabIndex 
= 0;
            panel.BackColor 
= Color.Black;
            
return panel;
        }
复制代码

      3.      分屏算法

复制代码
        /// <summary>
        
/// 根据通道数动态计算Panel的坐标和大小
        
/// </summary>
        
/// <param name="channelCount">通道数</param>
        
/// <param name="xy">返回运算后每个Panel的坐标</param>
        
/// <param name="wh">返回运算后每个Panel的大小</param>
        private void MathDynamicPanel(int channelCount, out Point[] xy, out Size[] wh)
        {
            xy 
= new Point[channelCount];
            wh 
= new Size[channelCount];

            
//第一个Panel的起始坐标——不变
            xy[0= new Point(238);

            
//模数
            int modulo;

            
if (channelCount <= 4)
                modulo 
= 2;
            
else if (channelCount <= 9)
                modulo 
= 3;
            
else if (channelCount <= 16)
                modulo 
= 4;
            
else if (channelCount <= 25)
                modulo 
= 5;
            
else if (channelCount <= 36)
                modulo 
= 6;
            
else if (channelCount <= 49)
                modulo 
= 7;
            
else// if (channelCount <= 64)
                modulo = 8;

            
int width, height;
            
//610 为整个预览区的宽
            width = (610 - modulo * 1/ modulo;
            
//532 为整个预览区的高
            height = (532 - modulo * 1/ modulo;

            
for (int i = 0; i < channelCount; i++)
            {
                wh[i] 
= new Size(width, height);
                
if (i > 0)
                {
                    
//同一行的Y坐标相等
                    
//同一列的X坐标相等
                    if (i % modulo == 0)
                        xy[i] 
= new Point(xy[i - modulo].X, xy[i - modulo].Y + height + 1);
                    
else
                        xy[i] 
= new Point(xy[i - 1].X + width + 1, xy[i - 1].Y);
                }
            }
        }
复制代码

            代码说明:
                  a).      采用平方算法,即4个头4个Panel(2 ^ 2),8个头9个Panel(3 ^ 3),算是比较简单也满足基本需求的算法了。
                  b).      注意需要固定左上角顶点坐标和总面积,即(2,38)和610,532,这个可以根据自己的时间情况加以修改,可以定义成const int 就行。
                  c).      注意里面算坐标的时候有+1,这个是Panel之间的间隙。
      4.      使用例子
        在Form_Load中加入如下代码:

复制代码
            Point[] xy;
            Size[] wh;
            
int channel = 8;
            
//计算面板坐标
            MathDynamicPanel(channel, out xy, out wh);
            
//创建面板
            for (int i = 0; i < channel; i++)
            {
                
this.Controls.Add(CreatePanel(xy[i], wh[i]));
            }
复制代码

            运行即可见到截图中的样子,最大支持64个屏幕,满足基本需求,自己加上放大、缩小和全屏的代码功能就比较完整了。

 

  5.文章更新维护

    5.1  2010-5-22  修改一下方法,更加好用点

复制代码
        /// <summary>
        
/// 计算视频面板位置和面积
        
/// </summary>
        
/// <param name="channelCount"></param>
        
/// <param name="TotalSquare">总面积和坐标</param>
        
/// <returns></returns>
        private IList<Rectangle> CalcPanelRectangle(int channelCount, Size TotalArea)
        {
            IList
<Rectangle> result = new List<Rectangle>();

            
//模数
            int modulo;
            
if (channelCount <= 4)
                modulo 
= 2;
            
else if (channelCount > 64)
                modulo 
= 8;
            
else
                modulo 
= (int)Math.Ceiling(Math.Sqrt(channelCount));         //平方根

            
int width, height;

            
//单个画面大小
            width = (TotalArea.Width - modulo * 1/ modulo;
            height 
= (TotalArea.Height - modulo * 1/ modulo;

            
for (int i = 0; i < channelCount; i++)
            {
                Rectangle rect 
= new Rectangle();
                rect.Width 
= width;
                rect.Height 
= height;
                
if (i % modulo == 0)
                {
                    rect.X 
= 1;
                    
if (i == 0)
                        rect.Y 
= 1;
                    
else
                        rect.Y 
= result[i - modulo].Y + height + 1;
                }
                
else
                {
                    rect.X 
= result[i - 1].X + width + 1;
                    rect.Y 
= result[i - 1].Y;
                }
                result.Add(rect);
            }
            
return result;
        }
复制代码

  

    5.2  示例代码  2010-5-25

      分屏示例下载


结束语
      这个功能也是在最近代码重构的时候补上来的,也欢迎大家提供其他算法来分屏 :)

posted @ 2013-02-05 09:35  于为  阅读(590)  评论(0编辑  收藏  举报