You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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;
    }
}

关键细节说明

  1. 分页逻辑:通过_currentPrintPositionY跟踪已经打印的内容位置,每次打印一页时,只绘制当前页范围内的控件,超出的部分留到下一页。
  2. 缩放适配:计算_printScaleFactor让FlowLayoutPanel的宽度刚好适配页面可打印宽度,避免内容被横向截断。
  3. 完整控件捕获:每个子控件单独用DrawToBitmap绘制,确保TextBox、Label的文本和Panel的样式都被完整打印,不会遗漏。
  4. Graphics状态管理:保存和恢复Graphics的状态,避免缩放和偏移影响其他绘制操作。

这样修改后,就能完整打印FlowLayoutPanel的所有内容,包括滚动区域的部分,并且自动分页。

内容的提问来源于stack exchange,提问作者pol realestate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:27:41