【问题标题】:Printing DataGridView from Right to Left从右到左打印 DataGridView
【发布时间】:2017-02-21 23:16:43
【问题描述】:

我是 vb.net 打印的新手,我想做的是打印 DataGridView 项目 我在网上搜索了代码,我从MSDN 找到了这个源,代码工作完美,但我想要的是从右到左打印DataGridView,我该怎么做。 谢谢。

这是我从Printing DataGridView Example得到的源代码:

Public Class Form1 

    ''' <summary> 
    ''' structire to hold printed page details 
    ''' </summary> 
    ''' <remarks></remarks> 
    Private Structure pageDetails 
        Dim columns As Integer 
        Dim rows As Integer 
        Dim startCol As Integer 
        Dim startRow As Integer 
    End Structure 
    ''' <summary> 
    ''' dictionary to hold printed page details, with index key 
    ''' </summary> 
    ''' <remarks></remarks> 
    Private pages As Dictionary(Of Integer, pageDetails) 

    Dim maxPagesWide As Integer 
    Dim maxPagesTall As Integer 

    ''' <summary> 
    ''' this just loads some text values into the dgv 
    ''' </summary> 
    ''' <param name="sender"></param> 
    ''' <param name="e"></param> 
    ''' <remarks></remarks> 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
        DataGridView1.RowHeadersWidth = CInt(DataGridView1.RowHeadersWidth * 1.35) 
        For r As Integer = 1 To 100 
            Dim y As Integer = r 
            Dim fmt As String = "R{0}C{1}" 
            DataGridView1.Rows.Add() 
            DataGridView1.Rows(r - 1).SetValues(Enumerable.Range(1, 10).Select(Function(x) String.Format(fmt, y, x)).ToArray) 
            DataGridView1.Rows(r - 1).HeaderCell.Value = r.ToString 
        Next 
    End Sub 

    ''' <summary> 
    ''' shows a PrintPreviewDialog 
    ''' </summary> 
    ''' <param name="sender"></param> 
    ''' <param name="e"></param> 
    ''' <remarks></remarks> 
    Private Sub btnPreview_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPreview.Click 
        Dim ppd As New PrintPreviewDialog 
        ppd.Document = PrintDocument1 
        ppd.WindowState = FormWindowState.Maximized 
        ppd.ShowDialog() 
    End Sub 

    ''' <summary> 
    ''' starts print job 
    ''' </summary> 
    ''' <param name="sender"></param> 
    ''' <param name="e"></param> 
    ''' <remarks></remarks> 
    Private Sub btnPrint_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPrint.Click 
        PrintDocument1.Print() 
    End Sub 

    ''' <summary> 
    ''' the majority of this Sub is calculating printed page ranges 
    ''' </summary> 
    ''' <param name="sender"></param> 
    ''' <param name="e"></param> 
    ''' <remarks></remarks> 
    Private Sub PrintDocument1_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint 
        ''this removes the printed page margins 
        PrintDocument1.OriginAtMargins = True 
        PrintDocument1.DefaultPageSettings.Margins = New Drawing.Printing.Margins(0, 0, 0, 0) 

        pages = New Dictionary(Of Integer, pageDetails) 

        Dim maxWidth As Integer = CInt(PrintDocument1.DefaultPageSettings.PrintableArea.Width) - 40 
        Dim maxHeight As Integer = CInt(PrintDocument1.DefaultPageSettings.PrintableArea.Height) - 40 + Label1.Height 

        Dim pageCounter As Integer = 0 
        pages.Add(pageCounter, New pageDetails) 

        Dim columnCounter As Integer = 0 

        Dim columnSum As Integer = DataGridView1.RowHeadersWidth 

        For c As Integer = 0 To DataGridView1.Columns.Count - 1 
            If columnSum + DataGridView1.Columns(c).Width < maxWidth Then 
                columnSum += DataGridView1.Columns(c).Width 
                columnCounter += 1 
            Else 
                pages(pageCounter) = New pageDetails With {.columns = columnCounter, .rows = 0, .startCol = pages(pageCounter).startCol} 
                columnSum = DataGridView1.RowHeadersWidth + DataGridView1.Columns(c).Width 
                columnCounter = 1 
                pageCounter += 1 
                pages.Add(pageCounter, New pageDetails With {.startCol = c}) 
            End If 
            If c = DataGridView1.Columns.Count - 1 Then 
                If pages(pageCounter).columns = 0 Then 
                    pages(pageCounter) = New pageDetails With {.columns = columnCounter, .rows = 0, .startCol = pages(pageCounter).startCol} 
                End If 
            End If 
        Next 

        maxPagesWide = pages.Keys.Max + 1 

        pageCounter = 0 

        Dim rowCounter As Integer = 0 

        Dim rowSum As Integer = DataGridView1.ColumnHeadersHeight 

        For r As Integer = 0 To DataGridView1.Rows.Count - 2 
            If rowSum + DataGridView1.Rows(r).Height < maxHeight Then 
                rowSum += DataGridView1.Rows(r).Height 
                rowCounter += 1 
            Else 
                pages(pageCounter) = New pageDetails With {.columns = pages(pageCounter).columns, .rows = rowCounter, .startCol = pages(pageCounter).startCol, .startRow = pages(pageCounter).startRow} 
                For x As Integer = 1 To maxPagesWide - 1 
                    pages(pageCounter + x) = New pageDetails With {.columns = pages(pageCounter + x).columns, .rows = rowCounter, .startCol = pages(pageCounter + x).startCol, .startRow = pages(pageCounter).startRow} 
                Next 

                pageCounter += maxPagesWide 
                For x As Integer = 0 To maxPagesWide - 1 
                    pages.Add(pageCounter + x, New pageDetails With {.columns = pages(x).columns, .rows = 0, .startCol = pages(x).startCol, .startRow = r}) 
                Next 

                rowSum = DataGridView1.ColumnHeadersHeight + DataGridView1.Rows(r).Height 
                rowCounter = 1 
            End If 
            If r = DataGridView1.Rows.Count - 2 Then 
                For x As Integer = 0 To maxPagesWide - 1 
                    If pages(pageCounter + x).rows = 0 Then 
                        pages(pageCounter + x) = New pageDetails With {.columns = pages(pageCounter + x).columns, .rows = rowCounter, .startCol = pages(pageCounter + x).startCol, .startRow = pages(pageCounter + x).startRow} 
                    End If 
                Next 
            End If 
        Next 

        maxPagesTall = pages.Count \ maxPagesWide 

    End Sub 

    ''' <summary> 
    ''' this is the actual printing routine. 
    ''' using the pagedetails i calculated earlier, it prints a title, 
    ''' + as much of the datagridview as will fit on 1 page, then moves to the next page. 
    ''' this is setup to be dynamic. try resizing the dgv columns or rows 
    ''' </summary> 
    ''' <param name="sender"></param> 
    ''' <param name="e"></param> 
    ''' <remarks></remarks> 
    Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage 
        Dim rect As New Rectangle(20, 20, CInt(PrintDocument1.DefaultPageSettings.PrintableArea.Width), Label1.Height) 
        Dim sf As New StringFormat 
        sf.Alignment = StringAlignment.Center 
        sf.LineAlignment = StringAlignment.Center 

        e.Graphics.DrawString(Label1.Text, Label1.Font, Brushes.Black, rect, sf) 

        sf.Alignment = StringAlignment.Near 

        Dim startX As Integer = 50 
        Dim startY As Integer = rect.Bottom 

        Static startPage As Integer = 0 

        For p As Integer = startPage To pages.Count - 1 
            Dim cell As New Rectangle(startX, startY, DataGridView1.RowHeadersWidth, DataGridView1.ColumnHeadersHeight) 
            e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell) 
            e.Graphics.DrawRectangle(Pens.Black, cell) 

            startY += DataGridView1.ColumnHeadersHeight 

            For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1 
                cell = New Rectangle(startX, startY, DataGridView1.RowHeadersWidth, DataGridView1.Rows(r).Height) 
                e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell) 
                e.Graphics.DrawRectangle(Pens.Black, cell) 
                e.Graphics.DrawString(DataGridView1.Rows(r).HeaderCell.Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf) 
                startY += DataGridView1.Rows(r).Height 
            Next 

            startX += cell.Width 
            startY = rect.Bottom 

            For c As Integer = pages(p).startCol To pages(p).startCol + pages(p).columns - 1 
                cell = New Rectangle(startX, startY, DataGridView1.Columns(c).Width, DataGridView1.ColumnHeadersHeight) 
                e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell) 
                e.Graphics.DrawRectangle(Pens.Black, cell) 
                e.Graphics.DrawString(DataGridView1.Columns(c).HeaderCell.Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf) 
                startX += DataGridView1.Columns(c).Width 
            Next 

            startY = rect.Bottom + DataGridView1.ColumnHeadersHeight 

            For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1 
                startX = 50 + DataGridView1.RowHeadersWidth 
                For c As Integer = pages(p).startCol To pages(p).startCol + pages(p).columns - 1 
                    cell = New Rectangle(startX, startY, DataGridView1.Columns(c).Width, DataGridView1.Rows(r).Height) 
                    e.Graphics.DrawRectangle(Pens.Black, cell) 
                    e.Graphics.DrawString(DataGridView1(c, r).Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf) 
                    startX += DataGridView1.Columns(c).Width 
                Next 
                startY += DataGridView1.Rows(r).Height 
            Next 

            If p <> pages.Count - 1 Then 
                startPage = p + 1 
                e.HasMorePages = True 
                Return 
            Else 
                startPage = 0 
            End If 

        Next 

    End Sub 

End Class 

【问题讨论】:

  • 当您可以简单地使用RDLC 报告打印DataGridView,为什么要使用GDI+ 代码打印DataGridView
  • 如果由于某种原因您不能/不想使用 rdlc 报告,您可以使用包含 html 代码的运行时 t4 模板以更友好/灵活的方式打印您的数据模型比使用 GDI+。看看this example
  • 因为我对 RDLC 报告一无所知,所以它不可能而且容易??我需要在客户端机器上安装 RDLC 报告吗?
  • 选择权在你,或许你更了解自己的需求。但是使用 clickonce 或任何其他安装程序部署 RDLC 报告非常简单,并且为此类任务创建了报告工具。
  • 无论如何要使打印 RTL,您需要在发布的代码中进行一些更改,例如所有 DrawString 方法,应使用 StringFormatStringFormatFlags.DirectionRightToLeft。此外,您应该更正坐标以支持从右到左的绘制,而不是从左到右绘制矩形。耐心地纠正这些问题是完全可能的。但 rdlc 解决方案要好得多。

标签: .net vb.net winforms datagridview printdocument


【解决方案1】:

要使打印 RTL,您需要对发布的代码进行一些更改

  1. 您应该使用具有StringFormatFlags.DirectionRightToLeft 格式的StringFormat
  2. 此外,您应该更正坐标以支持从右到左的绘制,而不是从左到右绘制矩形。

要解决第一个问题,将提到的标志添加到字符串格式就足够了:

sf.FormatFlags = sf.FormatFlags Or StringFormatFlags.DirectionRightToLeft

要解决第二个问题,你应该创建这样的方法:

Public Function GetRTLCoordinates(container As Rectangle, drawRectangle As Rectangle) _
    As Rectangle
    Return New Rectangle(container.Width - drawRectangle.Width - drawRectangle.X, _
        drawRectangle.Y, drawRectangle.Width, drawRectangle.Height)
End Function

然后在代码中,在每行代码计算出一个名为单元格的矩形之后,添加这行代码:

cell = GetRTLCoordinates(rect, cell)

代码

这是PrintDocument1_PrintPage 方法的更改版本。不要忘记复制上面提到的GetRTLCoordinates方法。

Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    Dim rect As New Rectangle(20, 20, CInt(PrintDocument1.DefaultPageSettings.PrintableArea.Width), Label1.Height)
    Dim sf As New StringFormat
    sf.Alignment = StringAlignment.Center
    sf.LineAlignment = StringAlignment.Center
    sf.FormatFlags = sf.FormatFlags Or StringFormatFlags.DirectionRightToLeft

    e.Graphics.DrawString(Label1.Text, Label1.Font, Brushes.Black, rect, sf)

    sf.Alignment = StringAlignment.Near

    Dim startX As Integer = 50
    Dim startY As Integer = rect.Bottom

    Static startPage As Integer = 0

    For p As Integer = startPage To pages.Count - 1
        Dim cell As New Rectangle(startX, startY, DataGridView1.RowHeadersWidth, DataGridView1.ColumnHeadersHeight)
        cell = GetRTLCoordinates(rect, cell)
        e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell)
        e.Graphics.DrawRectangle(Pens.Black, cell)

        startY += DataGridView1.ColumnHeadersHeight

        For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1
            cell = New Rectangle(startX, startY, DataGridView1.RowHeadersWidth, DataGridView1.Rows(r).Height)
            cell = GetRTLCoordinates(rect, cell)
            e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell)
            e.Graphics.DrawRectangle(Pens.Black, cell)
            e.Graphics.DrawString(DataGridView1.Rows(r).HeaderCell.Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf)
            startY += DataGridView1.Rows(r).Height
        Next

        startX += cell.Width
        startY = rect.Bottom

        For c As Integer = pages(p).startCol To pages(p).startCol + pages(p).columns - 1
            cell = New Rectangle(startX, startY, DataGridView1.Columns(c).Width, DataGridView1.ColumnHeadersHeight)
            cell = GetRTLCoordinates(rect, cell)
            e.Graphics.FillRectangle(New SolidBrush(SystemColors.ControlLight), cell)
            e.Graphics.DrawRectangle(Pens.Black, cell)
            e.Graphics.DrawString(DataGridView1.Columns(c).HeaderCell.Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf)
            startX += DataGridView1.Columns(c).Width
        Next

        startY = rect.Bottom + DataGridView1.ColumnHeadersHeight

        For r As Integer = pages(p).startRow To pages(p).startRow + pages(p).rows - 1
            startX = 50 + DataGridView1.RowHeadersWidth
            For c As Integer = pages(p).startCol To pages(p).startCol + pages(p).columns - 1
                cell = New Rectangle(startX, startY, DataGridView1.Columns(c).Width, DataGridView1.Rows(r).Height)
                cell = GetRTLCoordinates(rect, cell)
                e.Graphics.DrawRectangle(Pens.Black, cell)
                e.Graphics.DrawString(DataGridView1(c, r).Value.ToString, DataGridView1.Font, Brushes.Black, cell, sf)
                startX += DataGridView1.Columns(c).Width
            Next
            startY += DataGridView1.Rows(r).Height
        Next

        If p <> pages.Count - 1 Then
            startPage = p + 1
            e.HasMorePages = True
            Return
        Else
            startPage = 0
        End If

    Next

End Sub

【讨论】:

  • 这太棒了,我也在阅读报告查看器,它很有趣,真的谢谢你,你是最好的人:)
  • 不客气 :) - 干得好,我发布了修复,因为它似乎是 MSDN 中的一个流行示例。
  • 你好,我想问你一些关于报表查看器的问题,我正在尝试创建新报表,我已经添加了报表查看器 dll 文件但是当我尝试添加报表时我找不到分类报告见picture 1,一定是这样picture 2要我问新问题吗??
  • @Rabeeaqabaha 嗯,它为我显示了报告类别。此外,如果我选择可视 C# 项目(我在您的屏幕截图中看不到),它会在中间列表的项目之间显示报告。我使用的是 Visual Studio 2013,在 2010 年也是一样的。此外,我还没有添加 dll 或任何东西。安装 Visual Studio 后,默认情况下它就在那里。你的 Visual Studio 版本是多少?顺便说一句,嗨。
  • Hii :) 是的,这很奇怪,我使用的是 Visual Studio 2015 Enterprise,在添加 Dll 文件之前没有 Report Viewer 控件,现在有 Control 但我在类别中找不到它,我会尝试重新安装它。
猜你喜欢
  • 2017-07-22
  • 1970-01-01
  • 2012-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-12
  • 2014-05-18
相关资源
最近更新 更多