开发者论坛

 找回密码
 注册 (请使用非IE浏览器)
查看: 5293|回复: 4

[教程] 窗体控件打印类

[复制链接]

0

精华

105

贡献

62

赞扬

帖子
104
软币
876
在线时间
101 小时
注册时间
2013-8-21
发表于 2014-8-8 15:25:02 | 显示全部楼层 |阅读模式
[C#] 纯文本查看 复制代码
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Drawing.Printing;
using System.Windows.Forms;
using System.Drawing;
using System.Collections;

namespace PrintControl
{
    public partial class ControlPrint : PrintDocument
    {
        private Control m_ctrl;

        private bool stretch;

        /// <summary>
        /// Set true to stretch the control to fill a single printed page
        /// </summary>
        public bool StretchControl
        {
            set { stretch = value; }
            get { return stretch; }
        }

        private int width;
        private int height;
        /// <summary>
        /// The width of the control to print. You can change this value if the automatically 
        /// calculated width does not fit all the elements of the control
        /// </summary>
        public int PrintWidth
        {
            set { width = value; }
            get { return width; }
        }
        /// <summary>
        /// The height of the control to print. You can change this value if the automatically
        /// calculated height does not fit all the elements of the control
        /// </summary>
        public int PrintHeight
        {
            set { height = value; }
            get { return height; }
        }

        private int inbetween;
        /// <summary>
        /// The area to be reprinted between pages if there are more than one
        /// pages to be printed, to prevent data loss
        /// </summary>
        public int RepeatArea
        {
            get { return inbetween; }
            set { inbetween = value; }
        }
        
        /// <summary>
        /// Default constructor
        /// </summary>
        public ControlPrint()
        {
            InitializeComponent();
            m_ctrl = new Control();
            stretch = false;
            width = m_ctrl.Width;
            height = m_ctrl.Height;
            inbetween = 10;
        }

        /// <summary>
        /// Intialize the component with the selected control
        /// </summary>
        /// <param name="print">The control to printed</param>
        public ControlPrint(Control print)
        {
            InitializeComponent();
            SetControl(print);
            stretch = false;
            inbetween = 10;
        }

        /// <summary>
        /// Initialize the component with the selected control specifying
        /// whether to stretch or not
        /// </summary>
        /// <param name="print">The control to be printed</param>
        /// <param name="Stretch">Set true to stretch the control to fill a single printed page</param>
        public ControlPrint(Control print, bool Str)
        {
            InitializeComponent();
            SetControl(print);
            stretch = Str;
            inbetween = 10;
        }

        /// <summary>
        /// Initialize the component with the selected control specifying
        /// specific width and height
        /// </summary>
        /// <param name="print">The control to be printed</param>
        /// <param name="Width">Printed width</param>
        /// <param name="Height">Printed height</param>
        public ControlPrint(Control print, int Width, int Height)
        {
            InitializeComponent();
            SetControl(print);
            stretch = false;
            width = Width;
            height = Height;
            inbetween = 10;
        }

        /// <summary>
        /// Intialize the component with a specific container, Insignificant
        /// </summary>
        /// <param name="container"></param>
        private ControlPrint(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
            m_ctrl = new Control();
            stretch = false;
            inbetween = 10;
        }

        /// <summary>
        /// Set the control to be printed
        /// </summary>
        /// <param name="print">The control you wish to print</param>
        public void SetControl(Control print)
        {
            m_ctrl = print;
            Size NewSize = m_ctrl.GetPreferredSize(Size.Empty);
            width = NewSize.Width;
            height = NewSize.Height;
            printedheight = 0;
        }

        /// <summary>
        /// Set the control with a specified height & width
        /// </summary>
        /// <param name="print">The control to be printed</param>
        /// <param name="Width">Control's width</param>
        /// <param name="Height">Control's height</param>
        public void SetControl(Control print, int Width, int Height)
        {
            m_ctrl = print;
            width = Width;
            height = Height;
            printedheight = 0;
        }

        private int printedheight;
        private void ControlPrint_PrintPage(object sender, PrintPageEventArgs e)
        {
            //We get the old status of the control
            Size NewSize = new Size(width, height);
            DockStyle OldDock = m_ctrl.Dock;
            Size OldSize = new Size(m_ctrl.Width, m_ctrl.Height);
            Control parent = m_ctrl;
            List<Control> Parents = new List<Control>();
            List<Size> OldSizes = new List<Size>();
            
            //enumerate the parents
            while (parent.Parent != null)
            {
                Parents.Add(parent.Parent);
                OldSizes.Add(parent.Parent.Size);
                parent = parent.Parent;
            }
            //Change the size of the control to fullt display it and get rid of scrollbars
            m_ctrl.Dock = DockStyle.None;
            m_ctrl.Size = NewSize;
            //Make sure that the size changes otherwise resize the parents
            while (m_ctrl.Size == OldSize)
            {
                foreach (Control c in Parents)
                {
                    c.Size = new Size(c.Width + 100, c.Height + 100);
                }
                m_ctrl.Size = NewSize;
            }
            //print dimentions will be according to page size and margins
            int printwidth = width;
            int printheight = height;

            //change the width to fit the paper, and change the height to maintain the ratio
            if (printwidth > e.MarginBounds.Width)
            {
                printheight = (int)(((float)e.MarginBounds.Width / (float)printwidth) * printheight);
                printwidth = e.MarginBounds.Width;
            }

            //if too long, we will need more papers
            if (printheight - printedheight > e.MarginBounds.Height && !stretch)
                e.HasMorePages = true;
            else
                e.HasMorePages = false;
            

            GraphicsUnit gp = GraphicsUnit.Point;
            Bitmap b = new Bitmap(width, height);
            //Good, now we can draw
            m_ctrl.DrawToBitmap(b, new Rectangle(0, 0, width, height));
            //Will we stretch the image?
            if (stretch)
            {
                e.Graphics.DrawImage(b, e.MarginBounds, b.GetBounds(ref gp), gp);
                e.HasMorePages = false;
            }
            else
            {
                //If not stretched then make sure to print the area of the current page only
                float ScaleF = (float)height / (float)printheight;
                printheight -= printedheight;
                if (printheight > e.MarginBounds.Height)
                    printheight = e.MarginBounds.Height;
                Rectangle rect = new Rectangle(0, (int)(printedheight * ScaleF), b.Width, (int)(printheight * ScaleF));
                Bitmap b2 = b.Clone(rect, System.Drawing.Imaging.PixelFormat.DontCare);
                e.Graphics.DrawImage(b2, new Rectangle((e.PageBounds.Width/2) - (printwidth/2), e.MarginBounds.Top, printwidth, printheight));
            }
            if (e.HasMorePages)
            {
                //Change the printed height, and don't forget the RepeatArea
                printedheight += e.MarginBounds.Height - inbetween;
            }
            else
                printedheight = 0;
            //Restore the control's state
            for (int i = 0; i < Parents.Count; i++)
            {
                Parents.Size = OldSizes;
            m_ctrl.Size = new Size(OldSize.Width, OldSize.Height);
            m_ctrl.Dock = OldDock;
         }

        /// <summary>
        /// Draw the control fully to a bitmap & return it
        /// </summary>
        /// <returns></returns>
        public Bitmap GetBitmap()
        {
            //Get old states
            Size NewSize = new Size(width, height);
            DockStyle OldDock = m_ctrl.Dock;
            Size OldSize = new Size(m_ctrl.Width, m_ctrl.Height);
            Control parent = m_ctrl;
            List<Control> Parents = new List<Control>();
            List<Size> OldSizes = new List<Size>();
            while (parent.Parent != null)
            {
                Parents.Add(parent.Parent);
                OldSizes.Add(parent.Parent.Size);
                parent = parent.Parent;
            }
            m_ctrl.Dock = DockStyle.None;
            m_ctrl.Size = NewSize;
            while (m_ctrl.Size == OldSize)
            {
                foreach (Control c in Parents)
                {
                    c.Size = new Size(c.Width + 100, c.Height + 100);
                }
                m_ctrl.Size = NewSize;
            }
            Bitmap b = new Bitmap(width, height);
            //Draw
            m_ctrl.DrawToBitmap(b, new Rectangle(0, 0, width, height));
            //Restore states
            for (int i = 0; i < Parents.Count; i++)
                Parents.Size = OldSizes;
            m_ctrl.Size = new Size(OldSize.Width, OldSize.Height);
            m_ctrl.Dock = OldDock;
            return b;
        }

        private List<TreeNode> Nodes; // All enumerated nodes are here
        private void EnumNodes(TreeNode TN)
        {
            if (!Nodes.Contains(TN) && (TN.Parent == null || (TN.Parent != null && TN.Parent.IsExpanded)))
                Nodes.Add(TN);
            //Enum all subnodes of the current node
            foreach (TreeNode R in TN.Nodes)
                EnumNodes(R);
        }
        
        /// <summary>
        /// Return the best size that fits the control
        /// </summary>
        /// <returns></returns>
        public Size CalculateSize()
        {
            //Identify the control's type
            if (m_ctrl.GetType().AssemblyQualifiedName.IndexOf("TreeView") >= 0)
            {
                if (((TreeView)m_ctrl).Nodes.Count == 0)
                {
                    //if no elemts return 1X1 to avoid exceptions
                    return new Size(1, 1);
                }
                else
                {
                    int TempW = 0, TempH = 0;
                    Nodes = new List<TreeNode>();
                    foreach (TreeNode T in ((TreeView)m_ctrl).Nodes)
                        EnumNodes(T);
                    foreach (TreeNode N in Nodes)
                    {
                        if (TempW < N.Bounds.Right)
                            TempW = N.Bounds.Right;
                    }
                    TempH = Nodes.Count * ((TreeView)m_ctrl).ItemHeight;
                    return new Size(TempW + 30, TempH + 30);
                }
            }
            else if (m_ctrl.GetType().AssemblyQualifiedName.IndexOf("ListView") >= 0)
            {
                if (((ListView)m_ctrl).Items.Count > 0)
                {
                    //This will work if the listview is in details mode
                    ((ListView)m_ctrl).Items[0].EnsureVisible();
                    int tempwidth = ((ListView)m_ctrl).Items[0].Bounds.Width;
                    int tempheight = ((ListView)m_ctrl).Items[((ListView)m_ctrl).Items.Count - 1].Bounds.Bottom;
                    //This is for other modes
                    foreach (ListViewItem i in ((ListView)m_ctrl).Items)
                    {
                        if (tempwidth < i.Bounds.Right)
                            tempwidth = i.Bounds.Right;
                        if (tempheight < i.Bounds.Bottom)
                            tempheight = i.Bounds.Bottom;
                    }
                    return new Size(tempwidth + 30, tempheight + 30);
                }
                else
                    return new Size(1, 1);
            }
            else if (m_ctrl.Controls.Count > 0)
            {
                //Just in case the form didn't calculate its PreferredSize properly
                int tempwidth = 1;
                int tempheight = 1;
                foreach (Control c in m_ctrl.Controls)
                {
                    if (c.Bounds.Right > tempwidth)
                        tempwidth = c.Bounds.Right;
                    if (c.Bounds.Bottom > tempheight)
                        tempheight = c.Bounds.Bottom;
                }
                return new Size(tempwidth, tempheight);
            }
            else
                return new Size(m_ctrl.PreferredSize.Width, m_ctrl.PreferredSize.Height);
            return Size.Empty;
        }

        /// <summary>
        /// Apply the best size that fits the control
        /// </summary>
        public void ApplyBestSize()
        {
            Size temp = CalculateSize();
            width = temp.Width;
            height = temp.Height;
        }
    }
}

ControlPrint.zip

118.28 KB, 下载次数: 129

例子源码

评分

参与人数 1贡献 +3 赞扬 +1 收起 理由
羽叶 + 3 + 1 感谢分享

查看全部评分

回复

使用道具 举报

0

精华

5295

贡献

6059

赞扬

管理员

帖子
1176
软币
22629
在线时间
4467 小时
注册时间
2013-6-7

黄马甲

发表于 2014-8-8 16:01:20 | 显示全部楼层
谢谢分享
另外论坛有插入C#代码并高亮的功能 这次帮你编辑了
回复

使用道具 举报

0

精华

14

贡献

4

赞扬

帖子
110
软币
451
在线时间
43 小时
注册时间
2014-4-9
发表于 2015-1-4 14:21:30 | 显示全部楼层
不错的东西啊
回复

使用道具 举报

0

精华

2

贡献

1

赞扬

帖子
65
软币
276
在线时间
18 小时
注册时间
2014-10-16
发表于 2015-5-29 15:51:26 | 显示全部楼层
晚上回去慢慢看。。累。
回复

使用道具 举报

Archiver|手机版|小黑屋|开发者网 ( 苏ICP备08004430号-2 )
版权所有:南京韵文教育信息咨询有限公司

GMT+8, 2024-12-23 12:03

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表