[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

how do I get the correct font width for print formatting vb.net

Posted on 2009-12-22
7
Medium Priority
?
408 Views
Last Modified: 2012-08-14
Hi,
I have two lines both are the same other than the font color. The second line prints with extra spaces between the letters. I need a way  to get the correct font width for calculating the start/x position for printing. The attached code uses MeasureString and prints wrong.

Thanks
Richard
Dim pic_font As New Font("Lucida Console", 10, FontStyle.Regular, GraphicsUnit.Pixel)
        Dim c As Long
        Dim ps As String
        Dim h As Integer
        Dim w As Double

        w = 0
        h = 0

        e.Graphics.DrawString("Rich", pic_font, Brushes.Black, w, 10)

        ps = "R"
        e.Graphics.DrawString("R", pic_font, Brushes.Black, w, 20)
        c = e.Graphics.MeasureString(ps, pic_font).Width
        w = w + c

        ps = ps + "i"
        e.Graphics.DrawString("i", pic_font, Brushes.Red, w, 20)
        c = e.Graphics.MeasureString(ps, pic_font).Width
        w = w + c

        ps = ps + "c"
        e.Graphics.DrawString("c", pic_font, Brushes.Blue, w, 20)
        c = e.Graphics.MeasureString(ps, pic_font).Width
        w = w + c

        ps = ps + "h"
        e.Graphics.DrawString("h", pic_font, Brushes.Green, w, 20)

        e.HasMorePages = False

Open in new window

Bad-Output.bmp
Good-Output.bmp
0
Comment
Question by:fwlrichard
  • 4
  • 3
7 Comments
 
LVL 41

Expert Comment

by:graye
ID: 26106247
Just get rid of the following lines:
        w = w + c

As they are only needed to *add* spacing (and are not needed to write one character after another) .  Recall that the "w" parameter is passed by value and gets incremented inside the function
http://msdn.microsoft.com/en-us/library/aa327575(VS.71).aspx 
0
 
LVL 41

Expert Comment

by:graye
ID: 26106257
Uh, you don't need the MeasureString either
0
 

Author Comment

by:fwlrichard
ID: 26106361
Hi graye,

I removed w=w+c and thy all print on top of each other.  
Would you have an example that fixes my code.
Also-bad.bmp
0
NFR key for Veeam Backup for Microsoft Office 365

Veeam is happy to provide a free NFR license (for 1 year, up to 10 users). This license allows for the non‑production use of Veeam Backup for Microsoft Office 365 in your home lab without any feature limitations.

 
LVL 41

Expert Comment

by:graye
ID: 26106900
Oops, you're right... sorry about that
OK.. try the following.... it will be "close", but not exactly what you want.   The problem is that with printing a single character at a time, the graphics engine can't use any of it's kerning rules.   So, you'll have to turn that off, or just fudge it a little bit.
In this case, with a fixed width font, you could use a single value as the width (without having to calculate it).  I'd use something like

        w = w + pic_font.SizeInPoints * 0.65

        Dim pic_font As New Font("Lucida Console", 20, FontStyle.Regular, GraphicsUnit.Point)
        Dim c As Single
        Dim ps As String
        Dim h As Single
        Dim w As Single

        e.Graphics.PageUnit = GraphicsUnit.Point

        ' set the margins
        w = e.MarginBounds.Left
        h = e.MarginBounds.Top

        e.Graphics.DrawString("Rich", pic_font, Brushes.Black, w, h)
        ' a new line...
        h = e.MarginBounds.Top + pic_font.Height + 1
        w = e.MarginBounds.Left

        e.Graphics.DrawString("R", pic_font, Brushes.Black, w, h)
        c = e.Graphics.MeasureString("R", pic_font).Width
        w = w + c

        e.Graphics.DrawString("i", pic_font, Brushes.Red, w, h)
        c = e.Graphics.MeasureString("i", pic_font).Width
        w = w + c

        e.Graphics.DrawString("c", pic_font, Brushes.Blue, w, h)
        c = e.Graphics.MeasureString("c", pic_font).Width
        w = w + c

        ps = ps & "h"
        e.Graphics.DrawString("h", pic_font, Brushes.Green, w, h)

        e.HasMorePages = False

Open in new window

0
 

Author Comment

by:fwlrichard
ID: 26107477
Graye,

Yes the problem is it's not fixed and the color itn't all I want to change it's just what I chose for this example/code. I'm new to vb.net I came from vb6 this isn't a problem with vb6 as with it you just don't give it a new x location.
Your code MeasureString calculates the width to be 19.0722656
My guess is it should be around 12.4
Any idea why it wrong?

Thanks
Richard
0
 
LVL 41

Accepted Solution

by:
graye earned 2000 total points
ID: 26107820
I don't know... I'm a little puzzled by this myself.
If you do a MeasureString on "Rich", it will be 56.3 points wide (which equates to 14.08 point for each character).  But if you meassure each character separately, you get 19.07 point each.
The documentation tells us what's going on... and tell us to use MeasureCharacterRanges instead

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.
0
 

Author Comment

by:fwlrichard
ID: 26108461
Graye
Thank you for all your help.
The MeasureCharacterRanges method is what I was missing.
This may not be the best way but it works.

Thanks
Richard
Dim stringFont As New Font("Lucida Console", 20)

        ' Set character ranges to "First" and "Second".
        Dim characterRanges As CharacterRange() = {New CharacterRange(0, 1)}

        ' Create rectangle for layout.
        Dim x As Single = 50.0F
        Dim y As Single = 50.0F
        Dim width As Single = 1000
        Dim height As Single = 1000
        Dim layoutRect As New RectangleF(x, y, width, height)
        Dim measureRect1 As RectangleF
        Dim stringRegions() As [Region]
        Dim stringFormat As New StringFormat

        stringFormat.SetMeasurableCharacterRanges(characterRanges)

        ' Draw First line to screen
        e.Graphics.DrawString("Rich", stringFont, Brushes.Black, x, y)
        ' Set new Y location for next line
        y = y + 25

        ' Draw Second line first string
        e.Graphics.DrawString("R", stringFont, Brushes.Black, x, y)

        ' Measure the string.
        stringRegions = e.Graphics.MeasureCharacterRanges("R", stringFont, layoutRect, stringFormat)
        ' Get string X,Y,Width,Height
        measureRect1 = stringRegions(0).GetBounds(e.Graphics)
        x = x + measureRect1.Width

        ' Draw second line second string
        e.Graphics.DrawString("i", stringFont, Brushes.Red, x, y)

        stringRegions = e.Graphics.MeasureCharacterRanges("i", stringFont, layoutRect, stringFormat)
        measureRect1 = stringRegions(0).GetBounds(e.Graphics)
        x = x + measureRect1.Width

        ' Draw second line third string
        e.Graphics.DrawString("c", stringFont, Brushes.Blue, x, y)

        stringRegions = e.Graphics.MeasureCharacterRanges("c", stringFont, layoutRect, stringFormat)
        measureRect1 = stringRegions(0).GetBounds(e.Graphics)
        x = x + measureRect1.Width

        ' Draw second line forth string
        e.Graphics.DrawString("h", stringFont, Brushes.Green, x, y)

        e.HasMorePages = False

Open in new window

0

Featured Post

NEW Veeam Backup for Microsoft Office 365 1.5

With Office 365, it’s your data and your responsibility to protect it. NEW Veeam Backup for Microsoft Office 365 eliminates the risk of losing access to your Office 365 data.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The object model of .Net can be overwhelming at times – so overwhelming that quite trivial tasks often take hours of research. In this case, the task at hand was to populate the datagrid from SQL Server database in Visual Studio 2008 Windows applica…
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
this video summaries big data hadoop online training demo (http://onlineitguru.com/big-data-hadoop-online-training-placement.html) , and covers basics in big data hadoop .
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…
Suggested Courses
Course of the Month19 days, 9 hours left to enroll

872 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question