E se il testo fosse lungo diverse pagine?
Come detto in precedenza si utilizza la proprietà e.HasMorePages; però è anche necessario valutare lo spazio che abbiamo a disposizione, per verificare se le righe che compongono il paragrafo che stiamo processando, possono essere inserite, o bisogna passare alla pagina successiva.
Si procede in questo modo:
Si preleva il testo da stampare, da un file e lo si inserisce in una stringa (Testo).
Attraverso un ciclo si scorre tutto il documento suddividendolo in paragrafi e depositandoli in una collection (ListaParagrafi) il cui contenuto sarà letto di volta in volta dalla stringa TestoM.
Ovviamente si devono definire il font (NuovoFont) e il tipo di formattazione per il nostro documento (CustomFormat). In questo caso abbiamo deciso per un allineamento a sinistra (StringAlignment.Near), e abbiamo imposto che, qualora in una riga una parola sia troppo lunga da inserire, essa debba essere scritta nella linea successiva (StringTrimming.Word), piuttosto che divisa a metà.
Inoltre per quanto riguarda l'ultima linea della pagina, abbiamo scelto di visualizzare solo righe intere (StringFormatFlags.LineLimit), in quanto può capitare che con una particolare dimensione di un font, la riga in questione venga disegnata per metà in una pagina e per metà nella successiva, impedendo al lettore di leggere correttamente quanto scritto.
A questo punto si può procedere con lo stampare il testo nella pagina.
Inizialmente lo spazio a disposizione (AreaDisponibile) è pari a tutto il foglio, esclusi i margini di stampa.
Si prendono i paragrafi uno alla volta e li misuriamo valutandone le dimensioni (DimensioneTesto) per potere capire quanto spazio occupano e in quale posizione (y) iniziare a scriverli. Vi sono due variabili, characters_fitted e line_filled che memorizzano il numero di caratteri inseriti e le linee occupate dal paragrafo, recuperabili, come riferimenti, dal metodo Graphics.MeasureString(...).
Se il paragrafo contiene dei caratteri significa che non è una linea vuota e che può essere disegnato, altrimenti si procede oltre. Finito di scrivere il paragrafo, si recupera dalla variabile characters_fitted, quanti caratteri sono stati effettivamente disegnati e la stringa che contiene il testo (TestoM) viene aggiornata perché contenga l'eventuale rimanenza di caratteri da stampare.
Questa è una situazione che si verifica soltanto quando viene processato un paragrafo che è prossimo alla fine della pagina. Se esso occupa una spazio maggiore di quello disponibile, si rende necessario dividerlo in due parti, da visualizzare alla fine di una pagina e all'inizio della successiva rispettivamente.
Se ciò accade, automaticamente viene valutata la proprietà e.HasMorePages e se risulta True, viene richiamato il metodo PrintDocument1_PrintPage1 per continuare la stampa in una nuova pagina, altrimenti si va avanti fino a quando finisce la pagina o finisce il documento.
Per concludere, nell'evento PrintDocument1_EndPrint1 si insericono le procedure per il rilascio delle risorse.
Imports System.Drawing.Printing Public Class Form1 'definizione di un button Private WithEvents Button1 As New Button 'definizione di un documento di stampa Private WithEvents PrintDocument1 As New PrintDocument 'definizione della finestra di dialogo "Anteprima" Private PrintPreviewDialog1 As New PrintPreviewDialog 'definizione di un nuovo font Private NuovoFont As Font 'definizione della variabile che contiene il testo Dim Testo As String 'definizione del formato del testo Dim CustomFormat As New StringFormat 'definizione dei paragrafi che compongono il testo Dim ListaParagrafi As Collection 'definizione del contatore per la collection paragrafi Dim conteggio As Integer 'inizializzazione dei componenti Form e Button Public Sub New() InitializeComponent() 'imposta la form Me.Size = New Size(210, 180) Me.Text = "Stampa Testo" 'imposta il button Button1.Size = New Size(100, 30) Button1.Location = New Point(51, 58) Button1.Text = "Anteprima" 'aggiunge il button alla form Me.Controls.Add(Button1) End Sub Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click 'anteprima di stampa del "documento" PrintPreviewDialog1.Document = PrintDocument1 PrintPreviewDialog1.Show() End Sub 'Inpostazioni iniziali prima dell'avvio del processo di stampa Private Sub PrintDocument1_BeginPrint1(ByVal sender As Object, ByVal e As _ System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint 'creazione di una nuova istanza di tipo collection ListaParagrafi = New Collection 'legge il testo contenuto nel file indicato Testo = My.Computer.FileSystem.ReadAllText("d:\documenti\Prova.txt") 'suddivide il testo in paragrafi e li inserisce nella collection ListaParagrafi Dim paragrafo As String = "" 'legge il testo carattere per carattere... For Each carattere As Char In Testo 'se il carattere corrisponde ad un'ANDATA A CAPO If carattere = vbLf Then 'aggiunge il paragrafo alla collection ListaParagrafi.Add(paragrafo) 'resetta il paragrafo paragrafo = "" Else 'aggiunge il carattere al paragrafo paragrafo += carattere End If Next 'aggiorna il conteggio dei paragrafi conteggio = ListaParagrafi.Count 'definisce il font NuovoFont = New Font("Arial", 20, FontStyle.Regular, GraphicsUnit.Pixel) 'allineamento orizzontale: vicino (near) al margine sinistro CustomFormat.Alignment = StringAlignment.Near 'Impone di visualizzare solo linee intere. Potrebbe accadere che l'ultima linea sia disegnata per metà alla fine 'di una pagina e per l'altra metà all'inizio della successiva; questa istruzione impone che siano disegnate solo 'linee intere CustomFormat.FormatFlags = StringFormatFlags.LineLimit 'Impone di visualizzare parole intere impedendo che siano troncate quando vengono stampate 'vicino alla fine della riga CustomFormat.Trimming = StringTrimming.Word End Sub Private Sub PrintDocument1_PrintPage1(ByVal sender As Object, ByVal e As _ System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage 'Area a disoposizione in cui è possibile scrivere il paragrafo che viene processato in quel momento Dim areaDisponibile As RectangleF 'dimensioni dello spazio occupato dal paragrafo quando viene valutato Dim dimensioniTesto As SizeF 'numero dei caratteri totali che compongono il paragrafo Dim characters_fitted As Integer 'linee occupate del paragrago in questione Dim line_filled As Integer 'coordinata y alla quale viene inserito il paragrafo in corso di scrittura Dim y As Integer = 0 'valore dell'indice della collection "ListaParagrafi" Dim indice As Integer 'stringa che contiene il testo modificato Dim TestoM As String Do While conteggio > 0 'se la posizione del prossimo paragrafo non ha ancora raggiunto il margine inferiore... If (y + e.MarginBounds.Top) < e.MarginBounds.Bottom Then 'definizione dell'AreaDisponibile areaDisponibile = New RectangleF(e.MarginBounds.Left, _ e.MarginBounds.Top + y, _ e.MarginBounds.Width, _ e.MarginBounds.Bottom - e.MarginBounds.Top - y) 'imposta l'indice della colection indice = ListaParagrafi.Count - conteggio + 1 'recupera il testo del paragrafo inserito nella colection TestoM = ListaParagrafi.Item(indice).ToString 'valutazione della dimensione del testo dimensioniTesto = e.Graphics.MeasureString(TestoM, _ NuovoFont, _ New SizeF(areaDisponibile.Width, areaDisponibile.Height), _ CustomFormat, characters_fitted, line_filled) 'se il paragrafo è composto da caratteri allora lo si scrive ( potrebbe essere una linea vuota...) If characters_fitted > 0 Then e.Graphics.DrawString(TestoM, _ NuovoFont, Brushes.Black, _ areaDisponibile, CustomFormat) y += CType(dimensioniTesto.Height, Integer) End If 'la variabile per il testo modificato contiene il documento rimanente qualora non vi sia stato spazio 'sufficiente per disegnare tutto il contenuto del paragrafo. 'Substring permette di recuperare il testo finale della stringa a partire dall'indice indicato. TestoM = TestoM.Substring(characters_fitted) 'se il testo modificato contiene caratteri allora vuol dire che siamo a fine pagina 'pertanto sostituiamo il paragrafo che stiamo valutando con il contenuto di TestoM 'quindi si esce dal ciclo Do...Loop If TestoM.Length > 0 Then 'rimozione del paragrafo originale ListaParagrafi.Remove(indice) 'riscrittura del nuovo paragarfo ListaParagrafi.Add(TestoM, , indice, ) Exit Do End If End If 'aggiorna il contatore conteggio -= 1 Loop 'quando arriviamo a fine pagina viene controllata e.HasMorePages per sapere se vi sono altri fogli da stampare 'e ciò avviene se il risultato è True. e.HasMorePages = (conteggio > 0) End Sub Private Sub PrintDocument1_EndPrint1(ByVal sender As Object, ByVal e As _ System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.EndPrint 'rilascia le risorse occupate dal testo NuovoFont.Dispose() NuovoFont = Nothing End Sub End Class