相关文章推荐
体贴的葡萄  ·  python ...·  5 月前    · 
纯真的熊猫  ·  什么时候 MySQL ...·  1 年前    · 

一、设置方法概述:
通过在系统的打印机中,创建3种尺寸纸张大小的打印模版,然后在打印的时候,选择对应尺寸的打印模版进行打印即可。

二、不同纸张尺寸大小说明:
A4:21.0cm*29.7cm
针式打印纸1等分:24.1cm*28.0cm;

针式打印纸2等分:24.1cm*14.0cm;

针式打印纸3等分:24.1cm*9.3cm。


三、操作步骤:
(一)设置打印尺寸模版
如果你使用的电脑是Windows 7系统:
1.点击开始-设备和打印机,进入对应页面;
2.随便选中一个打印机,上方会显示“打印服务器属性”,点击“打印服务器属性”;
3.进入打印服务器属性页面,勾选创建新纸张规格,填写纸张规格名称和纸张大小,例如填写名称“3等分“,宽度24.1cm,高度9.3cm。最后点击确定按钮。



如果你使用的电脑是Windows 10系统:
1.点击开始-设置-设备-打印机和扫描仪,下拉到底部,点击打印服务器属性;
2.同Windows 7系统中的步骤3



(二)打印时选择正确尺寸模版
1.在使用浏览器的打印功能时,都可以选择事先创建的纸张尺寸。例如下图展示了有赞中采购订单打印页面,点击打印后,可以在纸张尺寸中选择“3等分”这个尺寸。
2.如果打印页面没有纸张尺寸的选项,可以点击下方的更多设置按钮。
3.每个不同的浏览器都会默认记住上一次选择的纸张尺寸,只需要选择1次即可。如果更换浏览器,请重新选择纸张尺寸。

page-break-after 属性用于设置在指定元素后面插入分页符。

注意: 您不能对绝对定位的元素使用此属性。

注意: 请尽可能少地使用分页属性,并且避免在表格、浮动元素、带有边框的块元素中使用分页属性。

JavaScript 语法: object .style.pageBreakAfter="always"

于 2021-05-18 09:48:59 发布

2827
收藏 3
分类专栏: 前端 js 文章标签: javascript
版权

前端
同时被 2 个专栏收录
12 篇文章0 订阅
订阅专栏

js
45 篇文章0 订阅
订阅专栏
前言:
做项目的时候可能会遇到打印,不管是调用系统的(Ctrl+shift+p)或者浏览器里window.print();

打印实现方案:
1.调用系统的(Ctrl+shift+p);

2.调用浏览器里window.print(); window.print() api

window.print():默认打印当前页面body里的所有内容。当然也可以打印局部。思路就是把要打印的临时赋值给body然后再重新赋值会原来的。

function doPrint2(){
//根据div标签ID拿到div中的局部内容
bdhtml=window.document.body.innerHTML;
var jubuData = document.getElementById("printcontent").innerHTML;
//把获取的 局部div内容赋给body标签, 相当于重置了 body里的内容
window.document.body.innerHTML= jubuData;
//调用打印功能
window.print();
window.document.body.innerHTML=bdhtml;//重新给页面内容赋值;
return false;
}
参考:window.print实现局部打印

window.onbeforeprint()--打印之前做的事 onbeforeprint api

window.onafterprint()--打印之后做的事 nafterprint api

3.实际上转换成图片再打印也行或者截图打印(当然效果不太好,对于海报之类的可能会好些可以用)这个也是一个思路建议用上面的。

例如:html2Canvas html2Cavas遇到的问题及解决方案 html2Cavas官网 api

定义和用法
onbeforeprint 事件在页面即将打印时触发 (在打印窗口出现前)。

提示: onbeforeprint 事件的相反事件为 onafterprint 。

遇到的问题:
打印预览的时候表格被分割了,就是一共两页而其中一行显示在不同的两个页面(而不想让tr被隔开,很难看)。如下图:

代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Document</title>
<style>

tr {
width: 500px;
height: 500px;
}
table {
/* width: 200px; */
border-top: 1px solid #999;
border-left: 1px solid #999;

border-spacing: 0;
/*去掉单元格间隙*/
}

</style>
</head>

<body>
<button onclick=func()>printthis page</button>
<table border="1px">
<tr>
<th>nmae</th>
<th>age</th>
</tr>
<tr>
<td>33</td>
<td>33</td>
</tr>
<tr>
<td>33</td>
<td>33</td>
</tr>
<tr class="vv">
<td>33</td>
<td>33</td>
</tr>
</table>
</body>
<script>
function func() {
window.print();
}
</script>

</html>
解决方案:
给tr加上age-break-inside: avoid;

tr {
width: 500px;
height: 500px;
page-break-inside: avoid;
/* page-break-before: avoid;
page-break-after: avoid; */

}
加上之后效果图

浏览器支持
表格中的数字注明了完全支持该属性的首个浏览器版本。

属性 Chrome IE Firefox Safari Opera
page-break-inside 1.0 8.0 19.0 1.3 7.0
一、定义和用法 (page-break-inside)
page-break-inside 属性设置元素内部的 page-breaking 行为。

尽管可以用 always 强制放上分页符,但是无法保证避免分页符的插入,创作人员最多只能要求用户代理尽可能避免插入分页。

应用于:position 值为 relative 或 static 的非浮动块级元素。

注释:请尽可能少地使用分页属性,并且避免在表格、浮动元素、带有边框的块元素中使用分页属性。

默认值: auto
继承性: no
版本: CSS2
JavaScript 语法: object.style.pageBreakInside="avoid"
可能的值
值 描述
auto 默认。如果必要则在元素内部插入分页符。
avoid 避免在元素内部插入分页符。
inherit 规定应该从父元素继承 page-break-inside 属性的设置。
参考: w3c page-break-inside api

二、定义和用法(page-break-before)
page-break-before 属性设置元素前的 page-breaking 行为。

尽管可以用 always 强制放上分页符,但是无法保证避免分页符的插入,创作人员最多只能要求用户代理尽可能避免插入分页。

