【向zgke提问】打印panel控件问题

chaozi_249 2009-12-21 09:05:55
一个大panel容器里,放入了几个panel(我们就称它们为小panel),以及text文本框,和label,用了网上找的截图打印,可以打印,但就是在出现滚动条的时候,打印不完整。
截图打印代码

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace panelPrint
{
public class PrintCom
{
private static Bitmap mBitmap = null;
private static System.Drawing.Printing.PrintDocument printDoc = new System.Drawing.Printing.PrintDocument();

public static void PrintPanel (Panel p)
{
PrintPreviewDialog ppvw;
Graphics mygraphics = p.CreateGraphics();
Size s = p.Size;
mBitmap = new Bitmap(s.Width, s.Height, mygraphics);
Graphics memoryGraphics = Graphics.FromImage(mBitmap);
IntPtr dc1 = mygraphics.GetHdc();
IntPtr dc2 = memoryGraphics.GetHdc();
BitBlt (dc2,0,0,p.ClientRectangle.Width,p.ClientRectangle.Height,dc1,0,0,13369376);
mygraphics.ReleaseHdc(dc1);
memoryGraphics.ReleaseHdc(dc2);

ppvw = new PrintPreviewDialog();
ppvw.Width = 800;
ppvw.Height = 600;
ppvw.Document = printDoc;
printDoc.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(PrintDoc_PrintPage);
if (ppvw.ShowDialog() != DialogResult.OK)
{
printDoc.PrintPage -= new System.Drawing.Printing.PrintPageEventHandler(PrintDoc_PrintPage);
return;
}
printDoc.Print();
}

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern long BitBlt(IntPtr HDest, int nXDest, int nYDest, int nWidth, int hHeight, IntPtr HSrc, int nXSrc, int nYSrc, int DwRop);

private static void PrintDoc_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(mBitmap, 0, 0);
}
}
}


用了zgke前辈博客里写的,出现上面问题解决方法。能解决出现滚动条的情况,但是因为几个小panel里是自定义控件,所以现在出现的问题是panel里自己画的图没有打印出来。
http://blog.csdn.net/zgke/archive/2008/12/18/3551584.aspx
请高手指点
...全文
1060 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
dafei198607 2010-10-23
  • 打赏
  • 举报
回复
强人,膜拜一下
meng_jian 2010-08-24
  • 打赏
  • 举报
回复
学习中。。。。
阳光的味道 2010-08-02
  • 打赏
  • 举报
回复
e.Graphics.DrawImage(bitMap, 0, 0); //绘制一幅图片
为空的时候是什么问题
阳光的味道 2010-08-02
  • 打赏
  • 举报
回复
Beauitful
hhc123 2009-12-21
  • 打赏
  • 举报
回复
mark
风之影子 2009-12-21
  • 打赏
  • 举报
