Tisk a zarovnání do bloku   zodpovězená otázka

VB.NET, WinForms, Tisk

Před několika lety jsem psal aplikaci pro tisk ještě pod VB6 a tam jsem vše řešil pomocí API funkcí, včetně zarovnání tištěného textu do bloku. Když chci nyní pro tisk použít funkce DrawText nebo DrawString nemohu najít možnost volby zarovnání tištěného textu do bloku. Někde jsem na to již narazil, ale nemohu to nyní najít. Poradí někdo?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jestli vám to pomůže tak já použil tuto třídu stáhnutou už nevím odkud :

Public Class WrapText
    Public Shared Function Wrap(ByVal Text As String, ByVal LineLength As Integer) As List(Of String)

        Dim ReturnValue As New List(Of String)
        ' Remove leading and trailing spaces
        Text = Trim(Text)


        Dim Words As String() = Text.Split(" ")

        If Words.Length = 1 And Words(0).Length > LineLength Then

            ' Text is just one big word that is longer than one line
            ' Split it mercilessly
            Dim lines As Integer = (Int(Text.Length / LineLength) + 1)
            Text = Text.PadRight(lines * LineLength)
            For i = 0 To lines - 1
                Dim SliceStart As Integer = i * LineLength
                ReturnValue.Add(Text.Substring(SliceStart, LineLength))
            Next
        Else
            Dim CurrentLine As New System.Text.StringBuilder
            For Each Word As String In Words
                ' will this word fit on the current line?
                If CurrentLine.Length + Word.Length < LineLength Then
                    CurrentLine.Append(Word & " ")
                Else
                    ' is the word too long for one line
                    If Word.Length > LineLength Then
                        ' hack off the first piece, fill out the current line and start a new line
                        Dim Slice As String = Word.Substring(0, LineLength - CurrentLine.Length)
                        CurrentLine.Append(Slice)
                        ReturnValue.Add(CurrentLine.ToString)
                        CurrentLine = New System.Text.StringBuilder

                        ' Remove the first slice from the word
                        Word = Word.Substring(Slice.Length, Word.Length - Slice.Length)

                        ' How many more lines do we need for this word?
                        Dim RemainingSlices As Integer = Int(Word.Length / LineLength) + 1
                        For LineNumber = 1 To RemainingSlices
                            If LineNumber = RemainingSlices Then

                                'this is the last slice
                                CurrentLine.Append(Word & " ")
                            Else
                                ' this is not the last slice
                                ' hack off a slice that is one line long, add that slice
                                ' to the output as a line and start a new line
                                Slice = Word.Substring(0, LineLength)
                                CurrentLine.Append(Slice)

                                ReturnValue.Add(CurrentLine.ToString)
                                CurrentLine = New System.Text.StringBuilder()

                                ' Remove the slice from the Word()
                                Word = Word.Substring(Slice.Length, Word.Length - Slice.Length)
                            End If
                        Next
                    Else
                        ' finish the current line and start a new one with the wrapped word
                        ReturnValue.Add(CurrentLine.ToString)
                        CurrentLine = New System.Text.StringBuilder(Word & " ")
                    End If
                End If
            Next

            ' Write the last line to the output
            If CurrentLine.Length > 0 Then
                ReturnValue.Add(CurrentLine.ToString)
            End If
        End If
        Return ReturnValue
    End Function
End Class

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tato třída dělá v principu to, že text rozloží na jednotlivá slova a znovu je poskládá tak, aby délka odpovídala délce jednoho řádku. Tyto jednotlivé řádky potom vrací jako List. Stejně funguje funkce Graphics.DrawString s TextFormatFlags.WordBreak.

Já potřebuji použít API funkci SetTextJustification pro zvětšení mezer mezi jednotlivými slovy, ale to budu muset asi řešit tisk mimo .NET.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

To DrawString má poměrně dost možností nastavení, zkuste to pořádně prozkoumat.

Zrovna zalamování do bloku by měla umět sama, jestli se nemýlím.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak nakonec si odpovím sám a dám sem kousek kódu, který jsem si upravil pro své potřeby

Imports System.Drawing
Imports System.Text
Imports System.Collections.Specialized