应用于:position 值为 relative 或 static 的非浮动块级元素。

注释:请尽可能少地使用分页属性,并且避免在表格、浮动元素、带有边框的块元素中使用分页属性。

可能的值
值 描述
auto 默认值。如果必要则在元素前插入分页符。
always 在元素前插入分页符。
avoid 避免在元素前插入分页符。
left 在元素之前足够的分页符,一直到一张空白的左页为止。
right 在元素之前足够的分页符,一直到一张空白的右页为止。
inherit 规定应该从父元素继承 page-break-before 属性的设置。
参考: w3c page-break-before api

三、定义和用法(page-break-after)
page-break-after 属性设置元素后的 page-breaking 行为。

尽管可以用 always 强制放上分页符,但是无法保证避免分页符的插入,创作人员最多只能要求用户代理尽可能避免插入分页。

应用于:position 值为 relative 或 static 的非浮动块级元素。

可能的值
值 描述
auto 默认。如果必要则在元素后插入分页符。
always 在元素后插入分页符。
avoid 避免在元素后插入分页符。
left 在元素之后足够的分页符,一直到一张空白的左页为止。
right 在元素之后足够的分页符,一直到一张空白的右页为止。
inherit 规定应该从父元素继承 page-break-after 属性的设置。
注释:请尽可能少地使用分页属性,并且避免在表格、浮动元素、带有边框的块元素中使用分页属性。

参考:w3c page-break-after api

其他用法:
这个只是其中一种用法,可以搭配另外两个属性组合成各种效果(根据自己的效果搭配)。

一、page-break-before

想要实现让h1独占一页

代码如下:

任何属性都没加

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<!-- <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> -->

<title>Document</title>
<style>

h1{
text-align: center;
}

</style>
</head>

<body>
<button onclick=func()>printthis page</button>
<h1>ttttt</h1>
<p>
5555555555555555555
</p>
</body>
<script>
function func() {
window.print();
}
</script>

</html>


解决方案:

(1)给h1加page-break-after: right;

<style>

h1{
text-align: center;
page-break-after: right;
}


</style>
(2)给p加 page-break-before: right;

<style>

h1{
text-align: center;
/* page-break-after: right; */
}
p{
page-break-before: right;
}

</style>
本文部分参api考于:css-page-break 属性

vue和react中的插件
vue: vue-printjs

vue-printjs
https://codechina.csdn.net/mirrors/xyl66/vueplugs_printjs?utm_source=csdn_github_accelerator vue-print.js api地址当然github上也有只是,访问很慢 github print.js api

react:react-to-print

https://codechina.csdn.net/mirrors/gregnb/react-to-print?utm_source=csdn_github_accelerator react-to-print 地址 当然github上也有只是,访问很慢github react-to-print api

当然vue,react或者其他框架里也可以事用上面的浏览器自带的方案也行 ,请根据自己的需求择优选择。这些插件都事基于window.print封装的,有些api还是很方便的。

动态调整打印机纸张大小

江苏省昆山市地方税务局

信息管理系统中经常要提供各种打印功能,例如报表打印、凭证打印以及发票打印。在这些打印过程中所需要纸张的大小往往是不一致的,例如,打印报表有可能使用A4 纸或A3 纸,打印凭证或发票可能需要将打印纸张设置成自定义大小。如果在同一台打印机上打印这些内容,那么就应该针对不同的打印内容设置不同的纸张尺寸。显然如果用手动的方法来设置打印机的纸张尺寸是件很麻烦的事,最好的方法是让程序动态地修改打印机的纸张尺寸。

解决问题的思路

通过查阅API 函数技术文档可知,每个打印机都拥有唯一的一个叫做DevMode 的结构,与打印机相关的各项参数被存放在这个结构中。通过对DevMode 结构的分析,发现与设置打印机纸张大小有关的结构成员有四项:dmFields、dmPaperSize、dmPaperLength 以及dmPaperWidth。dmFields 是DevMode 的标志位初始化部分,如果要修改结构中的某些成员,那么dmFields 中相应位应被置位。dmPaperSize 表示打印机当前默认的打印纸张的大小,若要设置自定义纸张该项应为0(注,上述解释是根据微软提供的技术文档,但是在Delphi 中应将该成员设置成$100 即256)。dmPaperLength 和dmPaperWidth 只是在设置自定义大小纸张时使用,分别表示纸张的长度和宽度。如何对打印机的DevMode 结构进行修改呢?无非采用两种方法,一种是利用Delphi 提供的TPrinter 类中的某些方法,还有一种是调用与打印有关的API 函数。下面就以Delphi 为开发工具,以Epson 1600K 为默认打印机,用两种不同的方法来实现这一功能。

方法一:利用Delphi 的TPrinter 类

TPrinter 类是Delphi 对Windows 打印处理系统的封装,它能够帮助程序员在开发打印程序时尽可能地减少工作量。在程序中使用TPrinter,只要在单元的Use 子句后面添加Printers 即可。当前打印机的DevMode 结构的句柄可以通过调用Tprinter 类中的GetPrinter 方法来获取。当程序获得DevMode 结构的句柄后,就调用GlobalLock 函数来得到指向该结构的指针,随后可对结构中的某些成员进行修改。下面就举一个例子来说明这一问题:假设当前打印机的默认纸张尺寸是A3 纸,现在要打印长度为114mm、宽度为190mm 的纸张。为了简单起见,我们只在Form1 上放置一个Button1 按钮,增加一个OnClick 事件,在Use 子句后添加Printers。程序的代码如下:

