zoukankan      html  css  js  c++  java
  • 分享一个自定义打印套打方案

    最近项目中需要实现单据套打的功能,实现后,留此日记以备忘,同时为有类似需求的同学提供一种解决方案.

    原始需求:

    1. 打印模板支持灵活自定义,支持可视化设置(含设置打印项是否打印,及位置,大小,字体等…).

    2. 支持自定义打印项.

    3. 常规的打印项设置(如自动打印小计/合计,表头表尾等…)

    4. 在设置模板的时候,支持实时预览.

    首先,先上个图, 给大家看一下打印套打模板的大致效果图,各位同学看着顺眼再往下看.

    image

    接下来,我们简单的来讨论一下如何实现这个需求,简单分析一下,在这个功能中,可能需要存在以下角色对象.

    1. 打印项: 姑且暂称为 PrintItem ,我们不难发现至少应该具备以下属性: 标签名称, 数据源, 宽度, 高度, 字体, 颜色, 对齐方式, 打印坐标(表明细区域可能为打印位置索引)…

    2. 打印模板数据: 姑且暂称为 BillPrintData , 为了简单起见,我们可以将这个打印模板数据拆分为 表头, 表体, 表尾,因为表头和表尾在控制上行为基本上是一致的,由此我们很自然的衍生出来了 表头表尾 以及 中间的”表体 ”这两个对象.

    3. 表头表尾: 姑且暂称为 BillHeaderOrBottom ,不难看出,其理所应当的应该包含一个打印项集合,一个为这些打印项赋值的数据源. 以及这个区域的大小和其实坐标位置.

    4. 表体即中间表格部分,姑且暂称为 BillGridBody, 具有和 BillHeaderOrBottom 一样的内容,同时还应该有设置那些行需要小计/合计.

    5. 打印控制器,姑且暂称为  BillPrinter , 主要功能为加载打印格式,同时根据参数配置,控制输出到打印机.

    有了上面的简单分析,我们来简单画一下这个需求的类结构图.

    image

    有了上面这些分析,下面我们一起来看下如何来实现这个功能.我们先来实现一个可运行状态随意拖动的容器控件.

    为了简单起见,这里我们不妨就暂称我们将要扩展的Panel容器名称为 MoveControlPanel,该容器至少需要实现以下功能

    1. 识别当前鼠标位置,是否处于某个内部组件的边框位置,以让鼠标显示出对应的图标(拉伸,移动…)

    2.移动鼠标以改变内部某个组件的大小及坐标,

    3.保存容器内每个组件的当前坐标及大小.

    为了便于描述当前光标状态,我们不妨定义一个枚举.姑且称其为 EMousePointPosition, 其至少应该具有如下定义.

           /// <summary>
            /// 光标状态
            /// </summary>
            private enum EMousePointPosition
            {
                /// <summary>
                /// 无
                /// </summary>
                None = 0,
    
                /// <summary>
                /// 处于拉伸右边框位置
                /// </summary>
                MouseSizeRight = 1,
    
                /// <summary>
                /// 处于拉伸左边框位置
                /// </summary>
                MouseSizeLeft = 2,
    
                /// <summary>
                /// 处于拉伸下边框位置
                /// </summary>
                MouseSizeBottom = 3,
    
                /// <summary>
                /// 处于拉伸上边框位置
                /// </summary>
                MouseSizeTop = 4,
    
                /// <summary>
                /// 处于拉伸左上角位置
                /// </summary>
                MouseSizeTopLeft = 5,
    
                /// <summary>
                /// 处于拉伸右上角位置
                /// </summary>
                MouseSizeTopRight = 6,
    
                /// <summary>
                /// 处于拉伸左小角位置
                /// </summary>
                MouseSizeBottomLeft = 7,
    
                /// <summary>
                /// 处于拉伸右下角位置
                /// </summary>
                MouseSizeBottomRight = 8,
    
                /// <summary>
                /// 鼠标拖动状态
                /// </summary>
                MouseDrag = 9
            }

    接下来,我们需要通过处理容器内控件的 鼠标按下/鼠标移动/鼠标离开 三个事件,来实现对容器内各个控件的大小/位置的改变.

    /// <summary>
    /// 初始化鼠标事件
    /// </summary>
    public void InitMouseEvent()
    {
      for (int i = 0; i < this.Controls.Count; i++)
        {
          this.Controls[i].MouseDown += new System.Windows.Forms.MouseEventHandler(ctrl_MouseDown);
          this.Controls[i].MouseLeave += new System.EventHandler(ctrl_MouseLeave);
          this.Controls[i].MouseMove += new System.Windows.Forms.MouseEventHandler(ctrl_MouseMove);
         }
    }

    接下来我们去尝试实现以下鼠标移动事件,

    1) 如果当前没有按下鼠标按键,则去尝试获取当前鼠标的状态,并设置当前光标样式

    2) 当按下了鼠标左键,此时需要根据光标状态来改变当前控件的坐标/大小.

    private const int Band = 5;                                     //边框大小
     private const int MinWidth = 10;                            //最小宽度
     private const int MinHeight = 10;                           //最小高度
     private EMousePointPosition _currentMousePointPosition;     //当前鼠标状态
     private Point p, p1;                                        //临时变量,缓存改变前后鼠标坐标
    
            /// <summary>
            /// 获取鼠标坐标状态
            /// </summary>
            /// <param name="size">当前控件大小</param>
            /// <param name="e">当前鼠标坐标位置</param>
            /// <returns></returns>
            private EMousePointPosition GetMousePointPosition(Size size, Point e)
            {
                if ((e.X >= -1 * Band) | (e.X <= size.Width) | (e.Y >= -1 * Band) | (e.Y <= size.Height))
                {
                    if (e.X < Band)
                    {
                        if (e.Y < Band)
                        {
                            return EMousePointPosition.MouseSizeTopLeft;
                        }
                        else
                        {
                            if (e.Y > -1 * Band + size.Height)
                            {
                                return EMousePointPosition.MouseSizeBottomLeft;
                            }
                            else
                            {
                                return EMousePointPosition.MouseSizeLeft;
                            }
                        }
                    }
                    else
                    {
                        if (e.X > -1 * Band + size.Width)
                        {
                            if (e.Y < Band)
                            {
                                return EMousePointPosition.MouseSizeTopRight;
                            }
                            else
                            {
                                if (e.Y > -1 * Band + size.Height)
                                {
                                    return EMousePointPosition.MouseSizeBottomRight;
                                }
                                else
                                {
                                    return EMousePointPosition.MouseSizeRight;
                                }
                            }
                        }
                        else
                        {
                            if (e.Y < Band)
                            {
                                return EMousePointPosition.MouseSizeTop;
                            }
                            else
                            {
                                if (e.Y > -1 * Band + size.Height)
                                {
                                    return EMousePointPosition.MouseSizeBottom;
                                }
                                else
                                {
                                    return EMousePointPosition.MouseDrag;
                                }
                            }
                        }
                    }
                }
                else
                {
                    return EMousePointPosition.None;
                }
            }
    /// <summary>
            /// 设置光标状态
            /// </summary>
            /// <param name="e">当前引发的鼠标事件参数</param>
            /// <param name="tempCtrl">当前控件大小</param>
            private void SetCursorStyle(MouseEventArgs e, Control tempCtrl)
            {
                _currentMousePointPosition = GetMousePointPosition(tempCtrl.Size, e.Location);   //判断光标的位置状态   
    
                //根据光标位置状态设置当前鼠标状态
                switch (_currentMousePointPosition)
                {
                    case EMousePointPosition.None:
                        this.Cursor = Cursors.Arrow;
                        break;
                    case EMousePointPosition.MouseDrag:                 //移动效果
                        this.Cursor = Cursors.SizeAll;
                        break;
                    case EMousePointPosition.MouseSizeBottom:           //上下边框              
                    case EMousePointPosition.MouseSizeTop:
                        this.Cursor = Cursors.SizeNS;
                        break;
                    case EMousePointPosition.MouseSizeLeft:             //左右边框
                    case EMousePointPosition.MouseSizeRight:
                        this.Cursor = Cursors.SizeWE;
                        break;
                    case EMousePointPosition.MouseSizeBottomLeft:       //左上/右下
                    case EMousePointPosition.MouseSizeTopRight:
                        this.Cursor = Cursors.SizeNESW;
                        break;
                    case EMousePointPosition.MouseSizeBottomRight:      //右下左上
                    case EMousePointPosition.MouseSizeTopLeft:
                        this.Cursor = Cursors.SizeNWSE;
                        break;
                    default:
                        break;
                }
            }
    /// <summary>
            /// 处理鼠标移动事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void ctrl_MouseMove(object sender, MouseEventArgs e)
            {
                Control tempCtrl = sender as Control;
    
                if (e.Button == MouseButtons.Left)
                {
                    switch (_currentMousePointPosition)
                    {
                        case EMousePointPosition.MouseDrag:
                            tempCtrl.Left = tempCtrl.Left + e.X - p.X;
                            tempCtrl.Top = tempCtrl.Top + e.Y - p.Y;
                            break;
                        case EMousePointPosition.MouseSizeBottom:
                            tempCtrl.Height = tempCtrl.Height + e.Y - p1.Y;
                            p1.X = e.X;
                            p1.Y = e.Y; //记录光标拖动的当前点   
                            break;
                        case EMousePointPosition.MouseSizeBottomRight:
                            tempCtrl.Width = tempCtrl.Width + e.X - p1.X;
                            tempCtrl.Height = tempCtrl.Height + e.Y - p1.Y;
                            p1.X = e.X;
                            p1.Y = e.Y; //记录光标拖动的当前点   
                            break;
                        case EMousePointPosition.MouseSizeRight:
                            tempCtrl.Width = tempCtrl.Width + e.X - p1.X;
                            //       lCtrl.Height = lCtrl.Height + e.Y - p1.Y;   
                            p1.X = e.X;
                            p1.Y = e.Y; //'记录光标拖动的当前点   
                            break;
                        case EMousePointPosition.MouseSizeTop:
                            tempCtrl.Top = tempCtrl.Top + (e.Y - p.Y);
                            tempCtrl.Height = tempCtrl.Height - (e.Y - p.Y);
                            break;
                        case EMousePointPosition.MouseSizeLeft:
                            tempCtrl.Left = tempCtrl.Left + e.X - p.X;
                            tempCtrl.Width = tempCtrl.Width - (e.X - p.X);
                            break;
                        case EMousePointPosition.MouseSizeBottomLeft:
                            tempCtrl.Left = tempCtrl.Left + e.X - p.X;
                            tempCtrl.Width = tempCtrl.Width - (e.X - p.X);
                            tempCtrl.Height = tempCtrl.Height + e.Y - p1.Y;
                            p1.X = e.X;
                            p1.Y = e.Y; //记录光标拖动的当前点   
                            break;
                        case EMousePointPosition.MouseSizeTopRight:
                            tempCtrl.Top = tempCtrl.Top + (e.Y - p.Y);
                            tempCtrl.Width = tempCtrl.Width + (e.X - p1.X);
                            tempCtrl.Height = tempCtrl.Height - (e.Y - p.Y);
                            p1.X = e.X;
                            p1.Y = e.Y; //记录光标拖动的当前点   
                            break;
                        case EMousePointPosition.MouseSizeTopLeft:
                            tempCtrl.Left = tempCtrl.Left + e.X - p.X;
                            tempCtrl.Top = tempCtrl.Top + (e.Y - p.Y);
                            tempCtrl.Width = tempCtrl.Width - (e.X - p.X);
                            tempCtrl.Height = tempCtrl.Height - (e.Y - p.Y);
                            break;
                        default:
                            break;
                    }
                    if (tempCtrl.Width < MinWidth) tempCtrl.Width = MinWidth;
                    if (tempCtrl.Height < MinHeight) tempCtrl.Height = MinHeight;
    
                }
                else
                {
                    SetCursorStyle(e, tempCtrl);
                }
            }

    接下来,我们在处理一下鼠标按下及鼠标离开事件,

    1) 鼠标按下,记录当前坐标

    2) 鼠标离开,还原光标状态

    /// <summary>
            /// 处理鼠标按下事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void ctrl_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
            {
                if (e.Button == System.Windows.Forms.MouseButtons.Left)
                {
                    p.X = e.X;
                    p.Y = e.Y;
                    p1.X = e.X;
                    p1.Y = e.Y;
                }
            }
            /// <summary>
            /// 处理鼠标离开
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void ctrl_MouseLeave(object sender, EventArgs e)
            {
                _currentMousePointPosition = EMousePointPosition.None;
                this.Cursor = Cursors.Arrow;
            }

    ok, 截止到这里,这个控件基本上就已完成了,已实现在界面中实时拖拽,改变大小功能.

    此功能简略的讲解到这里,我想若有类似需求的朋友已经能知道后面的路怎么走了.剩下无非就是在一个设计器界面中引入这个控件,然后根据用户拖动的位置将坐标记录下来,在打印的时候,将数据源这个格式一起绑定后交给打印控制处理器负责打印即可.

  • 相关阅读:
    UOJ.26.[IOI2014]Game(交互 思路)
    Good Bye 2016 F.New Year and Finding Roots(交互)
    Codeforces.835E.The penguin's game(交互 按位统计 二分)
    Codeforces.744B.Hongcow's Game(交互 按位统计)
    Codeforces.862D.Mahmoud and Ehab and the binary string(交互 二分)
    正睿OI 提高 Day1T3 ZYB玩字符串(DP)
    划分vlan
    2三层交换机实现vlan间的路由
    交换机基础-交换机远程telnet
    自动化运维环境的搭建问题处理
  • 原文地址:https://www.cnblogs.com/xie-zhonglai/p/3844264.html
Copyright © 2011-2022 走看看