回复
关注
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 chaozi_249 的回复:]
我的下面方法写在Paint事件下面。
C# code#region 绘制图形方法privatevoid intoChart(Panel pelOne,int tempTopValue,int YtempValues,string ChartTitle, DataTable dt)
{
top= tempTopValue;#region 绘制框架图
Graphics tempLine= pelOne.CreateGraphics();
tempLine.DrawLine(BorderPen, left, top*2, left, pelOne.Height- top);
tempLine.DrawLine(BorderPen, left, pelOne.Height- top, pelOne.Width- left, pelOne.Height- top);#endregion#region 绘制图形标题
SizeF ChartTitleStr= tempLine.MeasureString(ChartTitle,new Font("楷体",8.5F));float ChartTitleStrWidth= (float)Math.Ceiling(ChartTitleStr.Width);//获取Y轴字符串的宽度 tempLine.DrawString(ChartTitle,new Font("楷体",8.5F),new SolidBrush(Color.Black), pelOne.Width/2- ChartTitleStrWidth/2,5);#endregion#region 绘制Y轴刻度及文本float tempJianGeY= (pelOne.Height- top*3)/ 10F;//Y轴刻度间隔值float tempKeDuY= YtempValues/ (pelOne.Height- top*3);//单像素代表数字值for (int count=0; count<11; count++)
{
tempLine.DrawLine(BorderPen, left, pelOne.Height- top- tempJianGeY* count, left+5, pelOne.Height- top- tempJianGeY* count);
}for (int count=0; count<11; count++)
{
SizeF YAxisStr= tempLine.MeasureString(Convert.ToString(YtempValues/10* count),new Font("楷体",7));int YAxisNameHeight= (int)Math.Ceiling(YAxisStr.Height);//获取Y轴字符串的高度int YAxisNameWidth= (int)Math.Ceiling(YAxisStr.Width);//获取Y轴字符串的宽度 tempLine.DrawString(Convert.ToString(YtempValues/10* count),new Font("楷体",7),new SolidBrush(Color.Black), left- YAxisNameWidth, pelOne.Height- top- tempJianGeY* count- YAxisNameHeight/2);
}#endregion#region 绘制X轴刻度及文本float tempJianGeX= (pelOne.Width- left*2)/ dt.Rows.Count;//X轴刻度间隔值for (int count=0; count< dt.Rows.Count+1; count++)
{
tempLine.DrawLine(BorderPen, left+ tempJianGeX* count, pelOne.Height- top, left+ tempJianGeX* count, pelOne.Height- top-5);
}for (int count=0; count< dt.Rows.Count; count++)
{
SizeF XAxisStr= tempLine.MeasureString(dt.Rows[count][0].ToString(),new Font("楷体",7));int XAxisNameWidth= (int)Math.Ceiling(XAxisStr.Width);//获取X轴字符串的宽度 tempLine.DrawString(dt.Rows[count][0].ToString(),new Font("楷体",7),new SolidBrush(Color.Black), left+ tempJianGeX* (count+1)- XAxisNameWidth/2, pelOne.Height- top+3);
}#endregion#region 绘制曲线for (int countOne=0; countOne< dt.Columns.Count-1; countOne++)
{if (countOne==1)
{for (int count=0; count< dt.Rows.Count-1; count++)
{
tempLine.DrawLine(LinePenOne, left+ tempJianGeX* (count+1), pelOne.Height- top-float.Parse(dt.Rows[count][countOne].ToString())/ tempKeDuY, left+ tempJianGeX* (count+2), pelOne.Height- top-float.Parse(dt.Rows[count+1][countOne].ToString())/ tempKeDuY);
}
}elseif (countOne==2)
{for (int count=0; count< dt.Rows.Count-1; count++)
{
tempLine.DrawLine(LinePenTwo, left+ tempJianGeX* (count+1), pelOne.Height- top-float.Parse(dt.Rows[count][countOne].ToString())/ tempKeDuY, left+ tempJianGeX* (count+2), pelOne.Height- top-float.Parse(dt.Rows[count+1][countOne].ToString())/ tempKeDuY);
}
}elseif (countOne==3)
{for (int count=0; count< dt.Rows.Count-1; count++)
{
tempLine.DrawLine(LinePenThree, left+ tempJianGeX* (count+1), pelOne.Height- top-float.Parse(dt.Rows[count][countOne].ToString())/ tempKeDuY, left+ tempJianGeX* (count+2), pelOne.Height- top-float.Parse(dt.Rows[count+1][countOne].ToString())/ tempKeDuY);
}
}elseif (countOne==4)
{for (int count=0; count< dt.Rows.Count-1; count++)
{
tempLine.DrawLine(LinePenFour, left+ tempJianGeX* (count+1), pelOne.Height- top-float.Parse(dt.Rows[count][countOne].ToString())/ tempKeDuY, left+ tempJianGeX* (count+2), pelOne.Height- top-float.Parse(dt.Rows[count+1][countOne].ToString())/ tempKeDuY);
}
}elseif (countOne==5)
{for (int count=0; count< dt.Rows.Count-1; count++)
{
tempLine.DrawLine(LinePenFive, left+ tempJianGeX* (count+1), pelOne.Height- top-float.Parse(dt.Rows[count][countOne].ToString())/ tempKeDuY, left+ tempJianGeX* (count+2), pelOne.Height- top-float.Parse(dt.Rows[count+1][countOne].ToString())/ tempKeDuY);
}
}
}#endregion
}#endregion
[/Quote]
正解
chaozi_249 2009-12-21
  • 打赏
  • 举报
回复
以下是我参考zgke前辈的代码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.ComponentModel;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Text;