Procedure TForm1.Button1Click(Sender: TObject);
var
Device : array[0..cchDeviceName -1] of Char;
Driver : array[0..(MAX_PATH -1)] of Char;
Port : array[0..32]of Char;
hDMode : THandle;
pDMode : PDevMode;
begin
Printer.GetPrinter(Device,Driver,Port,hDMode);
// 获取打印机DevMode 结构的句柄值,
存放在hDMode 中
if hDMode < > 0 then begin
pDMode := GlobalLock(hDMode);
// 获取指向打印机DevMode 结构的// 指针
if pDMode < > nil then begin
pDMode^.dmPaperSize := 256;
// 如果要将当前打印机纸张变为自定义
dmPaperSize 必须设置成256
pDMode^.dmPaperLength := 1140;
pDMode^.dmPaperWidth := 1900;
pDMode^.dmFields := pDMode^.dmFields or
DM_PAPERSIZE;
pDMode^.dmFields :=
pDMode^.dmFields or DM_PAPERLENGTH;
pDMode^.dmFields :=
pDMode^.dmFields or DM_PAPERWIDTH;
{ 以上三条语句是对相应
的dmFields 成员进行置位。}
ResetDC(Printer.Handle,pDMode^);
// 设置打印机设备环境句柄的值
GlobalUnlock(hDMode);
end;
end;
{ 下面的代码是为了测试打印机是否
按190 *114 纸张大小来打印}
with Printer do begin
BeginDoc;
Canvas.TextOut(10,10,'Hello, My Friend!');
EndDoc;
end;
end;

方法二:利用有关打印的Windows API 函数

解决问题的思路和第一种方法类似,首先要获取当前打印机的DevMode 结构的指针,然后再对该结构进行修改,从而修改打印机纸张大小。要完成上述功能,就得调用DocumentProperties 函数。利用该函数程序就可以获取并修改与当前打印机相关的DevMode 结构中的成员。DocumentProperties 函数申明如下:

LONG DocumentProperties
(
HWND    hWnd,
HANDLE   hPrinter,
LPTSTR   pDeviceName,
PDEVMODE pDevModeOutput,
PDEVMODE pDevModeInput,
DWORD   fMode
);
六个参数中只有pDevModeOutput 是输出变量,其余五个参数必须由程序给出具体值。其中,hWnd 表征当前窗口的句柄值;hPrinter 表示当前打印机的句柄;pDeviceName 是对打印机设备的描述;pDevModeOutput 是指向句柄值为hPrinter 的打印机DevMode 结构的指针;pDevModeInput 是指向一个修改后的DevMode 结构的指针,该结构有待于被句柄值为hPrinter 的打印机接受;fMode 定义了该函数的具体功能,如果取值DM_IN_BUFFER 那么表示打印机接受由参数pDevModeInput 表示的由程序修改了的DevMode 值,如果取值DM_OUT_BUFFER 那么程序可以通过参数pDevModeOutput 来获取打印机的DevMode 值,如果fMode 为零,则函数返回的值表示结构DevMode 所需的字节数。承接上述例子,现在将190 *114 大小的纸张设成A4 纸。再往Form1 上放置按钮Button2,增加OnClick 事件,在Use 子句后面添加WinSpool。代码如下:

Procedure TForm1.Button2Click(Sender: TObject);
var
PrnHd : THandle;
PrnInfo : PPrinterInfo1;
pcbNeeded : DWORD;
PDevModeBytes : DWORD;
DevMode: PDeviceMode;
PrnHdc : HDC;
DocInfo : PDocInfo;
begin
OpenPrinter('Epson LQ -1600K',PrnHd,nil);
// 获得打印机句柄PrnHd
GetMem(PrnInfo,1024);
GetPrinter(PrnHd,1,PrnInfo,1024,@pcbNeeded);
PDevModeBytes:= DocumentProperties
( Handle,PrnHd,prninfo^.
pDescription,DevMode^,DevMode^,0 );
{ 获取DevMode 结构所需的字节数}
GetMem(DevMode,PDevModeBytes);
// 给结构DevMode 分配空间
DocumentProperties( Handle,PrnHd,PrnInfo^.p
Description,DevMode^,DevMode^,DM_OUT_BUFFER );
// 获取打印机的DevMode 结构
With DevMode^ do begin
dmPaperSize := DMPAPER_A4   ;
// 将纸张设置成A4 纸
dmFields := dmFields or DM_PAPERSIZE;
end;
DocumentProperties( Handle,PrnHd,PrnInfo^.p
Description,DevMode^,DevMode^,
DM_OUT_BUFFER or DM_IN_BUFFER);
// 修改DevMode 结构。
{ 下面的代码是为了测试打印机
是否按A4 纸大小来打印 }
PrnHdc := CreateDC
( nil, 'Epson LQ -1600K',nil,DevMode );
GetMem( DocInfo, 100 );
With DocInfo^ do begin
cbSize := sizeof(DocInfo);
lpszDocName := nil;
lpszOutput := nil;
lpszDatatype := nil;
fwType := DI_APPBANDING;
end;
StartDoc( PrnHdc, DocInfo^);
StartPage(PrnHdc);
TextOut( PrnHdc, 10, 10, 'Hello My Friend!',17);
EndPage(PrnHdc);
EndDoc(PrnHdc);
DeleteDC(PrnHdc);
FreeMem(DocInfo);
FreeMem(PrnInfo);
FreeMem(DevMode);
end;
至此,程序实现了本文开头所提出的要求。需要指出的是,上述代码是在程序运行时,动态地改变打印机纸张大小,而不改变打印机默认纸张大小。也就是说当打印程序运行结束后,打印机还是会按照默认打印纸张大小来打印、走纸。动态调整打印机纸张尺寸也是因打印机而异,某些打印机基本不支持自定义纸张,例如惠普的HP DeskJet 1120C 喷墨打印机以及众多激光打印机。因此在这些打印机上,不能实现按任意纸张大小打印。对于一些针式打印机则没有上述问题。

上述程序是在Windows 95 环境下,用Delphi 4.0 为开发工具调试通过。

