• 分享一个自定义打印套打方案


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

    原始需求:

    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, 截止到这里,这个控件基本上就已完成了,已实现在界面中实时拖拽,改变大小功能.

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

  • 相关阅读:
    vim 命令详解
    vim基础命令
    JSP取得绝对路径
    sigar开发(java)
    HDU-5273
    HDU-1671
    HDU-1251
    POJ-1743
    POJ-2774
    hihocoder 1145 : 幻想乡的日常
  • 原文地址:https://www.cnblogs.com/xie-zhonglai/p/3844264.html
Copyright © 2020-2023  润新知