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

如何将DataGridView打印预览内容保存为图片

将打印预览内容保存为图片的解决方案

你的需求是复用现有打印逻辑(包含Logo、样式化表格)生成图片,而非直接导出DataGridView控件本身。以下是实现方案:

核心思路

把原本绘制到打印页面的逻辑,改为绘制到内存中的Bitmap对象,最终将Bitmap保存为图片文件。这样能保证生成的图片和打印预览内容完全一致。

实现步骤

  1. 提取绘制逻辑为独立方法:将原有打印事件中的绘制代码抽离,接收Graphics对象作为参数,同时兼容打印和图片生成场景。
  2. 创建Bitmap模拟打印页面:根据打印页面的尺寸(如A4)创建对应大小的Bitmap,获取其Graphics上下文。
  3. 调用绘制方法生成内容:把Bitmap的Graphics传入提取的方法,完成内容绘制。
  4. 保存Bitmap为图片:将生成的Bitmap保存为PNG/JPG等格式文件。

完整代码实现

第一步:提取通用绘制方法

Private Sub DrawPrintContent(g As Graphics, pageBounds As Rectangle, marginBounds As Rectangle, ByRef startRow As Integer, ByRef pageCounter As Integer)
    Dim addressFont As New Font(dgvWarehouse.Font.FontFamily, 10, FontStyle.Regular, GraphicsUnit.Pixel)
    Dim logoImage As Image = CType(My.Resources.ResourceManager.GetObject("logo1"), Image)
    g.DrawImage(logoImage, CInt((pageBounds.Width - 800) / 2), 10, 300, 180)
    
    Dim companyname As String = "Sample"
    Dim address As String = "Sample"
    Dim number As String = "Sample"
    Dim email As String = "Sample"
    ' 注意:确保CompanyFont已在代码中定义,若未定义需补充声明
    g.DrawString(companyname, CompanyFont, Brushes.Black, CSng(pageBounds.Width - 1100 / 2), 60)
    g.DrawString(address, addressFont, Brushes.Black, CSng(pageBounds.Width - 1100 / 2), 90)
    g.DrawString(number, addressFont, Brushes.Black, CSng(pageBounds.Width - 1100 / 2), 105)
    g.DrawString(email, addressFont, Brushes.Black, CSng(pageBounds.Width - 1100 / 2), 120)

    Dim headerFont As New Font(dgvWarehouse.Font.FontFamily, 15, FontStyle.Italic, GraphicsUnit.Pixel)
    Dim actualWidth As Integer = dgvWarehouse.Columns.Cast(Of DataGridViewColumn).Sum(Function(c) c.Width)
    Dim percentage As Decimal = CDec(((100 / actualWidth) * marginBounds.Width) / 100)
    Dim header As String = "Warehouse Inventory"
    Dim footer As String
    Dim startX As Integer = marginBounds.Left - 30
    Dim startY As Integer = marginBounds.Top
    Dim r As Rectangle

    Dim szf As SizeF = g.MeasureString(header, headerFont)
    g.DrawString(header, headerFont, Brushes.Black, marginBounds.Left + (marginBounds.Width - szf.Width) / 2, startY - (r.Height - 80))
    footer = "Page " & pageCounter.ToString
    szf = g.MeasureString(footer, headerFont)
    g.DrawString(footer, headerFont, Brushes.Black, marginBounds.Left + (marginBounds.Width - szf.Width) / 2, marginBounds.Bottom + 5)

    startY += 100

    Dim sf As New StringFormat
    sf.Alignment = StringAlignment.Center
    sf.LineAlignment = StringAlignment.Center

    Dim gridFont As New Font(dgvWarehouse.Font.FontFamily, dgvWarehouse.Font.Size, FontStyle.Regular, GraphicsUnit.Pixel)

    ' 绘制表格表头
    For x As Integer = 0 To dgvWarehouse.Columns.Count - 1
        r.X = startX
        r.Y = startY
        r.Width = CInt((dgvWarehouse.Columns(x).Width + 15) * percentage)
        r.Height = dgvWarehouse.Rows(0).Height
        dgvWarehouse.Columns(x).HeaderCell.Style.BackColor = Color.Gray
        g.FillRectangle(New SolidBrush(dgvWarehouse.Columns(x).HeaderCell.Style.BackColor), r)
        g.DrawRectangle(Pens.Black, r)
        g.DrawString(dgvWarehouse.Columns(x).HeaderText, gridFont, Brushes.White, r, sf)
        startX += r.Width
    Next

    startY += r.Height

    ' 绘制表格内容行
    For y As Integer = startRow To dgvWarehouse.Rows.Count - 1
        If y = dgvWarehouse.NewRowIndex Then Continue For
        startX = marginBounds.Left
        For x As Integer = 0 To dgvWarehouse.Columns.Count - 1
            r.X = startX - 30
            r.Y = startY
            r.Width = CInt((dgvWarehouse.Columns(x).Width + 15) * percentage)
            r.Height = dgvWarehouse.Rows(0).Height
            g.DrawRectangle(Pens.Black, r)
            g.DrawString(If(Not dgvWarehouse.Rows(y).Cells(x).Value Is Nothing, dgvWarehouse.Rows(y).Cells(x).Value.ToString, ""),
                            gridFont, Brushes.Black, r, sf)

            startX += r.Width
        Next
        startY += r.Height
        If startY >= marginBounds.Bottom - 10 Then
            If y < dgvWarehouse.Rows.Count - 1 Then
                startRow = y + 1
                pageCounter += 1
                Exit For
            End If
        End If
    Next

    ' 释放资源,避免内存泄漏
    addressFont.Dispose()
    headerFont.Dispose()
    gridFont.Dispose()
    sf.Dispose()
    logoImage.Dispose()