不过还是要感谢他的提示 今天和小陈搞了一天,他在国外的论坛上看到了一篇文章得到了启示,最后我们在凌晨3点终于把自定义纸张的代码给写出来了,看来必须用API,微软的.NET对打印的支持太菜了 现公开我们工作室实现此功能的部分代码 using System; using System.Text; using System.Runtime.InteropServices; using System.Security; using System.ComponentModel; using System.Drawing.Printing; namespace MCCustomPrintForm /// <summary> /// 成都微创工作室(电子科技大学微创工作室) /// Tell 028-82853098 /// Email zyspipi@163.com , you680@gmail.com /// 打印机纸张的真正自定义部分代码 /// 2006-1-2 /// </summary> public class MCCustomPrintForm // Make a static class private MCCustomPrintForm() [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct structPrinterDefaults [MarshalAs(UnmanagedType.LPTStr)] public String pDatatype; public IntPtr pDevMode; [MarshalAs(UnmanagedType.I4)] public int DesiredAccess; [DllImport( " winspool.Drv " , EntryPoint= " OpenPrinter " , SetLastError= true , CharSet =CharSet.Unicode, ExactSpelling= false ,CallingConvention= CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)] string printerName, out IntPtr phPrinter, ref structPrinterDefaults pd); [DllImport( " winspool.Drv " , EntryPoint= " ClosePrinter " , SetLastError= true , CharSet =CharSet.Unicode, ExactSpelling= false , CallingConvention = CallingConvention.StdCall),SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool ClosePrinter(IntPtr phPrinter); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct structSize public Int32 width; public Int32 height; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct structRect public Int32 left; public Int32 top; public Int32 right; public Int32 bottom; [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] internal struct FormInfo1 [FieldOffset( 0 ), MarshalAs(UnmanagedType.I4)] public uint Flags; [FieldOffset( 4 ), MarshalAs(UnmanagedType.LPWStr)] public String pName; [FieldOffset( 8 )] public structSize Size; [FieldOffset( 16 )] public structRect ImageableArea; [StructLayout(LayoutKind.Sequential, CharSet =CharSet.Ansi /* changed from CharSet=CharSet.Auto */ )] internal struct structDevMode [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32 )] public String dmDeviceName; [MarshalAs(UnmanagedType.U2)] public short dmSpecVersion; [MarshalAs(UnmanagedType.U2)] public short dmDriverVersion; [MarshalAs(UnmanagedType.U2)] public short dmSize; [MarshalAs(UnmanagedType.U2)] public short dmDriverExtra; [MarshalAs(UnmanagedType.U4)] public int dmFields; [MarshalAs(UnmanagedType.I2)] public short dmOrientation; [MarshalAs(UnmanagedType.I2)] public short dmPaperSize; [MarshalAs(UnmanagedType.I2)] public short dmPaperLength; [MarshalAs(UnmanagedType.I2)] public short dmPaperWidth; [MarshalAs(UnmanagedType.I2)] public short dmScale; [MarshalAs(UnmanagedType.I2)] public short dmCopies; [MarshalAs(UnmanagedType.I2)] public short dmDefaultSource; [MarshalAs(UnmanagedType.I2)] public short dmPrintQuality; [MarshalAs(UnmanagedType.I2)] public short dmColor; [MarshalAs(UnmanagedType.I2)] public short dmDuplex; [MarshalAs(UnmanagedType.I2)] public short dmYResolution; [MarshalAs(UnmanagedType.I2)] public short dmTTOption; [MarshalAs(UnmanagedType.I2)] public short dmCollate; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32 )] public String dmFormName; [MarshalAs(UnmanagedType.U2)] public short dmLogPixels; [MarshalAs(UnmanagedType.U4)] public int dmBitsPerPel; [MarshalAs(UnmanagedType.U4)] public int dmPelsWidth; [MarshalAs(UnmanagedType.U4)] public int dmPelsHeight; [MarshalAs(UnmanagedType.U4)] public int dmNup; [MarshalAs(UnmanagedType.U4)] public int dmDisplayFrequency; [MarshalAs(UnmanagedType.U4)] public int dmICMMethod; [MarshalAs(UnmanagedType.U4)] public int dmICMIntent; [MarshalAs(UnmanagedType.U4)] public int dmMediaType; [MarshalAs(UnmanagedType.U4)] public int dmDitherType; [MarshalAs(UnmanagedType.U4)] public int dmReserved1; [MarshalAs(UnmanagedType.U4)] public int dmReserved2; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct PRINTER_INFO_9 public IntPtr pDevMode; [DllImport( " winspool.Drv " , EntryPoint= " AddFormW " , SetLastError= true , CharSet =CharSet.Unicode, ExactSpelling= true , CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool AddForm( IntPtr phPrinter, [MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form); /* This method is not used [DllImport("winspool.Drv", EntryPoint="SetForm", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=false, CallingConvention=CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool SetForm(IntPtr phPrinter, string paperName, [MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form); [DllImport( " winspool.Drv " , EntryPoint= " DeleteForm " , SetLastError= true , CharSet =CharSet.Unicode, ExactSpelling= false ,CallingConvention= CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool DeleteForm( IntPtr phPrinter, [MarshalAs(UnmanagedType.LPTStr)] string pName); [DllImport( " kernel32.dll " , EntryPoint= " GetLastError " , SetLastError= false , ExactSpelling = true , CallingConvention= CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern Int32 GetLastError(); [DllImport( " GDI32.dll " , EntryPoint= " CreateDC " , SetLastError= true , CharSet =CharSet.Unicode, ExactSpelling= false , CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern IntPtr CreateDC([MarshalAs(UnmanagedType.LPTStr)] string pDrive, [MarshalAs(UnmanagedType.LPTStr)] string pName, [MarshalAs(UnmanagedType.LPTStr)] string pOutput, ref structDevMode pDevMode); [DllImport( " GDI32.dll " , EntryPoint= " ResetDC " , SetLastError= true , CharSet =CharSet.Unicode, ExactSpelling= false , CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern IntPtr ResetDC( IntPtr hDC, ref structDevMode pDevMode); [DllImport( " GDI32.dll " , EntryPoint= " DeleteDC " , SetLastError= true , CharSet =CharSet.Unicode, ExactSpelling= false , CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool DeleteDC(IntPtr hDC); [DllImport( " winspool.Drv " , EntryPoint= " SetPrinterA " , SetLastError= true , CharSet =CharSet.Auto, ExactSpelling= true , CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] internal static extern bool SetPrinter( IntPtr hPrinter, [MarshalAs(UnmanagedType.I4)] int level, IntPtr pPrinter, [MarshalAs(UnmanagedType.I4)] int command); LONG DocumentProperties( HWND hWnd, // handle to parent window HANDLE hPrinter, // handle to printer object LPTSTR pDeviceName, // device name PDEVMODE pDevModeOutput, // modified device mode PDEVMODE pDevModeInput, // original device mode DWORD fMode // mode options [DllImport( " winspool.Drv " , EntryPoint= " DocumentPropertiesA " , SetLastError= true , ExactSpelling = true , CallingConvention= CallingConvention.StdCall)] public static extern int DocumentProperties( IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)] string pDeviceName /* changed from String to string */ , IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode [DllImport( " winspool.Drv " , EntryPoint= " GetPrinterA " , SetLastError= true , ExactSpelling = true , CallingConvention= CallingConvention.StdCall)] public static extern bool GetPrinter( IntPtr hPrinter, int dwLevel /* changed type from Int32 */ , IntPtr pPrinter, int dwBuf /* chagned from Int32 */ , out int dwNeeded /* changed from Int32 */ // SendMessageTimeout tools [Flags] public enum SendMessageTimeoutFlags : uint SMTO_NORMAL = 0x0000 , SMTO_BLOCK = 0x0001 , SMTO_ABORTIFHUNG = 0x0002 , SMTO_NOTIMEOUTIFNOTHUNG = 0x0008 const int WM_SETTINGCHANGE = 0x001A ; const int HWND_BROADCAST = 0xffff ; [DllImport( " user32.dll " , SetLastError= true , CharSet= CharSet.Auto)] public static extern IntPtr SendMessageTimeout( IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out IntPtr result // 打印纸张长宽设置 public static void AddMC80MmPaperSizeToDefaultPrinter() AddCustomPaperSizeToDefaultPrinter( " MC 80mm * Receipt Length " , 80.1f , 4003.9f ); public static void AddMC104MmPaperSizeToDefaultPrinter() AddCustomPaperSizeToDefaultPrinter( " MC 104mm * Receipt Length " , 104.1f , 4003.9f ); /// <summary> /// Adds the printer form to the default printer /// </summary> /// <param name="paperName"> Name of the printer form </param> /// <param name="widthMm"> Width given in millimeters </param> /// <param name="heightMm"> Height given in millimeters </param> public static void AddCustomPaperSizeToDefaultPrinter( string paperName, float widthMm, float heightMm) PrintDocument pd = new PrintDocument(); string sPrinterName = pd.PrinterSettings.PrinterName; AddCustomPaperSize(sPrinterName, paperName, widthMm, heightMm); /// <summary> /// Add the printer form to a printer /// </summary> /// <param name="printerName"> The printer name </param> /// <param name="paperName"> Name of the printer form </param> /// <param name="widthMm"> Width given in millimeters </param> /// <param name="heightMm"> Height given in millimeters </param> public static void AddCustomPaperSize( string printerName, string paperName, float widthMm, float heightMm) if (PlatformID.Win32NT == Environment.OSVersion.Platform) // The code to add a custom paper size is different for Windows NT then it is // for previous versions of windows const int PRINTER_ACCESS_USE = 0x00000008 ; const int PRINTER_ACCESS_ADMINISTER = 0x00000004 ; const int FORM_PRINTER = 0x00000002 ; structPrinterDefaults defaults = new structPrinterDefaults(); defaults.pDatatype = null ; defaults.pDevMode = IntPtr.Zero; defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE; IntPtr hPrinter = IntPtr.Zero; // Open the printer. if (OpenPrinter(printerName, out hPrinter, ref defaults)) // delete the form incase it already exists DeleteForm(hPrinter, paperName); // create and initialize the FORM_INFO_1 structure FormInfo1 formInfo = new FormInfo1(); formInfo.Flags = 0 ; formInfo.pName = paperName; // all sizes in 1000ths of millimeters formInfo.Size.width = ( int )(widthMm * 1000.0 ); formInfo.Size.height = ( int )(heightMm * 1000.0 ); formInfo.ImageableArea.left = 0 ; formInfo.ImageableArea.right = formInfo.Size.width; formInfo.ImageableArea.top = 0 ; formInfo.ImageableArea.bottom = formInfo.Size.height; if (!AddForm(hPrinter, 1 , ref formInfo)) StringBuilder strBuilder = new StringBuilder(); strBuilder.AppendFormat( " Failed to add the custom paper size {0} to the printer {1}, System error number: {2} " , paperName, printerName, GetLastError()); throw new ApplicationException(strBuilder.ToString()); // INIT const int DM_OUT_BUFFER = 2 ; const int DM_IN_BUFFER = 8 ; structDevMode devMode = new structDevMode(); IntPtr hPrinterInfo, hDummy; PRINTER_INFO_9 printerInfo; printerInfo.pDevMode = IntPtr.Zero; int iPrinterInfoSize, iDummyInt; // GET THE SIZE OF THE DEV_MODE BUFFER int iDevModeSize = DocumentProperties(IntPtr.Zero, hPrinter, printerName, IntPtr.Zero, IntPtr.Zero, 0 ); if (iDevModeSize < 0 ) throw new ApplicationException( " Cannot get the size of the DEVMODE structure. " ); // ALLOCATE THE BUFFER IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100 ); // GET A POINTER TO THE DEV_MODE BUFFER int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, hDevMode, IntPtr.Zero, DM_OUT_BUFFER); if (iRet < 0 ) throw new ApplicationException( " Cannot get the DEVMODE structure. " ); // FILL THE DEV_MODE STRUCTURE devMode = (structDevMode)Marshal.PtrToStructure(hDevMode, devMode.GetType()); // SET THE FORM NAME FIELDS TO INDICATE THAT THIS FIELD WILL BE MODIFIED devMode.dmFields = 0x10000 ; // DM_FORMNAME // SET THE FORM NAME devMode.dmFormName = paperName; // PUT THE DEV_MODE STRUCTURE BACK INTO THE POINTER Marshal.StructureToPtr(devMode, hDevMode, true ); // MERGE THE NEW CHAGES WITH THE OLD iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, printerInfo.pDevMode, printerInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); if (iRet < 0 ) throw new ApplicationException( " Unable to set the orientation setting for this printer. " ); // GET THE PRINTER INFO SIZE GetPrinter(hPrinter, 9 , IntPtr.Zero, 0 , out iPrinterInfoSize); if (iPrinterInfoSize == 0 ) throw new ApplicationException( " GetPrinter failed. Couldn't get the # bytes needed for shared PRINTER_INFO_9 structure " ); // ALLOCATE THE BUFFER hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100 ); // GET A POINTER TO THE PRINTER INFO BUFFER bool bSuccess = GetPrinter(hPrinter, 9 , hPrinterInfo, iPrinterInfoSize, out iDummyInt); if (! bSuccess) throw new ApplicationException( " GetPrinter failed. Couldn't get the shared PRINTER_INFO_9 structure " ); // FILL THE PRINTER INFO STRUCTURE printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(hPrinterInfo, printerInfo.GetType()); printerInfo.pDevMode = hDevMode; // GET A POINTER TO THE PRINTER INFO STRUCTURE Marshal.StructureToPtr(printerInfo, hPrinterInfo, true ); // SET THE PRINTER SETTINGS bSuccess = SetPrinter(hPrinter, 9 , hPrinterInfo, 0 ); if (! bSuccess) throw new Win32Exception(Marshal.GetLastWin32Error(), " SetPrinter() failed. Couldn't set the printer settings " ); // Tell all open programs that this change occurred. SendMessageTimeout( new IntPtr(HWND_BROADCAST), WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero, MCCustomPrintForm.SendMessageTimeoutFlags.SMTO_NORMAL, 1000 , out hDummy); finally ClosePrinter(hPrinter); StringBuilder strBuilder = new StringBuilder(); strBuilder.AppendFormat( " Failed to open the {0} printer, System error number: {1} " , printerName, GetLastError()); throw new ApplicationException(strBuilder.ToString()); structDevMode pDevMode = new structDevMode(); IntPtr hDC = CreateDC( null , printerName, null , ref pDevMode); if (hDC != IntPtr.Zero) const long DM_PAPERSIZE = 0x00000002L ; const long DM_PAPERLENGTH = 0x00000004L ; const long DM_PAPERWIDTH = 0x00000008L ; pDevMode.dmFields = ( int )(DM_PAPERSIZE | DM_PAPERWIDTH | DM_PAPERLENGTH); pDevMode.dmPaperSize = 256 ; pDevMode.dmPaperWidth = ( short )(widthMm * 1000.0 ); pDevMode.dmPaperLength = ( short )(heightMm * 1000.0 ); ResetDC(hDC, ref pDevMode); DeleteDC(hDC);

C# PrintDocument打印 多页 打印预览

PrintDocument实例所有的订阅事件如下:

1.创建一个PrintDocument的实例.如下:
System.Drawing.Printing.PrintDocument docToPrint =
new System.Drawing.Printing.PrintDocument();
2.设置打印机开始打印的事件处理函数.函数原形如下:
void docToPrint_PrintPage(object sender,
System.Drawing.Printing.PrintPageEventArgs e)
3.将事件处理函数添加到PrintDocument的PrintPage事件中。
docToPrint.PrintPage+=new PrintPageEventHandler(docToPrint_PrintPage);
4.设置PrintDocument的相关属性,如:
PrintDialog1.AllowSomePages = true;PrintDialog1.ShowHelp = true;
5.把PrintDialog的Document属性设为上面配置好的PrintDocument的实例:
PrintDialog1.Document = docToPrint;
6.调用PrintDialog的ShowDialog函数显示打印对话框:
DialogResult result = PrintDialog1.ShowDialog();
7.根据用户的选择,开始打印:
if (result==DialogResult.OK)
{
docToPrint.Print();
}
8.打印预览控件PrintPreviewDialog
例子如下:

使用时先创建PrintService类的实例,然后调用void StartPrint(Stream streamToPrint,string streamType)函数开始打印。其中streamToPrint是要打印的内容(字节流),streamType是流的类型(txt表示普通文本,image表示图像);

public partial class PrintTxt
private PrintPreviewDialog PrintPreview = new PrintPreviewDialog();
private string StreamType;
private Image image = null ;
private Stream StreamToPrint = null ;
Font mainFont = new Font( "宋体" , 12); //打印的字体
public string Filename = null ;
//订阅BeginPrint事件
pdDocument.BeginPrint += new PrintEventHandler(pdDocument_BeginPrint);
//訂閱EndPrint事件,释放资源
//订阅Print打印事件,该方法必须放在订阅打印事件的最后
FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
StartPrint(fs, filetype);
PageSettings ps = new PageSettings();
//显示设置打印页对话框
PageSetupDialog Psdl = new PageSetupDialog();
//打印多份设置,注意,该方法需放在printpage方法后面。
PrintDialog pt = new PrintDialog();
pt.AllowCurrentPage = true ;
pt.AllowSomePages = true ;
pt.AllowPrintToFile = true ;
StreamToPrint = streamToPrint; //打印的字节流
StreamType = streamType; //打印的类型
pdDocument.DocumentName = Filename; //打印的文件名
Psdl.Document = pdDocument;
PrintPreview.Document = pdDocument;
pt.Document = pdDocument;
Psdl.PageSettings = pdDocument.DefaultPageSettings;
//显示对话框
if (Psdl.ShowDialog() == DialogResult.OK)
ps = Psdl.PageSettings;
pdDocument.DefaultPageSettings = Psdl.PageSettings;
if (pt.ShowDialog() == DialogResult.OK)
pdDocument.PrinterSettings.Copies = pt.PrinterSettings.Copies;
pdDocument.Print();
if (PrintPreview.ShowDialog()==DialogResult.OK )
//调用打印
pdDocument.Print();
* PrintDocument对象的Print()方法在PrintController类中执行PrintPage事件。
catch (InvalidPrinterException ex)
MessageBox.Show(ex.Message, "Simple Editor" , MessageBoxButtons.OK, MessageBoxIcon.Error);
throw ;
/// <summary>
/// 3、得到打印內容
/// 每个打印任务只调用OnBeginPrint()一次。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void pdDocument_BeginPrint( object sender, PrintEventArgs e)
char [] param = { '\n' };
char [] trimParam = { '\r' }; //回车
switch (StreamType)
case "txt" :
StringBuilder text = new StringBuilder();
System.IO.StreamReader streamReader = new StreamReader(StreamToPrint, Encoding.Default);
while (streamReader.Peek() >= 0)
lines = streamReader.ReadToEnd().Split(param);
for ( int i = 0; i < lines.Length; i++)
lines[i] = lines[i].TrimEnd(trimParam);
break ;
case "image" :
image = System.Drawing.Image.FromStream(StreamToPrint);
break ;
default :
break ;
/// <summary>
/// 4、绘制多个打印界面
/// printDocument的PrintPage事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnPrintPage( object sender, PrintPageEventArgs e)
int leftMargin = Convert.ToInt32((e.MarginBounds.Left) * 3 / 4); //左边距
int topMargin = Convert.ToInt32(e.MarginBounds.Top * 2 / 3); //顶边距
switch (StreamType)
case "txt" :
while (linesPrinted < lines.Length)
//向画布中填写内容
e.Graphics.DrawString(lines[linesPrinted++], new Font( "Arial" , 10), Brushes.Black, leftMargin, topMargin, new StringFormat());
topMargin += 55; //行高为55,可调整
//走纸换页
if (topMargin >= e.PageBounds.Height - 60) //页面累加的高度大于页面高度。根据自己需要,可以适当调整
//如果大于设定的高
e.HasMorePages = true ;
* PrintPageEventArgs类的HaeMorePages属性为True时,通知控件器,必须再次調用OnPrintPage()方法,打印一个页面。
* PrintLoopI()有一个用於每个要打印的页面的序例。如果HasMorePages是False,PrintLoop()就会停止。
return ;
break ;
case "image" : //一下涉及剪切图片,
int width = image.Width;
int height = image.Height;
if ((width / e.MarginBounds.Width) > (height / e.MarginBounds.Height))
width = e.MarginBounds.Width;
height = image.Height * e.MarginBounds.Width / image.Width;
height = e.MarginBounds.Height;
width = image.Width * e.MarginBounds.Height / image.Height;
System.Drawing.Rectangle destRect = new System.Drawing.Rectangle(topMargin, leftMargin, width, height);
//向画布写入图片
for ( int i = 0; i < Convert.ToInt32(Math.Floor(( double )image.Height/ 820)) + 1; i++)
e.Graphics.DrawImage(image, destRect, i*820,i*1170 , image.Width, image.Height, System.Drawing.GraphicsUnit.Pixel);
//走纸换页
if (i * 1170 >= e.PageBounds.Height - 60) //页面累加的高度大于页面高度。根据自己需要,可以适当调整
//如果大于设定的高
e.HasMorePages = true ;
* PrintPageEventArgs类的HaeMorePages属性为True时,通知控件器,必须再次調用OnPrintPage()方法,打印一个页面。
* PrintLoopI()有一个用於每个要打印的页面的序例。如果HasMorePages是False,PrintLoop()就会停止。
return ;
break ;
//打印完毕后,画线条,且注明打印日期
e.Graphics.DrawLine( new Pen(Color.Black), leftMargin, topMargin, e.MarginBounds.Right, topMargin);
string strdatetime = DateTime.Now.ToLongDateString() + DateTime.Now.ToLongTimeString();
e.Graphics.DrawString( string .Format( "打印时间:{0}" , strdatetime), mainFont, Brushes.Black, e.MarginBounds.Right-240, topMargin+40, new StringFormat());
linesPrinted = 0;
//绘制完成后,关闭多页打印功能
e.HasMorePages = false ;
/// <summary>
///5、EndPrint事件,释放资源
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void pdDocument_EndPrint( object sender, PrintEventArgs e)
//变量Lines占用和引用的字符串数组,现在释放
lines = null ;
//PrintTxt simple = new PrintTxt("D:\\Mainsoft\\12.txt", "txt");

