Solved

Print a rotated text centered in a given rectangle

Posted on 2004-10-27
375 Views
Last Modified: 2008-01-09
I'm trying to print some rotated text centered in a specific area of the printer form using windows API. This is the code I've written for this:
        '*************** create font *****************
        lf.lfHeight = -MulDiv(FontSize, GetDeviceCaps(hPrintDc, LOGPIXELSY), 72)
        'lf.lfWidth = 0
        lf.lfEscapement = Rotation * 10
        lf.lfOrientation = Rotation * 10
        If FontBold = 1 Then
            lf.lfWeight = FW_BOLD
        Else
            lf.lfWeight = FW_NORMAL
        End If
        lf.lfItalic = CByte(FontItal)
        lf.lfUnderline = CByte(FontUnder)
        lf.lfStrikeOut = CByte(FontStrk)
        lfCharSet = DEFAULT_CHARSET
        lfOutPrecision = OUT_DEFAULT_PRECIS
        lf.lfClipPrecision = CLIP_LH_ANGLES
        lf.lfQuality = DEFAULT_QUALITY
        lf.lfPitchAndFamily = DEFAULT_PITCH Or FF_DONTCARE
        lf.lfFaceName = FontName
        hFont = CreateFontIndirect(lf)  'Create the rotated font
        hOldfont = SelectObject(hPrintDc, hFont)
        OutAlign = DT_TOP
        If TextAlign = 0 Then
            OutAlign = OutAlign + DT_LEFT
        ElseIf TextAlign = 1 Then
            OutAlign = OutAlign + DT_RIGHT
        Else
            OutAlign = OutAlign + DT_CENTER
        End If
        If TextWordW = 1 Then
            OutAlign = OutAlign + DT_WORDBREAK
        End If
        '******** area for printing *************
        'note that there is a 270degrees rotation so "left/right" are inverted
        TextRect.Left = 2414
        TextRect.Top = 1386
        TextRect.Right = 2198
        TextRect.Bottom = 2883
        Result = SetTextColor(hPrintDc, ForeColor)
        Result = DrawText(hPrintDc, TextString, Len(TextString), TextRect, OutAlign)
        Result = SelectObject(hPrintDc, hOldfont)
        Result = DeleteObject(hFont)    'Delete the font object

Well, if I use DT_LEFT alignment it works fine but, if I use DT_RIGHT or DT_CENTER alignment it doesn't work. I can´t see any text.

Pls, can anybody tell me what is going wrong?

Thanks
    Leo
