PageSetupDialog 类的一个 BUG
来源:互联网 发布:淘宝日本直邮是真的吗 编辑:程序博客网 时间:2024/06/03 11:15
我们在用 C# 语言编写 WinForm 程序时,如果在程序中需要打印一些东东的话,经常需要先使用页面设置对话框进行一些设置。而 Microsoft .NET Framework Base Class Library 已经为我们考虑得很周到了,我们只需要使用 System.Windows.Forms 命名空间中的 PageSetupDialog 类就行了。但是这个类有个小小的 BUG,下面就是相应的测试程序 PageSetupTester.cs:
001: using System;002: using System.Drawing;003: using System.Windows.Forms;004: using System.Globalization;005: using System.Drawing.Printing;006: 007: namespace Skyiv.Tester008: {009: sealed class PageSetupTester : Form010: {011: PageSetupDialog setupB;012: 013: PageSetupTester()014: {015: Text = "页面设置测试";016: Width = 380;017: 018: var lbl = new Label();019: lbl.Parent = this;020: lbl.Text = string.Format(021: " OS: {1}{0}CLR: {2} ( {3} ){0}{4}{5}{0}{0}{6}{0}{7}{0}{8}{0}{9}{0}{10}",022: Environment.NewLine,023: Environment.OSVersion,024: Environment.Version,025: RuntimeFramework.CurrentFramework,026: "控制面板的区域选项的度量衡系统为",027: (RegionInfo.CurrentRegion.IsMetric ? "公制。" : "英制。"),028: "当度量衡系统为公制,且操作系统为Windows时,",029: "显示在页面设置对话框中的当前页边距是以公制为单位的数值,",030: "按下“确定”时,PageSetupDialog类内部却把屏幕上显示的",031: "页边距数值按英制为单位对页面进行设定,",032: "造成页边距不断减少的BUG。");033: lbl.Top = 10;034: lbl.AutoSize = true;035: 036: var docA = new PrintDocument();037: docA.PrintPage += PrintPage;038: var setupA = new PageSetupDialog();039: setupA.Document = docA;040: 041: var btnPageSetupA = new Button();042: btnPageSetupA.Parent = this;043: btnPageSetupA.Text = "页面设置A(可能有BUG)";044: btnPageSetupA.Top = 145;045: btnPageSetupA.Width = 150;046: btnPageSetupA.Click += (sender, e) => setupA.ShowDialog();047: 048: var btnPreviewA = new Button();049: btnPreviewA.Parent = this;050: btnPreviewA.Text = "打印预览A";051: btnPreviewA.Top = btnPageSetupA.Top;052: btnPreviewA.Left = btnPageSetupA.Right + 5;053: btnPreviewA.Width = 100;054: btnPreviewA.Click += (sender, e) => PreviewPrint(docA);055: 056: var docB = new PrintDocument();057: docB.PrintPage += PrintPage;058: setupB = new PageSetupDialog();059: setupB.Document = docB;060: 061: var btnSetupB = new Button();062: btnSetupB.Parent = this;063: btnSetupB.Text = "页面设置B(修正)";064: btnSetupB.Top = btnPageSetupA.Top + 30;065: btnSetupB.Width = 150;066: btnSetupB.Click += PageSetupBClick;067: 068: var btnPreviewB = new Button();069: btnPreviewB.Parent = this;070: btnPreviewB.Text = "打印预览B";071: btnPreviewB.Top = btnSetupB.Top;072: btnPreviewB.Left = btnSetupB.Right + 5;073: btnPreviewB.Width = 100;074: btnPreviewB.Click += (sender, e) => PreviewPrint(docB);075: }076: 077: void PrintPage(object o, PrintPageEventArgs e)078: {079: Graphics g = e.Graphics;080: Rectangle r = e.MarginBounds;081: g.DrawRectangle(new Pen(Color.Red), r);082: g.DrawString(r.ToString(), new Font("宋体", 40), new SolidBrush(Color.Blue), r);083: }084: 085: void PreviewPrint(PrintDocument doc)086: {087: var ppc = new PreviewPrintController();088: doc.PrintController = ppc;089: doc.Print();090: new PreviewPrintDialog(ppc.GetPreviewPageInfo()).ShowDialog();091: }092: 093: void PageSetupBClick(object o, EventArgs e)094: {095: // 当前线程所使用的区域选项的度量衡系统为公制,且操作系统为Windows时,096: // 显示在页面设置对话框中的当前页边距是以公制为单位的数值,097: // 按下“确定”时,PageSetupDialog类内部却把屏幕上显示的098: // 页边距数值按英制为单位对页面进行设定,099: // 造成页边距不断减少的BUG。100: // 以下代码就是为了纠正这个BUG的。101: if (setupB.ShowDialog() == DialogResult.OK && RegionInfo.CurrentRegion.IsMetric102: && Environment.OSVersion.Platform != PlatformID.Unix)103: {104: setupB.PageSettings.Margins = PrinterUnitConvert.Convert105: (setupB.PageSettings.Margins, PrinterUnit.Display, PrinterUnit.TenthsOfAMillimeter);106: }107: }108: 109: [STAThread]110: static void Main()111: {112: Application.EnableVisualStyles();113: Application.Run(new PageSetupTester());114: }115: }116: }
本来嘛,在 C# 程序要得到一个页面设置对话框是非常简单的事,只要象上述程序中第 46 行那样给“页面设置”按钮的 Click 事件注册一个调用 System.Windows.Forms.PageSetupDialog 类的 ShowDialog 方法的Lambda 表达式就行了。
编译响应文件 mak.rsp 的内容如下:
用于打印预览的 PreviewPrintDialog.cs 将在本文最后给出。而 RuntimeFramework.cs 请参见我在2009年12月13日写的“.NET Framework CLR 版本检测”一文。
让我们在 Windows Vista 操作系统的 .NET Framework 4 环境下编译和运行:
然后点击“打印预览B”按钮,得到的结果如下图(图1)所示:
图1
再点击“页面设置B(修正)”按钮,得到的结果如下图(图2)所示:
图2
点击上图中的“确定”按钮后,再次点击主窗体中的“打印预览B”按钮,得到的结果依然如图1所示。这是页面设置对话框应该有的正确行为。实际上这个行为是经过 PageSetupTester.cs 中第 104 行到第 105 行的语句修正后的结果。
现在让我们点击主窗体中的“打印预览A”按钮,得到的结果也是如图1如示,这也是正常的结果。然后再点击主窗体中的“页面设置A(可能有BUG)”按钮,得到的得到如图2所示,这也是预期的结果。然后再点“确定”按钮。现在,让我们再次点击主窗体中的“打印预览A”按钮,结果如下图所示:
这就不正常了。
再次点击主窗体中的“页面设置A(可能有BUG)”按钮,得到的得到如下图所示:
从上图中可以看到,页边距由图2中的“10毫米”变为现在的“3.94毫米”了。
我们知道,在控制面板的区域选项的度量衡系统设为英制时,页边距单位是“1/10英寸”。我们还知道“1/10英寸≈2.54毫米”。而“10/2.54≈3.94”,这个公式能够说明为什么页边距由图2中的“10毫米”变为现在的“3.94毫米”了。可能是 BCL 的 PageSetupDialog 类做了一次不必要的从公制到英制的转换。而 PageSetupTester.cs 中的第 104 到第 105 行通过调用 PrinterUnitConvert 类的 Convert 方法对页边距做了一次从英制到公制的转换,也就是从 PrinterUnit.Display(0.01英寸) 到 PrinterUnit.TenthsOfAMillimeter(0.1毫米) 的转换,以修正这个BUG。
在上图中点击“确定”按钮后,继续点击主窗体中的“打印预览A”按钮,结果如下图所示:
可以看出,页边距进一步缩小了。
让我们在 Windows Vista 操作系统的 .NET Framework 3.5 环境下编译和运行:
重复上面的测试过程,得到的结果也是一样的。
现在让我们在 Ubuntu 10.10 操作系统的 mono 2.8.1 环境下编译和运行:
点击主窗体的“打印预览A”按钮,得到的结果如下图(图3)所示:
图3
可以看到,文字超出矩形框部分被截断了,而不是象 Windows 操作系统中那样折行显示,这应该是 mono 实现的 WinForm 的一个缺点。
再点击主窗体中的“页面设置A(可能有BUG)”按钮,得到的结果如下图(图4)所示:
图4
点击“OK”按钮后,再点击主窗体中的“打印预览A”按钮,得到的结果如下图(图5)所示:
图5
这可能是页边距微调。再反复点击主窗体中的“页面设置A(可能有BUG)”按钮和“打印预览A”按钮,得到的结果一直如图4和图5所示,不会象在 Windows 操作系统中一样有BUG。
如果点击主窗体中的“页面设置B(修正)”按钮和“打印预览B”按钮,结果和点击“A”系列按钮一样。这是可以预期的,因为在 PageSetupTester.cs 中的第 102 行就已经判断如果是 Unix 类的操作系统的话,就不进行修正,从而“A”和“B”两组按钮的行为是一样的。
让我们在 Ubuntu 10.10 操作系统的 mono 2.6.7 环境下编译和运行:
测试结果和 mono 2.8.1 环境的一样。
让我们在 Windows Vista 操作系统的 mono 2.8.1 环境下编译和运行:
点击主窗体的“打印预览A”按钮,得到的结果如下图(图6)所示:
图6
对照前面如图3所示的 Ubuntu 10.10 操作系统 mono 2.8.1 环境下的打印预览,发现这次文字超出矩形框部分不会被截断了,而是正确地进行了折行处理。看来 mono 对 WinForm 的实现跟操作系统还是有关系的。
再点击主窗体中的“页面设置A(可能有BUG)”按钮,得到的结果如下图(图7)所示:
图7
点击“OK”按钮后,再点击主窗体中的“打印预览A”按钮,得到的结果如下图(图8)所示:
图8
这可能是页边距微调。再反复点击主窗体中的“页面设置A(可能有BUG)”按钮和“打印预览A”按钮,得到的结果一直如图7和图8所示,不会象在 Windows 操作系统的 .NET Framework 4 环境中一样有BUG,虽然这也是在 Windows 操作系统中运行,但这次是 mono 2.8.1 环境。
我们这次点击主窗体中的“打印预览B”按钮,结果如图6所示,这是正常的。再点击主窗体中“页面设置B(修正)”按钮,结果如图7所示,然后点击“OK”按钮,再次点击主窗体中的“打印预览B”按钮,结果如下图所示:
咦,页边距变大了。再次点击主窗体中的“页面设置B(修正)”按钮,结果如下图所示:
可以看出,页边距由图7中的“25毫米”变为现在的“63毫米”。这是 PageSetupTester.cs 程序中第 104 行到第 105 行的从英制到公制的转换造成的:“25 * 2.54 = 63.5”。程序中第 102 行认为不是 Unix 类的操作系统就需要进行修正,而实际上在 Windows 操作系统的 mono 环境中 PageSetupDialog 类没有这个 BUG,不需要修正。在 PageSetupDialog 类没有 BUG 的情况下去修正反而会出问题的。
最后,就是提供打印预览功能的 PreviewPrintDialog.cs 了:
01: using System.Drawing;02: using System.Drawing.Printing;03: using System.Windows.Forms;04: 05: namespace Skyiv06: {07: sealed class PreviewPrintDialog : Form08: {09: Label lbl;10: PictureBox pbx;11: Button btnPrevPage;12: Button btnNextPage;13: PreviewPageInfo[] ppi;14: 15: public PreviewPrintDialog(PreviewPageInfo[] ppi)16: {17: this.ppi = ppi;18: 19: Text = "打印预览";20: StartPosition = FormStartPosition.CenterScreen;21: Width = 400;22: Height = 610;23: ShowInTaskbar = false;24: 25: var pnlMain = new Panel();26: pnlMain.Parent = this;27: pnlMain.Dock = DockStyle.Fill;28: pnlMain.AutoScroll = true;29: 30: var pnlTop = new Panel();31: pnlTop.Parent = this;32: pnlTop.Dock = DockStyle.Top;33: pnlTop.Height = 30;34: 35: var page = 0;36: 37: lbl = new Label();38: lbl.Parent = pnlTop;39: lbl.Text = string.Format("第{0}页 共{1}页", page + 1, ppi.Length);40: lbl.Left = 5;41: lbl.Top = 8;42: lbl.Width = 95;43: 44: btnPrevPage = new Button();45: btnPrevPage.Parent = pnlTop;46: btnPrevPage.Text = "上页(&V)";47: btnPrevPage.Left = 100;48: btnPrevPage.Top = 3;49: btnPrevPage.Width = 80;50: btnPrevPage.Enabled = (page > 0);51: btnPrevPage.Click += delegate { if (page > 0) --page; PageHandler(page); };52: 53: btnNextPage = new Button();54: btnNextPage.Parent = pnlTop;55: btnNextPage.Text = "下页(&N)";56: btnNextPage.Left = 200;57: btnNextPage.Top = 3;58: btnNextPage.Width = 80;59: btnNextPage.Enabled = (page < ppi.Length - 1);60: btnNextPage.Click += delegate { if (page < ppi.Length - 1) ++page; PageHandler(page); };61: 62: var btnClose = new Button();63: btnClose.Parent = pnlTop;64: btnClose.Text = "关闭(&C)";65: btnClose.Left = 300;66: btnClose.Top = 3;67: btnClose.Width = 80;68: btnClose.DialogResult = DialogResult.OK;69: 70: var size = ppi[page].Image.Size;71: 72: var pnlImage = new Panel();73: pnlImage.Parent = pnlMain;74: pnlImage.Width = pnlMain.Width - 10;75: pnlImage.Height = pnlImage.Width * size.Height / size.Width;76: pnlImage.BackColor = Color.White;77: 78: pbx = new PictureBox();79: pbx.Parent = pnlImage;80: pbx.ClientSize = pnlImage.ClientSize;81: pbx.Image = ppi[page].Image;82: pbx.BorderStyle = BorderStyle.FixedSingle;83: pbx.SizeMode = PictureBoxSizeMode.StretchImage;84: }85: 86: void PageHandler(int page)87: {88: btnPrevPage.Enabled = (page > 0);89: btnNextPage.Enabled = (page < ppi.Length - 1);90: lbl.Text = string.Format("第{0}页 共{1}页", page + 1, ppi.Length);91: pbx.Image = ppi[page].Image;92: }93: }94: }
- PageSetupDialog 类的一个 BUG
- PageSetupDialog 类的一个 BUG
- PageSetupDialog 控件页边距bug的完整解决
- TimerWnd 类的一个 bug
- Sound类的一个bug
- 一个有关fstream类的bug
- 一个有关fstream类的bug
- 一个有关fstream类的bug
- 微软的一个bug?
- OracleParameter 的一个bug
- FireFox的一个bug
- 微软的一个BUG
- Tencent 的一个Bug
- 一个ComboBox的Bug
- WindowsXP的一个Bug
- QQ的一个BUG
- JCreator的一个BUG
- Word2007的一个bug
- Android环境搭建GOOD
- 【Android】Android之多页面问答题
- C语言的历史
- 异步调用
- 浅谈字符编码
- PageSetupDialog 类的一个 BUG
- 一次程序调试小记
- 浅谈 F# 2.0 的两个运行时
- [翻译] Programming F#
- 浅谈 GetHashCode
- Unicode 二三事
- Creo二次开发——清理多余版本
- .NET Framework CLR 版本检测
- java培训 2015-07-30