于 2016-05-30 15:26:56 发布

8703
收藏 18
分类专栏: C#学习笔记
版权

C#学习笔记
专栏收录该内容
54 篇文章0 订阅
订阅专栏
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PrintDocument控件
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

/// <summary>
/// PrintDocument:用于打印最重要的类,几乎所有的打印类都与这个类有关系。
/// </summary>

// 1、打印页面设置
private void btnSetting_Click(object sender, EventArgs e)
{
// 打印页面设置对话框
PageSetupDialog page = new PageSetupDialog();

page.Document = printDocument1;
page.AllowMargins = true;
page.AllowOrientation = true;
page.AllowPaper = true;
page.AllowPrinter = true;
page.ShowHelp = true;
if (page.ShowDialog() == DialogResult.OK)
{
// 将设置好的打印页 用作 PrintDocument进行打印。
printDocument1.DefaultPageSettings = page.PageSettings;
}
}

// 2、打印机设置
private void btnPrint_Click(object sender, EventArgs e)
{
// 打印机设置对话框
PrintDialog print = new PrintDialog();

print.Document = printDocument1;
print.AllowCurrentPage = true;
print.AllowPrintToFile = true;
print.AllowSelection = true;
print.AllowSomePages = true;
print.ShowHelp = true;
if (print.ShowDialog() == DialogResult.OK)
{
// 将设置好的打印机 用作 PrinDocument进行打印。
printDocument1.PrinterSettings = print.PrinterSettings;
}
}

// 3、打印预览
private void btnPreview_Click(object sender, EventArgs e)
{
if (MessageBox.Show("是否要预览打印文件?", "打印预览", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) == DialogResult.OK)
{
// 设置要预览的文档
printPreviewDialog1.Document = printDocument1;
// 开启操作系统的抗锯齿功能
printPreviewDialog1.UseAntiAlias = true;

// 打开预览窗口
if (printPreviewDialog1.ShowDialog() == DialogResult.OK)
{
// 如果选择的是系统默认打印机,点击“打印”按钮之后,会跳出“文件另存为”窗口;
// 如果选择别的打印机,点击“打印”之后,会直接打印,不会返回“OK”。
MessageBox.Show("开始打印");
}
else
{
MessageBox.Show("关闭预览");
}
}
}

// 4、开始打印
private void btnStart_Click(object sender, EventArgs e)
{
// PrintController:控制一个PrintDocument是如何打印的。
PrintController printController = new StandardPrintController();
printDocument1.PrintController = printController;
printDocument1.DocumentName = "社保样卡";
printDocument1.PrinterSettings.PrinterName = "XID8600 U1";
printDocument1.Print(); // 触发Print_Page事件。
}


// PrintDocument 三个事件中的第二个参数 e 有如下属性:
// e.Cancel:设置为true,将取消这次打印作业。
// e.Griphics:所使用打印机的设备环境。
// e.HasMorePages:PrintPage事件打印一页后,如果仍有数据未打印,退出事件前设置
// HasMorePages=true;退出事件之后将再次出发PrintPage事件,打印下一页。
// e.MarginBounds:打印区域的大小,是Rectangle结构,元素包括左上角坐标(Left和Top),
// 宽和高(Width和Height),单位为1/100英寸。
// e.PageSettings:PageSettings类对象,包含用对话框PageSetupDialog设置的页面打印方式的
// 全部信息,

// 在调用 Print 方法后,在打印文档的第一页之前发生。
private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
}

// 需要打印新的一页时发生,负责打印一页所需要的数据
// 打印预览会调用该事件,预览的内容就是此处设置好的内容。
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
Image iamge = Image.FromFile(@"D:\photo\test.jpg");

e.Graphics.DrawString("社保卡样卡", new Font("黑体", 35), Brushes.Black, new Point(400, 120));

e.Graphics.DrawString("姓名 张三", new Font("黑体", 25), Brushes.Black, new Point(480, 270));
e.Graphics.DrawString("社会保障号码 32032032302030230", new Font("黑体", 25), Brushes.Black, new Point(480, 360));
e.Graphics.DrawString("社会保障卡号 JS2018098", new Font("黑体", 25), Brushes.Black, new Point(480, 450));
e.Graphics.DrawString("制卡日期 2016年5月", new Font("黑体", 25), Brushes.Black, new Point(480, 540));
e.Graphics.DrawImage(iamge, new Point(100, 240));
}

// 在打印完最后一页文档时发生。
private void printDocument1_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
}

/// <summary>
/// 打印机状态值
/// </summary>
public enum PrinterStatus
{
其他状态 = 1,
未知,
空闲,
正在打印,
预热,
停止打印,
打印中,
离线
}

// 获取指定打印机的状态
private void btnState_Click(object sender, EventArgs e)
{
string strPrinter = "win32_printer.DeviceId='XID8300 U1'";

// 用指定的打印机实例化一个打印机对象。
ManagementObject printer = new ManagementObject(strPrinter);

// 获取打印机信息。
printer.Get();

// 获取打印机状态属性
string str = printer.Properties["PrinterStatus"].Value.ToString();
textBox1.Text = str;
}

// 获取本地所有打印机信息
private void button1_Click(object sender, EventArgs e)
{
string strPrinter = "win32_printer";

// 获取本地所有打印机
ManagementClass mc = new ManagementClass(strPrinter);

// 获取所有打印机实例的集合
ManagementObjectCollection moc = mc.GetInstances();

// 遍历本地所有打印机
foreach (ManagementObject printer in moc)
{
// 打印机名字
string strName = printer.Properties["DeviceId"].Value.ToString();
// 打印机状态
string strState = printer.Properties["PrinterStatus"].Value.ToString();
comboBox1.Items.Add(strName);
}
}
}
}


秋忆夏伤
关注

————————————————
版权声明:本文为CSDN博主「秋忆夏伤」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_29331365/article/details/51538369

======================个性签名=====================

之前认为Apple 的iOS 设计的要比 Android 稳定,我错了吗?

下载的许多客户端程序/游戏程序,经常会Crash,是程序写的不好(内存泄漏?刚启动也会吗?)还是iOS本身的不稳定!!!

如果在Android手机中可以简单联接到ddms,就可以查看系统log,很容易看到程序为什么出错,在iPhone中如何得知呢?试试Organizer吧,分析一下Device logs,也许有用.

对于博客园里的网友,不敢称为叫"程序员"的人,你们攻击性太强,看来你们是不会想到我的用意的.园子里有不少人都非常喜欢Jeffrey,是因为它的第一版 框架设计 CLR via C#.
可是从第一版到现在的第三版,没有看到真正底层的东西,内容仅仅是比MSDN文档更丰富一些,可能是我的要求太高了吧.
也就是因为它很多时候会接触到微软开发人员,会经常聊聊某些问题而已,而它又将这些问题反应到书中.也许它就像一个小记者.
它的年龄大我们不多,我的孩子与它小儿子一般大,如果我能向它那样出入微软与它们开发人员长时间交流,不仅仅会牛成它这样.....
可是微软的开发人员不会扔太多时间在它这儿的.所以它会整天追着这个,赶它那个..屁颠个不停吧...
而它的另一版被称为好书的 Windows核心编程,更是没有什么深度可言,仅仅是将windows提供的api,以及内核功能再重申了一遍.
这些书对晋及编程知识是有些贡献的,再说一遍我不是在匾低谁,说说想法而已.