Introduzione:
Recentemente ho avuto la necessità di stampare su carta i dati raccolti in una DataGridView, perciò mi sono impegnato a capire come poter risolvere questo problema.
In rete ho trovato molto materiale che ho elaborato, modificato e riunito nel codice che vi propongo.
L'esempio di applicazione è un punto di partenza per riuscire ad ottenere la stampa di una tabella. Non ho introdotto algoritmi per la gestione delle eccezioni, né controlli sulla larghezza totale della tabella o del contenuto delle colonne.
Va da sé che la DataGridView deve occupare uno spazio uguale o inferiore all'area stampabile. Il codice così come è stato scritto funziona e può essere adattato alle esigenze di ognuno.
Il Codice:
Il processo di stampa è identificabile in 2 punti:
- Definizione e formattazione del documento da stampare.
- Esecuzione della stampa.
Generalmente si definisce un oggetto System.Drawing.Printing.PrintDocument che raccoglie tutte le istruzioni necessarie a stampare i nostri dati. Una volta definito questo oggetto, sarà sufficiente inviarlo alla stampante per avere una copia su carta della nostra DataGridView.
Avviamo un nuovo progetto Visual Basic .Net e digitiamo il codice seguente:
Public Class Form1 Private WithEvents Tabella As New System.Windows.Forms.DataGridView Private WithEvents btnStampa As New System.Windows.Forms.Button Private WithEvents docToPrint As New System.Drawing.Printing.PrintDocument Friend PrintDialog1 As New System.Windows.Forms.PrintDialog Private Sub StampaDataGridView_Load(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles Me.Load Me.Size = New Size(430, 300) ImpostaControlli() RiempiDataGridView() End Sub Private Sub ImpostaControlli() With (Tabella.ColumnHeadersDefaultCellStyle) .Font = New Font(Tabella.Font, FontStyle.Bold) .Alignment = DataGridViewContentAlignment.TopCenter End With With Tabella .Name = "dgv" .Size = New Size(400, 180) .ColumnCount = 4 .ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single .CellBorderStyle = DataGridViewCellBorderStyle.Single .GridColor = Color.Black .RowHeadersVisible = True .Dock = DockStyle.Top .Columns(0).Name = "Cognome" .Columns(0).Width = 80 .Columns(1).Name = "Nome" .Columns(1).Width = 80 .Columns(2).Name = "Telefono" .Columns(2).Width = 100 .Columns(3).Name = "Cellulare" .Columns(3).Width = 100 End With With btnStampa .Text = "Stampa" .Size = New Size(80, 30) .Location = New Point(175, 200) End With Me.Controls.Add(Tabella) Me.Controls.Add(Me.btnStampa) End Sub
Abbiamo inizializzato una form, una DataGridView e un Button e impostato le loro proprietà per una rappresentazione grafica dei nostri dati.
Notate che all'inizio della classe è stato definito un oggetto (docToPrint) che
rappresenta il nostro documento da impostare e inviare alla stampante.
Adesso popoliamo la nostra tabella con varie informazioni, per un totale di 66 righe, tanto per essere sicuri di occupare lo spazio di 2 pagine da stampare.
Private Sub RiempiDataGridView() Dim riga0 As String() = {"Rossi", "Mario", "123/456789", "0999/987654"} Dim riga1 As String() = {"Bianchi", "Carlo", "231/566889", "0111/998877"} Dim riga2 As String() = {"Neri", "Antonio", "321/445566", "0222/552469"} Dim riga3 As String() = {"Gialli", "Luisa", "132/696987", "0333/487962"} Dim riga4 As String() = {"Verdi", "Franca", "213/323539", "0444/1258974"} For i As Integer = 0 To 12 With Tabella.Rows .Add(riga0) .Add(riga1) .Add(riga2) .Add(riga3) .Add(riga4) End With Next End Sub
Scriviamo il codice relativo all'evento _Click del Pulsante "Stampa"
Private Sub btnStampa_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnStampa.Click PrintDialog1.Document = docToPrint If (PrintDialog1.ShowDialog) = Windows.Forms.DialogResult.OK Then docToPrint.Print() End Sub
Il nostro documento (docToPrint) viene associato a quello della finestra di dialogo Stampa per il recupero delle impostazioni che possono occorrere.
Se l'utente seleziona il pulsante OK della finestra di Stampa, il nostro documento viene processato e inviato alla stampante con le specifiche impostate nella stessa finestra di dialogo ( Tipo Stampante, Numero di copie...) e realizzato con quanto definito nel codice seguente:
Private Sub docToPrint_PrintPage(ByVal sender As Object, ByVal e As _ System.Drawing.Printing.PrintPageEventArgs) Handles docToPrint.PrintPage Dim posX As Integer Dim posY As Integer = e.MarginBounds.Top Dim Rettangolo As Rectangle Dim Altezza As Integer = Tabella.RowTemplate.Height Dim NormalFont As Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, FontStyle.Regular) Dim BoldFont As Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, FontStyle.Bold) Static righeStampate As Integer = 0 Static pagineStampate As Integer = 0 Dim righeTotali As Integer = Tabella.Rows.Count Dim righePerPagina As Integer = CType(e.MarginBounds.Height / Altezza, Integer) Dim nPagine As Integer If righeTotali Mod righePerPagina > 0 Then nPagine = (righeTotali \ righePerPagina) + 1 Else nPagine = (righeTotali \ righePerPagina) End If posX = CType((e.MarginBounds.Width - 360) / 2 + e.MarginBounds.Left, Integer) Dim dimensioneCella As System.Drawing.SizeF Dim incremento As Integer For Each colonna As DataGridViewColumn In Tabella.Columns dimensioneCella = e.Graphics.MeasureString(colonna.HeaderText.ToString, NormalFont) incremento = CType((colonna.Width - dimensioneCella.Width) / 2, Integer) Rettangolo = New Rectangle(posX, posY, colonna.Width, Altezza) e.Graphics.DrawRectangle(Pens.Black, Rettangolo) e.Graphics.DrawString(colonna.HeaderText, BoldFont, Brushes.Black, posX + incremento, posY + 5) posX += colonna.Width Next posY += Altezza Dim testo As String For i As Integer = righeStampate To righeStampate + righePerPagina - 2 posX = CType((e.MarginBounds.Width - 360) / 2 + e.MarginBounds.Left, Integer) If i = righeTotali - 1 Then e.HasMorePages = False Exit For End If For Each colonna As DataGridViewColumn In Tabella.Columns testo = Tabella.Rows(i).Cells(colonna.Name).Value.ToString dimensioneCella = e.Graphics.MeasureString(testo.ToString, NormalFont) incremento = CType((colonna.Width - dimensioneCella.Width) / 2, Integer) Rettangolo = New Rectangle(posX, posY, colonna.Width, Altezza) e.Graphics.DrawRectangle(Pens.Black, Rettangolo) e.Graphics.DrawString(testo, NormalFont, Brushes.Black, posX + incremento, posY + 5) posX += colonna.Width Next righeStampate += 1 posY += Altezza Next pagineStampate += 1 If pagineStampate < nPagine Then e.HasMorePages = True posY = e.MarginBounds.Top Else e.HasMorePages = False righeStampate = 0 pagineStampate = 0 End If End Sub End Class
E il gioco è fatto!