Click here to Skip to main content
15,886,199 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
I want to print a text "AAA". First i print "A" then i measure the text width to get x position for next text like this. When i print in this way, it will give some gap between texts. How to solve?

What I have tried:

Public Class Form1
    Private TMPbmp As New Bitmap(1, 1)
    Private TMPgfx As Graphics = Graphics.FromImage(TMPbmp)
    Private TxtSize As SizeF
    Public prnDocument As New System.Drawing.Printing.PrintDocument
    Public WithEvents prnPreview As New System.Windows.Forms.PrintPreviewDialog
    Private egraphics As Graphics
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Click
        AddHandler prnDocument.PrintPage, AddressOf prnDocument_PrintPage
        prnPreview.Document = prnDocument
        prnPreview.WindowState = FormWindowState.Maximized
        prnPreview.ShowDialog()
    End Sub
    Private Sub prnDocument_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
        Dim lalign As New StringFormat
        egraphics = e.Graphics
        egraphics.PageUnit = GraphicsUnit.Point
        lalign.Alignment = StringAlignment.Near

        Dim lwi As Single = TextWidth("A", New Font("Arial", 19))
        egraphics.DrawString("A", New Font("Arial", 19), New SolidBrush(Color.Black), 10, 50, lalign)
        egraphics.DrawString("A", New Font("Arial", 19), New SolidBrush(Color.Black), 10 + lwi, 50, lalign)
        eGraphics.DrawString("A", New Font("Arial", 19), New SolidBrush(Color.Black), 10 + lwi + lwi, 50, lalign)
    End Sub
    Public Function TextWidth(ByVal Matter As String, ByVal pFont As System.Drawing.Font) As Single
        TMPgfx.PageUnit = GraphicsUnit.Point
        TxtSize = TMPgfx.MeasureString(Matter, pFont)
        TextWidth = TxtSize.Width
    End Function
End Class
Posted
Updated 11-Dec-17 4:52am

Nobody else pointed out that you're code will leak resource and eventually crash Windows.

Those Font and Brush objects you're newing up need to have Dispose called on them to free up GDI resources. You cannot just new them up "fire and forget" style.

A much cleaner version of the code would look something like this:
VB.NET
Private Sub prnDocument_PrintPage(ByVal sender As Object, ByVal e As PrintPageEventArgs)
    Dim g As Graphics = e.Graphics
    g.PageUnit = GraphicsUnit.Point

    Dim lalign As New StringFormat
    lalign.Alignment = StringAlignment.Near

    Using (Font font As New Font("Arial", 19))
        Using (Brush brushBlack As New SolidBrush(Color.Black)
            Dim lwi As Single = TextWidth("A", font)

            g.DrawString("A", font, brushBlack, 10, 50, lalign)
            g.DrawString("A", font, brushBlack, 10 + lwi, 50, lalign)
            g.DrawString("A", font, brushBlack, 10 + lwi + lwi, 50, lalign)
        End Using
    End Using
End Sub
 
Share this answer
 
v2
It is explained in the remarks section of the MeasureString funcion description:
The MeasureString method is designed for use with individual strings and includes a small amount of extra space before and after the string to allow for overhanging glyphs. Also, the DrawString method adjusts glyph points to optimize display quality and might display a string narrower than reported by MeasureString. To obtain metrics suitable for adjacent strings in layout (for example, when implementing formatted text), use the MeasureCharacterRanges method or one of the MeasureString methods that takes a StringFormat, and pass GenericTypographic. Also, ensure the TextRenderingHint for the Graphics is AntiAlias.

Follow the advices from the above text. There is usually no need to print a string character by character. Print at least word by word to benefit from the typography support of the Windows printing functions.
 
Share this answer
 
Comments
kgmmurugesh 12-Dec-17 0:04am    
Thanks for your help. I use the following code.

Public Function Charwidth(ByVal pstrcharacter As String, ByVal pfont As System.Drawing.Font) As Single
Dim a As Single
Dim b As Single

Try
TMPgfx.PageUnit = GraphicsUnit.Point
TxtSize = TMPgfx.MeasureString(pstrcharacter, pfont)
a = TxtSize.Width
TxtSize = TMPgfx.MeasureString(pstrcharacter + pstrcharacter, pfont)
b = TxtSize.Width
Charwidth = b - a
Catch ex As Exception
Throw ex
End Try

End Function
kgmmurugesh 12-Dec-17 0:05am    
Public Function Charwidth(ByVal pstrcharacter As String, ByVal pfont As System.Drawing.Font) As Single
Dim a As Single
Dim b As Single

Try
TMPgfx.PageUnit = GraphicsUnit.Point
TxtSize = TMPgfx.MeasureString(pstrcharacter, pfont)
a = TxtSize.Width
TxtSize = TMPgfx.MeasureString(pstrcharacter + pstrcharacter, pfont)
b = TxtSize.Width
Charwidth = b - a
Catch ex As Exception
Throw ex
End Try

End Function
It's complicated, but if you want to print characters with the right spacing, you need to measure the whole string, because the width of a character is not the only matter that affects the string width, there are "human eye" rules which apply as well. And proportional fonts (such as Arial) are all about making text "look good".

For example, there is something called "pair kerning" where characters are printed a lot closer than they would otherwise be: "VA" can be pair kerned to "tuck one under the other" and this looks more normal to people. You get similar effects with other character pairs.
And the spacing between characters is not the same as the width of two characters either, as the white space can be reduced to make them look better.

If you want to print "AAA" then measure "AAA" - you can't get the "right result" by measuring "A" and assuming that the width of "AAA" is exactly three times the width!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900