namespace jamonitor
{
class PrintPanel
{
#region API
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SCROLLINFO
{
public uint cbSize;
public uint fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
public enum ScrollBarInfoFlags
{
SIF_RANGE = 0x0001,
SIF_PAGE = 0x0002,
SIF_POS = 0x0004,
SIF_DISABLENOSCROLL = 0x0008,
SIF_TRACKPOS = 0x0010,
SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS)
}
public enum ScrollBarRequests
{
SB_LINEUP = 0,
SB_LINELEFT = 0,
SB_LINEDOWN = 1,
SB_LINERIGHT = 1,
SB_PAGEUP = 2,
SB_PAGELEFT = 2,
SB_PAGEDOWN = 3,
SB_PAGERIGHT = 3,
SB_THUMBPOSITION = 4,
SB_THUMBTRACK = 5,
SB_TOP = 6,
SB_LEFT = 6,
SB_BOTTOM = 7,
SB_RIGHT = 7,
SB_ENDSCROLL = 8
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetScrollInfo(IntPtr hwnd, int bar, ref SCROLLINFO si);
[DllImport("user32")]
public static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool Rush);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
#endregion
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern long BitBlt(IntPtr HDest, int nXDest, int nYDest, int nWidth, int hHeight, IntPtr HSrc, int nXSrc, int nYSrc, int DwRop);

private static Bitmap bitMap = null; //实例化一个位图
private static System.Drawing.Printing.PrintDocument printDoc = new System.Drawing.Printing.PrintDocument(); //实例化一个打印的对象
public static void GetPanel(Panel p)
{
MoveBar(0, 0, p); //下面的方法
MoveBar(1, 0, p); //下面的方法
Point pit = GetScrollPoint(p); //下面的方法
p.Width += pit.X + 5; //滚动条的宽
p.Height += pit.Y + 5; //滚动条的高
bitMap = new Bitmap(p.Width, p.Height); //根据画布的宽和高赋值给位图
p.DrawToBitmap(bitMap, new Rectangle(0, 0, bitMap.Width, bitMap.Height));
PrintPreviewDialog ppvw = new PrintPreviewDialog(); //初始化一个打印预览
ppvw.Width = 800; //设置预览的宽
ppvw.Height = 600; //设置预览的高
ppvw.Document = printDoc; // 预览的文档赋值发送给打印机
printDoc.DefaultPageSettings.Landscape = false; //是否为纵向打印
printDoc.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(PrintDoc_PrintPage); //打印之前发生的事
PaperSize pp = null; //定义纸张大小为空
foreach (PaperSize ps in ppvw.Document.PrinterSettings.PaperSizes) //获取该打印机支持的纸张大小
{
if (ps.PaperName.Equals("A3")) //这里设置纸张大小,但必须是定义好的
pp = ps;
}
ppvw.Document.DefaultPageSettings.PaperSize = pp; //设置纸张的大小为A3
if (ppvw.ShowDialog() != DialogResult.OK) //如果不打印的话,返回
{
printDoc.PrintPage -= new System.Drawing.Printing.PrintPageEventHandler(PrintDoc_PrintPage);
return;
}
printDoc.Print(); //开始打印
}

/// <summary>
/// 打印
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void PrintDoc_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(bitMap, 0, 0); //绘制一幅图片
}

/// <summary>
/// 获取滚动条数据
/// </summary>
/// <param name="MyControl"></param>
/// <param name="ScrollSize"></param>
/// <returns></returns>
private static Point GetScrollPoint(Control MyControl)
{
Point MaxScroll = new Point();

SCROLLINFO ScrollInfo = new SCROLLINFO();
ScrollInfo.cbSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(ScrollInfo);
ScrollInfo.fMask = (uint)ScrollBarInfoFlags.SIF_ALL;

GetScrollInfo(MyControl.Handle, 1, ref ScrollInfo);
MaxScroll.Y = ScrollInfo.nMax - (int)ScrollInfo.nPage;
if ((int)ScrollInfo.nPage == 0) MaxScroll.Y = 0;
GetScrollInfo(MyControl.Handle, 0, ref ScrollInfo);
MaxScroll.X = ScrollInfo.nMax - (int)ScrollInfo.nPage;
if ((int)ScrollInfo.nPage == 0) MaxScroll.X = 0;
return MaxScroll;
}
/// <summary>
/// 移动控件滚动条位置
/// </summary>
/// <param name="Bar"></param>
/// <param name="Point"></param>
/// <param name="MyControl"></param>
private static void MoveBar(int Bar, int Point, Control MyControl)
{
if (Bar == 0)
{
SetScrollPos(MyControl.Handle, 0, Point, true);
SendMessage(MyControl.Handle, (int)0x0114, (int)ScrollBarRequests.SB_THUMBPOSITION, 0);
}
else
{
SetScrollPos(MyControl.Handle, 1, Point, true);
SendMessage(MyControl.Handle, (int)0x0115, (int)ScrollBarRequests.SB_THUMBPOSITION, 0);
}
}
}
}

chaozi_249 2009-12-21
  • 打赏
  • 举报
回复
dqw120,你好
我前面用的就是你说的截图,但是当panel大过屏幕的时候,会出现滚动条,所以截的图不是完整的。
所以我才用zgke前辈写的方法。
dqw120 2009-12-21
  • 打赏
  • 举报
回复
首先要了解一下在C#中如何调用API(应用程序接口)函数。虽然在.Net框架中已经提供了许多类库,这些类库的功能也十分强大,但对于一些Windows底层编程来说,还是要通过调用这些API函数才可以实现。所有API都在"Kernel"、"User "和"GDI"三个库中得以运行:其中"Kernel",他的库名为 "KERNEL32.DLL", 他主要用于产生与操作系统之间的关联,譬如:程序加载,上下文选择,文件输入输出,内存管理等等。"User "这个类库在Win32中名叫 "USER32.DLL"。 它允许管理全部的用户接口。譬如:窗口 、菜单 、对话框 、图标等等。"GDI"(图象设备接口),它在Win32中的库名为:"GDI32.dll",它是图形输出库。使用GDI Windows"画"出窗口、菜单以及对话框等;它能创建图形输出;它也能保存图形文件。由于本文所涉及到是图象问题,所有调用的类库是"GDI32.dll"。在本文程序中我们使用的API函数是"BitBlt",这个函数对于广大程序员来说,一定不感觉到陌生,因为在图象处理方面他的用途是相对广的,在用其他程序语言编程中,时常也要和他打交道。在.Net FrameWork SDK中有一个名字空间"System.Runtime.InteropServices",此名字空间提供了一系列的类来访问COM对象,和调用本地的API函数。下面是在C#中声明此函数:

[ System.Runtime.InteropServices.DllImportAttribute ( "gdi32.dll" ) ]
private static extern bool BitBlt (
IntPtr hdcDest , // 目标 DC的句柄
int nXDest ,
int nYDest ,
int nWidth ,
int nHeight ,
IntPtr hdcSrc , // 源DC的句柄
int nXSrc ,
int nYSrc ,
System.Int32 dwRop // 光栅的处理数值
) ;



通过上面这个声明,就可以在下面的代码中使用此函数了。

下面是用C#做屏幕捕获程序的具体实现步骤:

(1).首先要获得当前屏幕的graphic对象,通过以下代码可以实现:

Graphics g1 = this.CreateGraphics ( ) ;


(2).创建一个Bitmap对象,并且这个Bitmap对象的大小是当前屏幕:

首先要获得当前屏幕的大小,通过名字空间"System.Windows.Forms"中的"Screen"类的GetWorkingArea()方法,可以实现。下面是得到当前屏幕的长(Height)和宽(Width):

Rectangle rect = new Rectangle ( ) ;
rect = Screen.GetWorkingArea ( this ) ;
"屏幕宽"= rect.Width ;
"屏幕长"= rect.Height ;



至此就可以得到我们想要的Bitmap了,通过下列语句可以实现:

Image MyImage = new Bitmap ( rect.Width , rect.Height , g1 ) ;
//创建以屏幕大小为标准的位图


(3).获得当前屏幕和此Bitmap对象的DC,这可以通过下列语句实现:

//得到屏幕的DC
IntPtr dc1 = g1.GetHdc ( ) ;
//得到Bitmap的DC
IntPtr dc2 = g2.GetHdc ( ) ;



(4).调用API函数,把当前屏幕拷贝到创建的Bitmap中:

BitBlt ( dc2 , 0 , 0 , rect.Width , rect.Height , dc1 , 0 , 0 , 13369376 ) ;


(5).释放当前屏幕和此Bitmap对象的DC,通过下面代码可以实现:

//释放掉屏幕的DC
g1.ReleaseHdc ( dc1 ) ;
//释放掉Bitmap的DC
g2.ReleaseHdc ( dc2 ) ;



(6).保存Bitmap对象,形成jpg图片:

MyImage.Save ( @"c:\Capture.jpg" , ImageFormat.Jpeg );


当然你也可以根据自己的需要,把屏幕以其他图片的格式来保存,如果你想把图片保存为位图文件,可以把"ImageFormat.Jpeg"改换成"ImageFormat.Bmp";想把图片保存为Gif文件,就把"ImageFormat.Jpeg"改换成"ImageFormat.Gif"。你可以保存的文件类型大概有十多种,这里就不一一介绍了,当然你也要相应改变保存文件的后缀。

用C#来捕获屏幕的源程序代码(Capture.cs):

了解上面的这些步骤的实现方法,就可以得到用C#捕获屏幕的源程序,如下:

using System ;
using System.Drawing ;
using System.Collections ;
using System.ComponentModel ;
using System.Windows.Forms ;
using System.Data ;
using System.Drawing.Imaging ;
public class Form1 : Form
{
private Button button1 ;
private System.ComponentModel.Container components = null ;

public Form1 ( )
{
//初始化窗体中的各个组件
InitializeComponent ( ) ;
}
// 清除程序中使用过的资源
protected override void Dispose ( bool disposing )
{
if ( disposing )
{
if ( components != null )
{
components.Dispose ( ) ;
}
}
base.Dispose ( disposing ) ;
}
private void InitializeComponent ( )
{
button1 = new Button ( );
SuspendLayout ( ) ;
button1.Location = new System.Drawing.Point ( 64 , 40 ) ;
button1.Name = "button1" ;
button1.Size = new System.Drawing.Size ( 80 , 32 ) ;
button1.TabIndex = 0 ;
button1.Text = "捕获" ;
button1.Click += new System.EventHandler ( button1_Click ) ;

AutoScaleBaseSize = new System.Drawing.Size ( 6 , 14 ) ;
ClientSize = new System.Drawing.Size ( 216 , 125 ) ;
Controls.Add ( button1 ) ;
MaximizeBox = false ;
MinimizeBox = false ;
Name = "Form1" ;
Text = "C#捕获当前屏幕!" ;
ResumeLayout ( false ) ;

}
//声明一个API函数
[ System.Runtime.InteropServices.DllImportAttribute ( "gdi32.dll" ) ]
private static extern bool BitBlt (
IntPtr hdcDest , // 目标 DC的句柄
int nXDest ,
int nYDest ,
int nWidth ,
int nHeight ,
IntPtr hdcSrc , // 源DC的句柄
int nXSrc ,
int nYSrc ,
System.Int32 dwRop // 光栅的处理数值
) ;

static void Main ( )
{
Application.Run ( new Form1 ( ) ) ;
}
private void button1_Click ( object sender , System.EventArgs e )
{
//获得当前屏幕的大小
Rectangle rect = new Rectangle ( ) ;
rect = Screen.GetWorkingArea ( this ) ;
//创建一个以当前屏幕为模板的图象
Graphics g1 = this.CreateGraphics ( ) ;
//创建以屏幕大小为标准的位图
Image MyImage = new Bitmap ( rect.Width , rect.Height , g1 ) ;
Graphics g2 = Graphics.FromImage ( MyImage ) ;
//得到屏幕的DC
IntPtr dc1 = g1.GetHdc ( ) ;
//得到Bitmap的DC
IntPtr dc2 = g2.GetHdc ( ) ;
//调用此API函数,实现屏幕捕获
BitBlt ( dc2 , 0 , 0 , rect.Width , rect.Height , dc1 , 0 , 0 , 13369376 ) ;
//释放掉屏幕的DC
g1.ReleaseHdc ( dc1 ) ;
//释放掉Bitmap的DC
g2.ReleaseHdc ( dc2 ) ;
//以JPG文件格式来保存
MyImage.Save ( @"c:\Capture.jpg" , ImageFormat.Jpeg );
MessageBox.Show ( "当前屏幕已经保存为C盘的capture.jpg文件!" ) ;
}
}
dqw120 2009-12-21
  • 打赏
  • 举报
回复
你可以先设定一个模块,然后读取出listbox的值,输出,然后打开模块。
chaozi_249 2009-12-21
  • 打赏
  • 举报
回复
我也是这么想的,先感谢你抽出宝贵的时间帮我忙,我先试试。
zgke 2009-12-21
  • 打赏
  • 举报
回复
Panel.BackgroundImage
chaozi_249 2009-12-21
  • 打赏
  • 举报
回复
有没有这方面的参考资料
我对这个不是很了解
chaozi_249 2009-12-21
  • 打赏
  • 举报
回复
绘制到BITMAP
那如何用panel来显示呢?
chaozi_249 2009-12-21
  • 打赏
  • 举报
回复
打印预览的时候就没有画出来,还没有提交给打印机呢,所有你说的打印机问题可以排除了。
zgke 2009-12-21
  • 打赏
  • 举报
回复
不要直接绘制到Panel上..一刷新就没了 你考虑绘制到BITMAP 用PANEL来显示他
michaelnami 2009-12-21
  • 打赏
  • 举报
回复
有没有可能是打印机的问题
chaozi_249 2009-12-21
  • 打赏
  • 举报
回复
图形就是矩形框,刻度和点点连线,简单图形
关键是取得的位图与画图执行顺序或者机制有冲突

我是这样认为的
对Api不是很了解
chaozi_249 2009-12-21
  • 打赏
  • 举报
回复
打印预览的时候,其他的都出来了,就是画的图没有出来
加载更多回复(6)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