End Sub

第二步:添加生成并保存图片的方法

Private Sub SavePrintContentAsImage()
    ' 模拟A4纸尺寸(96 DPI),可根据实际打印设置调整
    Dim pageWidth As Integer = CInt(8.5 * 96)
    Dim pageHeight As Integer = CInt(11 * 96)
    Dim pageBounds As New Rectangle(0, 0, pageWidth, pageHeight)
    ' 模拟打印边距,与打印设置保持一致
    Dim marginBounds As New Rectangle(50, 50, pageWidth - 100, pageHeight - 100)

    ' 创建Bitmap对象
    Using bmp As New Bitmap(pageWidth, pageHeight)
        Using g As Graphics = Graphics.FromImage(bmp)
            ' 设置绘图质量,匹配打印效果
            g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
            g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
            g.Clear(Color.White) ' 设置背景为白色

            Dim startRow As Integer = 0
            Dim pageCounter As Integer = 1
            ' 调用绘制方法生成内容
            DrawPrintContent(g, pageBounds, marginBounds, startRow, pageCounter)

            ' 处理多页:若内容有多页,可循环调用DrawPrintContent,更新startRow和pageCounter,保存为不同文件
            ' 示例仅生成第一页,多页场景可自行扩展循环逻辑

            ' 保存图片到指定路径
            bmp.Save("C:\Temp\WarehouseInventory_Page1.png", Imaging.ImageFormat.Png)
            MessageBox.Show("图片已成功保存!")
        End Using
    End Using
End Sub

关键注意事项

  • 资源释放:所有实现IDisposable的对象(如Font、Image、StringFormat)需调用Dispose()或用Using语句包裹,避免内存泄漏。
  • 多页处理:如果打印内容超过一页,可通过循环调用DrawPrintContent,每次更新startRow和pageCounter,并将每页保存为单独的图片文件。
  • 尺寸匹配:确保Bitmap的尺寸和打印页面尺寸一致,这样生成的图片比例才会和预览完全相同。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 10:55:16