0
Question by:leorocha
    8 Comments
     
    LVL 3

    Expert Comment

    by:Egore
    What is the return value from DrawText when the text does not display?  If it's 0, then we know that we're dealing with invalid parameters.
    0
     

    Author Comment

    by:leorocha
    Return value=211
    Text to print="817439225"
    Font=Arial,Normal,11
     
    0
     
    LVL 3

    Expert Comment

    by:Egore
    My next thought would be to swap Left and Right values back to normal and try a 45 degree rotation.  See if the issue is with all rotation, or just with a 270 degree rotation.
    0
     
    LVL 3

    Expert Comment

    by:Egore
    The following code is the quick-and-dirty code that I'm using to test with.  I think I see your problem.  Please try out this code in a new project.  I think I got all of the variables matched up properly and I'm using a "DrawFocusRect" routine to display the clipping rectangle.  You can use this code with the inverted Left and Right values as well, but "DrawFocusRect" doesn't accept them.

    After running this with a few iterations, it appears that DT_LEFT, DT_RIGHT, and DT_CENTER have no idea that your text is rotated.  Therefore, when you do DT_RIGHT (in my code example) you will get vertical text that runs properly north/south, but that is the same distance from the right edge of the draw area as if it was never rotated.  You can see the same thing with DT_CENTER.  The text displays way to the left.  And, as you already know, DT_LEFT displays to the left of the display area and is therefore never drawn on-screen.

    In a few minutes I'll post what I believe to be a solution.  I need to get the kinks worked out.  You can ignore my previous post.

    ----------------------------------

    Option Explicit

    Private Const DT_TOP = &H0
    Private Const FW_NORMAL = 400
    Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
    Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
    Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
    Private Type RECT
            Left As Long
            Top As Long
            Right As Long
            Bottom As Long
    End Type
    Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
    Private Const DEFAULT_CHARSET = 1
    Private Const OUT_DEFAULT_PRECIS = 0
    Private Const CLIP_LH_ANGLES = 16
    Private Const DEFAULT_QUALITY = 0
    Private Const DEFAULT_PITCH = 0
    Private Const FF_DONTCARE = 0
    Private Const DT_LEFT = &H0
    Private Const DT_RIGHT = &H2
    Private Const DT_CENTER = &H1
    Private Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long
    Private Const LF_FACESIZE = 32
    Private Type LOGFONT
            lfHeight As Long
            lfWidth As Long
            lfEscapement As Long
            lfOrientation As Long
            lfWeight As Long
            lfItalic As Byte
            lfUnderline As Byte
            lfStrikeOut As Byte
            lfCharSet As Byte
            lfOutPrecision As Byte
            lfClipPrecision As Byte
            lfQuality As Byte
            lfPitchAndFamily As Byte
            lfFaceName As String * LF_FACESIZE
    End Type
    Private Const LOGPIXELSY = 90
    Private Declare Function DrawFocusRect Lib "user32" (ByVal hdc As Long, lpRect As RECT) As Long

    Private Sub Form_Click()

        Dim hdc As Long
        Dim TextRect As RECT
        Dim Result As Long
        Dim TextString As String
        Dim hFont As Long
        Dim hOldFont As Long
        Dim lf As LOGFONT
        Dim Rotation As Integer
        Dim OutAlign As Long
        Dim TextAlign As Integer
        Dim FontName As String
       
        hdc = GetDC(Me.hwnd)
        Rotation = 270
        TextAlign = 1
        FontName = "Arial"
        TextString = "817439225"
       
        '*************** create font *****************
        lf.lfHeight = 0
        lf.lfEscapement = Rotation * 10
        lf.lfOrientation = Rotation * 10
        lf.lfWeight = FW_NORMAL
        lf.lfItalic = CByte(False)
        lf.lfUnderline = CByte(False)
        lf.lfStrikeOut = CByte(False)
        lf.lfCharSet = DEFAULT_CHARSET
        lf.lfOutPrecision = OUT_DEFAULT_PRECIS
        lf.lfClipPrecision = CLIP_LH_ANGLES
        lf.lfQuality = DEFAULT_QUALITY
        lf.lfPitchAndFamily = DEFAULT_PITCH Or FF_DONTCARE
        lf.lfFaceName = FontName
        hFont = CreateFontIndirect(lf)  'Create the rotated font
        hOldFont = SelectObject(hdc, hFont)
        OutAlign = DT_TOP
        If TextAlign = 0 Then
            OutAlign = OutAlign + DT_LEFT
        ElseIf TextAlign = 1 Then
            OutAlign = OutAlign + DT_RIGHT
        Else
            OutAlign = OutAlign + DT_CENTER
        End If
        '******** area for printing *************
        'note that there is a 270degrees rotation so "left/right" are inverted
        TextRect.Left = 50
        TextRect.Top = 50
        TextRect.Right = 500
        TextRect.Bottom = 500
        Result = DrawText(hdc, TextString, Len(TextString), TextRect, OutAlign)
        Result = DrawFocusRect(hdc, TextRect)
        Result = SelectObject(hdc, hOldFont)
        Result = DeleteObject(hFont)    'Delete the font object

    End Sub

    Private Sub Form_Load()

        Me.ScaleMode = vbPixels
        Me.WindowState = vbMaximized

    End Sub
    0
     
    LVL 3

    Expert Comment

    by:Egore
    I would highly suggest changing "DrawText" to "TextOut" unless you absolutely need the DT_WORDBREAK functionality.  It looks like "DrawText" is not suited to drawing anything other than 0 degree rotations.  You can easily hand-roll DT_LEFT, DT_RIGHT, and DT_CENTER routines.

    If this will work for you and you need code for how to do left, right, and center alignment by hand, I'd be happy to code it for you.

    On a side note, lfCharSet and lfOutPrecision are not being properly set by your code.  You forgot to put "lf." in front of them.  Turning on "Option Explicit" is great to catch those types of errors.
    0
     

    Author Comment

    by:leorocha
    Add DT_NOCLIP to DT_RIGHT and to DT_CENTER and the text appears. It seems to be centered between paper left margin and left side of the indicated rectangle.

    Thanks
    0
     
    LVL 3

    Expert Comment

    by:Egore
    Unfortunately, you're still not getting the effect that you want (namely, left-, right-, or center-justification).  Everything is off by a distance of the length of the text.  Try putting in a longer string, and you'll see that the text is shifted further to the side.  If you shorten the string, the text will be placed closer to where you would expect.

    I would highly suggest looking at "TextOut".  Once again, you lose DT_WORDBREAK, but everything else works if you do a little math.  However, even DT_WORDBREAK can be done with a tiny bit of logic (not to metion that you won't get the results from that flag that you are expecting due to the rotation).  "DrawText" simply was not designed to work with rotated text, but TextOut was.

    What I'm trying to get at is that you will have a heck of a time positioning text using DrawText since the RECT that you pass in is virtually meaningless.  Once again, if you need algorithms to left-justify, right-justify, and center your text, since this is a 500 point question, I would be happy to write them for you so that you can use TextOut instead of DrawText.
    0
     
    LVL 3

    Accepted Solution

    by:
    Oops, 250 point question, not 500.  Still plenty...
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Looking for New Ways to Advertise?

    Engage with tech pros in our community with native advertising, as a Vendor Expert, and more.

    There are many ways to remove duplicate entries in an SQL or Access database. Most make you temporarily insert an ID field, make a temp table and copy data back and forth, and/or are slow. Here is an easy way in VB6 using ADO to remove duplicate row…
    Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
    Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
    This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

    934 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

    Need Help in Real-Time?

    Connect with top rated Experts

    18 Experts available now in Live!

    Get 1:1 Help Now