Public Class PrintUtils

    Public Enum align_text
        left = 0
        center
        right
        justify
    End Enum

    ''' <summary>
    ''' Rozdělí řetězec na jednotlivé řádky tak, aby se svou délkou vešly do zadaného obdélníka
    ''' </summary>
    ''' <param name="text">Vstupní řetězec</param>
    ''' <param name="maxWidth">Šířka řádku, do kterého se má řetězec zalamovat</param>
    ''' <param name="g">Objekt typu Graphics, na němž se má řetězec vypsat</param>
    ''' <param name="font">Písmo, jímž bude řetězec vypsán</param>
    ''' <returns>Vrátí kolekci řetězců, která obsahuje jednotlivé řádky, které svou délkou odpovídají požadované šířce řádku</returns>
    Public Shared Function WordWrapString(ByVal text As String, ByVal maxWidth As Integer, ByVal g As Graphics, ByVal font As Font) As StringCollection
        ' Vytvoření objektu typu StringCollection pro jednotlivé řádky
        Dim wrappedText As New StringCollection()

        ' Objekt typu StringFormat pro zjištění šířky jednotlivých tokenů představujících slova 
        Dim stringFormat__1 As StringFormat = StringFormat.GenericTypographic
        ' Nastavení správného zahrnutí mezer do vypočítávané šířky textu
        stringFormat__1.FormatFlags = StringFormatFlags.MeasureTrailingSpaces
        If text IsNot Nothing AndAlso text.Length > 0 Then
            ' Odstranění případných konců řádků
            text = text.Replace(Environment.NewLine, " ")
            ' rozdělit text podle mezer na jednotlivá slova a zpracovat na jednotlivé řádky
            Dim words() As String = Split(text, " ")
            Dim row As String = Nothing
            Dim curW As Single
            For Each word As String In words
                If g.MeasureString(row & word, font, 0, stringFormat__1).Width <= maxWidth Then
                    row &= word & " "
                Else
                    wrappedText.Add(Trim(row))
                    row = word & " "
                    curW = 0
                End If
            Next
            If row IsNot Nothing Then wrappedText.Add(Trim(row))
        End If
        ' Vrácení výsledku 
        Return wrappedText
    End Function

    ''' <summary>
    ''' Tiskne text do zadaného obdélníka. Na základě parametru 'align' je tištěný text zarovnán k levému nebo pravému okraji, vycentrován nebo zarovnán do bloku.
    ''' </summary>
    ''' <param name="text">Text, který se bude tisknout</param>
    ''' <param name="rect">Obdélník, do kterého se bude tisknout</param>
    ''' <param name="g">Objekt typu Graphics, na němž se text vypíše</param>
    ''' <param name="font">Font, kterým bude tedxt vypsán</param>
    ''' <param name="align">Parametr o použitém zarovnání</param>
    ''' <remarks>Vrací souřadnice pravého horního rohu, na kterém byl ukončen tisk</remarks>
    Public Shared Function PrintText(ByVal text As String, ByVal rect As RectangleF, ByVal g As Graphics, ByVal font As Font, ByVal align As align_text) As PointF
        Dim s As SizeF
        Dim p As New PointF(rect.X, rect.Y)
        Dim stringFormat__1 As StringFormat = StringFormat.GenericTypographic
        ' Správné započítávání mezer při výpočtu šířky textu
        stringFormat__1.FormatFlags = StringFormatFlags.MeasureTrailingSpaces
        ' Rozdělení textu na jednotlivé řádky
        Dim sc As StringCollection = WordWrapString(text, rect.Width, g, font)
        ' Vytisknout text podle požadovaného zarovnání
        Select Case align
            Case align_text.left
                stringFormat__1.Alignment = StringAlignment.Near
                For Each row As String In sc
                    g.DrawString(text, font, Brushes.Black, rect, stringFormat__1)
                Next
            Case align_text.center
                stringFormat__1.Alignment = StringAlignment.Center
                For Each row As String In sc
                    g.DrawString(text, font, Brushes.Black, rect, stringFormat__1)
                Next
            Case align_text.right
                stringFormat__1.Alignment = StringAlignment.Far
                For Each row As String In sc
                    g.DrawString(text, font, Brushes.Black, rect, stringFormat__1)
                Next
            Case align_text.justify
                ' Základní zarovnání vlevo pro tisk krátkých řádků
                stringFormat__1.Alignment = StringAlignment.Near
                For Each row As String In sc
                    ' Rozdělení řádku na jednotlivá slova
                    Dim sa() As String = row.Split(" ")
                    ' Zjištění počtu mezer
                    Dim spc As Integer = sa.Count - 1
                    ' Zjištění skutečné šířky textu v řádku
                    s = g.MeasureString(row, font, 0, stringFormat__1)
                    ' Výpočet šířky mezery mezi jednotlivými slovy
                    Dim spw As Single = ((rect.Width - s.Width) / spc) + g.MeasureString(" ", font, 0, stringFormat__1).Width
                    ' Pokud je šířka řádku větší než 80% požadované šířky, zarovnat do bloku
                    If s.Width > (rect.Width * 0.8) Then
                        For i As Integer = 0 To sa.Count - 1
                            ' Vytiskne jedno slovo
                            g.DrawString(sa(i), font, Brushes.Black, p, stringFormat__1)
                            ' Zjistí šířku vytisknutého slova
                            s = g.MeasureString(sa(i), font, p, stringFormat__1)
                            ' Posune souřednice v ose X o šířku slova a šířku mezery
                            p.X += s.Width + spw
                        Next
                        ' Nastaví osu X na začátek řádku
                        p.X = rect.X
                        ' Nastaví osu Y o výšku řádku
                        p.Y += s.Height
                    Else
                        ' Vytiskne celý řádek, protože jeho délka je menší než 80% požadované šířky
                        g.DrawString(row, font, Brushes.Black, p, stringFormat__1)
                        s = g.MeasureString(row, font, p, stringFormat__1)
                        p.X += s.Width
                    End If
                Next

        End Select
        Return p
    End Function

End Class

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Objevil jsem chybu v tomto místě

Dim spw As Single = ((rect.Width - s.Width) / spc) + g.MeasureString(" ", font, 0, stringFormat__1).Width

Oprava má tvar

Dim spw As Single = ((rect.Width - s.Width) / spc) + (g.MeasureString("a a", font, 0, stringFormat__1).Width - 
g.MeasureString("aa", font, 0, stringFormat__1).Width)

Při některých použitích docházelo ke špatnému určení šířky mezery

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback