如何在C#中完整打印含滚动内容的多页FlowLayoutPanel?
解决FlowLayoutPanel完整多页打印问题
我懂你的痛点——用DrawToBitmap只能捕获控件当前可见的区域,滚动条下方的内容根本没被渲染出来。咱们换个思路,不依赖控件自身的截图,而是手动遍历子控件并分页绘制,这样就能完整打印所有内容了。
问题根源
你的原代码里,FlowLayoutPanel的Height是当前显示的客户端区域高度,而非所有子控件排列后的总高度。DrawToBitmap只会绘制控件当前在屏幕上显示的部分,所以滚动区域的内容自然打不出来。
解决方案:分页遍历绘制子控件
核心思路是:
- 跟踪当前打印的位置,逐页绘制子控件
- 计算缩放比例,让内容适配打印页面宽度
- 逐个绘制每个子控件(包括Panel、TextBox、Label),确保所有内容都被捕获
下面是完整的实现代码:
首先在窗体类里定义两个变量,用来跟踪打印状态:
private int _currentPrintPositionY = 0; // 记录当前打印到的Y坐标(控件原始坐标) private float _printScaleFactor = 1f; // 内容缩放比例,适配页面宽度
然后是打印按钮的点击事件,这里加入了打印设置对话框,让用户可以选择打印机和调整页面:
private void btnsave_Click(object sender, EventArgs e) { _currentPrintPositionY = 0; // 每次打印前重置位置 PrintDocument doc = new PrintDocument(); doc.PrintPage += Doc_PrintPage; PrintDialog printDialog = new PrintDialog(); printDialog.Document = doc; if (printDialog.ShowDialog() == DialogResult.OK) { // 计算缩放比例:让FlowLayoutPanel的宽度刚好适配打印页面的可打印宽度 _printScaleFactor = printDialog.Document.DefaultPageSettings.PrintableArea.Width / flowlayoutpanel.Width; doc.Print(); } }
关键的PrintPage事件处理逻辑,负责分页绘制内容:
private void Doc_PrintPage(object sender, PrintPageEventArgs e) { var printableArea = e.PageSettings.PrintableArea; // 把页面高度转换为控件原始坐标的高度(因为我们要按控件实际大小计算分页) float pageHeightInControlCoords = printableArea.Height / _printScaleFactor; // 保存Graphics的原始状态,之后要恢复 var originalGraphicsState = e.Graphics.Save(); // 应用缩放和偏移,确保内容对齐页面的可打印区域 e.Graphics.ScaleTransform(_printScaleFactor, _printScaleFactor); e.Graphics.TranslateTransform( -printableArea.Left / _printScaleFactor, -printableArea.Top / _printScaleFactor ); // 遍历FlowLayoutPanel里的所有子控件,按顺序打印 foreach (Control control in flowlayoutpanel.Controls) { // 检查当前控件是否超出了当前页的范围 if (control.Bottom > _currentPrintPositionY + pageHeightInControlCoords) { // 这个控件跨页了,标记还有更多内容要打印,退出当前页的绘制 e.HasMorePages = true; break; } // 计算控件在当前页的绘制Y坐标(相对于当前页的顶部) int drawY = control.Top - _currentPrintPositionY; // 绘制当前控件:用DrawToBitmap完整捕获控件的所有内容(包括TextBox、Label的文本) using (Bitmap controlBitmap = new Bitmap(control.Width, control.Height)) { control.DrawToBitmap(controlBitmap, new Rectangle(0, 0, control.Width, control.Height)); e.Graphics.DrawImage(controlBitmap, control.Left, drawY); } // 更新当前打印位置到这个控件的底部 _currentPrintPositionY = control.Bottom; } // 恢复Graphics的原始状态,避免影响后续操作 e.Graphics.Restore(originalGraphicsState); // 如果所有内容都打印完了,重置打印位置 if (!e.HasMorePages) { _currentPrintPositionY = 0; } }
关键细节说明
- 分页逻辑:通过
_currentPrintPositionY跟踪已经打印的内容位置,每次打印一页时,只绘制当前页范围内的控件,超出的部分留到下一页。 - 缩放适配:计算
_printScaleFactor让FlowLayoutPanel的宽度刚好适配页面可打印宽度,避免内容被横向截断。 - 完整控件捕获:每个子控件单独用
DrawToBitmap绘制,确保TextBox、Label的文本和Panel的样式都被完整打印,不会遗漏。 - Graphics状态管理:保存和恢复Graphics的状态,避免缩放和偏移影响其他绘制操作。
这样修改后,就能完整打印FlowLayoutPanel的所有内容,包括滚动区域的部分,并且自动分页。
内容的提问来源于stack exchange,提问作者pol realestate
相关产品推荐
相关产品推荐

