Results 1 to 19 of 19

Thread: [RESOLVED] VB3 - How to word-wrap a long string of Text?

  1. #1

    Thread Starter
    Member MorkenTheMonk's Avatar
    Join Date
    Sep 2017
    Location
    Scotland, UK
    Posts
    42

    Resolved [RESOLVED] VB3 - How to word-wrap a long string of Text?

    Hi guys,

    We have an old VB3 application that allows users to type into a Text Box (Multi Line, Scroll Bars) and save the resulting Text to a variable "Note".

    Currently, we force the user to hit [Enter] at the end of each typed line in order to print the "Note" onto a specific area of the page. Page real-estate dictates that the Text "Note" cannot be free-form typed without carriage-returns, otherwise the "Printer.Print Note" would overwrite other page output or fall off the right-hand side of the page.

    What we'd like is for the user to free-form type into the Text Box, and have the code parse the resulting long Text "Note" and apply a carriage-return at a specific point (say character position 60, unless that is halfway through a word, in which case it would be at the preceding space/punctuation before the word appearing at position 60). Sounds complicated, but must be a common requirement ... unless there's a smart way for the Text Box control to automatically format the carriage-returns when it word-wraps!?

    Any ideas?

    Thanks in advance,

    MorkenTheMonk

  2. #2
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: VB3 - How to word-wrap a long string of Text?

    It is hard to be specific since VB3 is so old most of us haven't even had it installed for over a decade. Even tougher with so many people being on 64-bit Windows where it won't run anymore.

    As far as I can tell, the text "wraps" at word breaks just fine within a multi-line TextBox. Your problem is really that you want wrapping when you use Printer.Print, right?

    If so, the answer is probably not to fiddle with the TextBox or place any hopes there since it does what it is supposed to. Indeed I'd filter out any newlines typed by the user, or else allow them to be considered paragraph breaks as they really are. TextBox and similar controls are not line-oriented but paragraph-oriented.

    So you'd take the String value of the entered text and format that for wrapping as you print it, not before. The Printer object does not support this in VB6, and most likely not in creaky old VB3 either.

    Widths are seldom in "characters" but instead in pixels, twips, inches, etc. mainly because most text is rendered in proportional fonts. If you are using a fixed-pitch font with a known character width then I suppose you could write code to parse the String into lines no longer than X chars wide each, avoiding breaking words. But in general you are going to want to use API calls to render text to the printer, most likely via the DrawText() function.


    Whether VB3 can make use of a 16-bit version of DrawText() I cannot say. Documentation for Windows 3.1 and Visual Basic 3.0 is very thin online and most people probably do not have the Help or SDK files installed.

  3. #3

    Thread Starter
    Member MorkenTheMonk's Avatar
    Join Date
    Sep 2017
    Location
    Scotland, UK
    Posts
    42

    Re: VB3 - How to word-wrap a long string of Text?

    You summed requirements up pretty well 'dilettante' ... hopefully someone will have a Code Snippet to parse a long string into fixed-width lines.

    We're having to run VB3 development and application inside an XP virtual machine running on 64-bit Windows 7 machines... haven't even tested running in Windows 10 yet In the absence of documentation, relying on VB3 Help (which is actually pretty good!)
    __________________________________________________________________________________________
    MorkenTheMonk
    SCOTLAND

    (Stuck supporting a 16-bit VB3 application over 20 years old! Deep Joy!!!)

  4. #4
    Fanatic Member Spooman's Avatar
    Join Date
    Mar 2017
    Posts
    868

    Re: VB3 - How to word-wrap a long string of Text?

    Mork

    Here is a 1st shot try, using VB6

    Name:  mork1.png
Views: 2900
Size:  6.1 KB

    What's going on:
    1. txt is a string
    2. Text2 is a multi-line textbox
    3. PB1 is a PictureBox, font set to Courier
    4. PB3 is a PictureBox

    Here is the essential code

    Code:
            '      0        1         2         3         4
            '      1234567890123456789012345678901234567890
            txt = "The MSDN Library is a member of the Visual Studio 6.0 family of development products, which includes: "
            With Text2
                .Text = txt
            End With
            With PB1
                .AutoRedraw = True
                .FontName = "Courier"
                PB1.Print txt
            End With
            With PB3
                oo = 33
                Dim NoteTX(4)
                For ii = 1 To 4
                    aa = Mid(txt, oo, 1)
                    If aa = " " Then
                        b = b
                    Else
                        xtr = Left(txt, oo)         ' The MSDN Library is a member of t
                        bb = InStrRev(xtr, " ")     ' 32 on 1st line
                        NoteTX(ii) = Left(xtr, oo - 1)
                        ' print line
                        PB3.Print NoteTX(ii)
                        ' scrub, prep for next pass
                        txt = Mid(txt, bb + 1)
                    End If
                Next ii
            End With
    Loose ends:
    1. Dealing with non-fixed length fonts
    2. Line 3 .. didn't properly deal with "left-over" word
    3. Branch If aa = " " Then
    4. I preset oo = 33 .. the number of characters, comparable to your "60"
    5. I preset NoteTX to 4 lines .. you'll need to be smarter


    Nonetheless, hope this gives you some ideas

    EDIT-1

    BTW, I used PB's as they support the .Print Method.
    I figured it would be comparable to Printer.Print.

    Spoo
    Last edited by Spooman; Sep 13th, 2017 at 06:31 AM.

  5. #5

    Thread Starter
    Member MorkenTheMonk's Avatar
    Join Date
    Sep 2017
    Location
    Scotland, UK
    Posts
    42

    Re: VB3 - How to word-wrap a long string of Text?

    Superb 'Spooman'... I'll have a wee play around with that this afternoon and let you know how I get on. Converting from VB6 to VB3 will be harder than it looks, but a great start... Thanks
    __________________________________________________________________________________________
    MorkenTheMonk
    SCOTLAND

    (Stuck supporting a 16-bit VB3 application over 20 years old! Deep Joy!!!)

  6. #6
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: VB3 - How to word-wrap a long string of Text?

    Not sure why that would be hard to convert to VB3. I don't see any code there that should not be supported.
    I would add As String to the dim statement and $ on the Mid statements even in VB6. May be required in VB3 not sure there as it has been about 20 years since I used VB3,

  7. #7
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: VB3 - How to word-wrap a long string of Text?

    Here is what I had in mind, but it is VB6:

    Form1.frm
    Code:
    Option Explicit
    
    Private Sub Command1_Click()
        Const TMARGIN As Single = 0.5 'Inches.
        Const LMARGIN As Single = 0.5
        Const VGAP As Single = 0.25
        Dim P As Integer
        Dim Text As String
        Dim PrintTop As Single
        Dim PrintedHeight As Single
    
        'For testing use a virtual printer driver:
        For P = 0 To Printers.Count - 1
            If Printers(P).DeviceName = "Microsoft XPS Document Writer" Then
                Exit For
            End If
        Next
        If P = Printers.Count Then Exit Sub
    
        Set Printer = Printers(P)
        With Printer
            .FontName = "Arial"
            .FontSize = 10
            Text = Text1.Text
            'Note that we want to delete any empty paragraphs found at the end:
            Do While Right$(Text, 2) = vbNewLine
                Text = Left$(Text, Len(Text) - 2)
            Loop
            PrintedHeight = PrintingHelp.PrintBoxed(Text, _
                                                    vbInches, _
                                                    LMARGIN, _
                                                    TMARGIN, _
                                                    3.5)
            PrintTop = TMARGIN + PrintedHeight + VGAP
            .FontName = "Comic Sans MS"
            Text = Text2.Text
            Do While Right$(Text, 2) = vbNewLine
                Text = Left$(Text, Len(Text) - 2)
            Loop
            PrintedHeight = PrintingHelp.PrintBoxed(Text, _
                                                    vbInches, _
                                                    LMARGIN, _
                                                    PrintTop, _
                                                    5.5)
            PrintTop = PrintTop + PrintedHeight + VGAP
            .FontName = "Courier New"
            .FontSize = 14
            Text = Text1.Text
            Do While Right$(Text, 2) = vbNewLine
                Text = Left$(Text, Len(Text) - 2)
            Loop
            PrintedHeight = PrintingHelp.PrintBoxed(Text, _
                                                    vbInches, _
                                                    LMARGIN, _
                                                    PrintTop, _
                                                    6.5)
            PrintTop = PrintTop + PrintedHeight + VGAP
            .ForeColor = vbRed
            Text = "01234 6789 01234 6789 01234 6789 01234 6789 01234 6789 01234 6789"
            PrintedHeight = PrintingHelp.PrintBoxed(Text, _
                                                    vbInches, _
                                                    LMARGIN, _
                                                    PrintTop, _
                                                    4.5)
            .EndDoc
        End With
    End Sub
    PrintingHelp.bas
    Code:
    Option Explicit
    
    Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
    End Type
    
    'wFormat flags:
    Private Const DT_BOTTOM As Long = &H8&
    Private Const DT_CALCRECT As Long = &H400&
    Private Const DT_CENTER As Long = &H1&
    Private Const DT_EDITCONTROL As Long = &H2000&
    Private Const DT_END_ELLIPSIS As Long = &H8000&
    Private Const DT_EXPANDTABS As Long = &H40&
    Private Const DT_EXTERNALLEADING As Long = &H200&
    Private Const DT_HIDEPREFIX As Long = &H100000
    Private Const DT_INTERNAL As Long = &H1000&
    Private Const DT_LEFT As Long = &H0&
    Private Const DT_MODIFYSTRING As Long = &H10000
    Private Const DT_NOCLIP As Long = &H100&
    Private Const DT_NOFULLWIDTHCHARBREAK As Long = &H80000
    Private Const DT_NOPREFIX As Long = &H800&
    Private Const DT_PATH_ELLIPSIS As Long = &H4000&
    Private Const DT_PREFIXONLY As Long = &H200000
    Private Const DT_RIGHT As Long = &H2&
    Private Const DT_SINGLELINE As Long = &H20&
    Private Const DT_TABSTOP As Long = &H80&
    Private Const DT_TOP As Long = &H0&
    Private Const DT_VCENTER As Long = &H4&
    Private Const DT_WORDBREAK As Long = &H10&
    Private Const DT_WORD_ELLIPSIS As Long = &H40000
    
    Private Declare Function DrawText Lib "user32" Alias "DrawTextA" ( _
        ByVal hDC As Long, _
        ByVal Str As String, _
        ByVal nCount As Long, _
        ByRef RECT As RECT, _
        ByVal wFormat As Long) As Long
    
    Public Sub Flush()
        With Printer
            Printer.PSet (.CurrentX, .CurrentY), vbWhite
        End With
    End Sub
    
    Public Function PrintBoxed(ByVal Text As String, _
                               ByVal BoxScale As ScaleModeConstants, _
                               ByVal BoxLeft As Single, _
                               ByVal BoxTop As Single, _
                               ByVal BoxWidth As Single, _
                               Optional ByVal BoxHeight As Single, _
                               Optional ByVal Center As Boolean, _
                               Optional ByVal AlignBottom As Boolean) As Single
        'Returns vertical space actually used, in BoxScale units.
        Dim ExtraFlags As Long
        Dim BoxRect As RECT
        Dim DrawCall As Long
    
        Flush 'Updates the hDC with font, color, etc. changes if any.
    
        If Center Then ExtraFlags = DT_CENTER
        If AlignBottom Then ExtraFlags = ExtraFlags Or DT_BOTTOM
        If BoxHeight = 0 Then ExtraFlags = ExtraFlags Or DT_NOCLIP
        With Printer
            BoxRect.Left = .ScaleX(BoxLeft, BoxScale, vbPixels)
            BoxRect.Top = .ScaleY(BoxTop, BoxScale, vbPixels)
            BoxRect.Right = BoxRect.Left + .ScaleX(BoxWidth, BoxScale, vbPixels)
            BoxRect.Bottom = BoxRect.Top + .ScaleY(BoxHeight, BoxScale, vbPixels)
            
            DrawCall = DrawText(.hDC, _
                                Text, _
                                Len(Text), _
                                BoxRect, _
                                ExtraFlags _
                             Or DT_NOPREFIX _
                             Or DT_WORDBREAK)
            If DrawCall = 0 Then
                Err.Raise &H80047700, _
                          "PrintingHelp", _
                          "System error " & CStr(Err.LastDllError) & " in PrintBoxed."
            End If
            PrintBoxed = .ScaleY(DrawCall, vbPixels, BoxScale)
        End With
    
        Flush 'Flushes our text to the printer.
    End Function
    Results (75% preview):

    Name:  sshot.png
Views: 2822
Size:  20.0 KB
    Attached Files Attached Files

  8. #8
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: VB3 - How to word-wrap a long string of Text?

    I'll just add my two-cents regarding VB3. As mentioned ad-nauseam on other posts of this forum, I've been doing this since PDS-Basic and even before. And, through VB6 (but not including .NET), the upgrade has been relatively painless. This is particularly true for all the Windows VB versions (through VB6).

    As others have said, it's been a "few" years since I've messed with older version of VB, but I'm thinking that VB3 code will pull into the VB6 IDE and just directly execute and compile. If not "directly", it certainly won't take much to get it going.

    Regarding your actual problem/question, here's some code I found in my "junk drawer". I didn't write it, and I have no idea who did, but it's named well for what you're describing.

    Code:
    
    
    Private Sub PrintWrappedText(ByVal txt As String, ByVal indent As Single, ByVal left_margin As Single, ByVal top_margin As Single, ByVal right_margin As Single, ByVal bottom_margin As Single)
        ' Print a string on a Printer or PictureBox, wrapped within the margins.
        Dim next_paragraph As String
        Dim next_word As String
        Dim pos As Integer
    
        ' Start at the top of the page.
        Printer.CurrentY = top_margin
    
        ' Repeat until the text is all printed.
        Do While Len(txt) > 0
            ' Get the next paragraph.
            pos = InStr(txt, vbCrLf)
            If pos = 0 Then
                ' Use the rest of the text.
                next_paragraph = Trim$(txt)
                txt = ""
            Else
                ' Get the paragraph.
                next_paragraph = Trim$(Left$(txt, pos - 1))
                txt = Mid$(txt, pos + Len(vbCrLf))
            End If
    
            ' Indent the paragraph.
            Printer.CurrentX = left_margin + indent
    
            ' Print the paragraph.
            Do While Len(next_paragraph) > 0
                ' Get the next word.
                pos = InStr(next_paragraph, " ")
                If pos = 0 Then
                    ' Use the rest of the paragraph.
                    next_word = next_paragraph
                    next_paragraph = ""
                Else
                    ' Get the word.
                    next_word = Left$(next_paragraph, pos - 1)
                    next_paragraph = Trim$(Mid$(next_paragraph, pos + 1))
                End If
    
                ' See if there is room for this word.
                If Printer.CurrentX + Printer.TextWidth(next_word) _
                    > right_margin _
                Then
                    ' It won't fit. Start a new line.
                    Printer.Print
                    Printer.CurrentX = left_margin
    
                    ' See if we have room for a new line.
                    If Printer.CurrentY + Printer.TextHeight(next_word) _
                        > bottom_margin _
                    Then
                        ' Start a new page.
                        Printer.NewPage
                        Printer.CurrentX = left_margin
                        Printer.CurrentY = top_margin
                    End If
                End If
    
                ' Now print the word. The ; makes the
                ' Printer not move to the next line.
                Printer.Print next_word & " ";
            Loop
    
            ' Finish the paragraph by ending the line.
            Printer.Print
        Loop
    End Sub
    
    
    Good Luck,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  9. #9

    Thread Starter
    Member MorkenTheMonk's Avatar
    Join Date
    Sep 2017
    Location
    Scotland, UK
    Posts
    42

    Re: VB3 - How to word-wrap a long string of Text?

    Thanks for all your help and opinions guys. Once I've had a chance to review and try out all of the above, I'll feed back here!

    (Incidentally, I seem to recall even VB4 wouldn't natively read our VB3 code. Rest assured, once time permits we want to get as far away from VB3 as we can, however the software is still LIVE and in daily use... )
    __________________________________________________________________________________________
    MorkenTheMonk
    SCOTLAND

    (Stuck supporting a 16-bit VB3 application over 20 years old! Deep Joy!!!)

  10. #10
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: VB3 - How to word-wrap a long string of Text?

    Quote Originally Posted by MorkenTheMonk View Post
    (Incidentally, I seem to recall even VB4 wouldn't natively read our VB3 code. Rest assured, once time permits we want to get as far away from VB3 as we can, however the software is still LIVE and in daily use... )
    By default VB3 saved files in binary format. I can't remember if VB4 could read those or not [I barely touched Vb4] but I know VB5 and 6 can not.
    There was also an option to save in text format which can be read by the other versions without issue.
    The only VB3 project upgrade issues other than the binary save were related to 3rd party vbx controls.

    Most VB3 projects which use only basic controls can be saved as text then updated and compiled in VB6 without issue.

  11. #11
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: VB3 - How to word-wrap a long string of Text?

    Ahhhh, DataMiser, excellent catch. Yes, I remember that too.

    @Morken: It's been too long to remember exactly where it is, but there's a Option/Setting somewhere in VB3 to tell it to save your files as ASCII/ANSI. You need to select that option. Selecting this won't change anything about how VB3 works, but it will save your FRM (and BAS, and other) files in a Notepad-readable form, which is the default (and only) way that VB6 does things. That may even fix the problems you were having with trying to go to VB4.

    Good Luck,
    Elroy

    EDIT1: Morken, just as some more FYI, older versions of VB could save files into something called p-code. This is a quasi-compiled version of the code. However, it can be easily un-compiled and displayed again, so long as that version of the IDE knows how to do that (which later versions do not). They did this to save a bit of disk space, and also to load your project a bit faster. However, as computers got faster and disk space got larger (and cheaper), Microsoft realized that saving files as p-code just didn't really gain that much, so they abandoned it.

    Interestingly, VB6 still uses p-code, but not for saving its files. VB6 uses this "compiled" p-code to run/execute your code while developing in the IDE. When actually compiled, it's no longer p-code. It's true machine code.

    Also, and I don't remember the exact dates/versions of all the transitions, but not all the older versions of VB actually compiled to machine code. The early versions (including VB3 I believe) only compiled the executable to p-code. As such, if someone got your executable, they could relatively easily de-compile it back to a relatively good version of your source code.
    Last edited by Elroy; Sep 13th, 2017 at 09:42 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  12. #12
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: VB3 - How to word-wrap a long string of Text?

    Yes VB3 compiles only to P-Code and can be de-compiled into usable though pretty much unreadable VB code.

    I think VB5 was the first version that produce native execuables with the exception of VBDOS of course. VBDOS could not only create a true EXE but could create a true standalone EXE.

  13. #13
    Junior Member
    Join Date
    May 2017
    Posts
    22

    Re: VB3 - How to word-wrap a long string of Text?

    Quote Originally Posted by DataMiser View Post
    Yes VB3 compiles only to P-Code and can be de-compiled into usable though pretty much unreadable VB code.

    I think VB5 was the first version that produce native execuables with the exception of VBDOS of course. VBDOS could not only create a true EXE but could create a true standalone EXE.
    Correct, compile to native EXE's started in VB5. Everything before is pcode, I think.

  14. #14
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: VB3 - How to word-wrap a long string of Text?

    Quote Originally Posted by DataMiser View Post
    Yes VB3 compiles only to P-Code and can be de-compiled into usable though pretty much unreadable VB code.

    I think VB5 was the first version that produce native execuables with the exception of VBDOS of course. VBDOS could not only create a true EXE but could create a true standalone EXE.
    right, but weren't those still interpreted / p-code ? (and the standalone just static linked the runtime)

  15. #15
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: VB3 - How to word-wrap a long string of Text?

    Honestly I am not sure now, I know the runtime was not required on the target system when a standalone exe was generated and I remember the compiler created obj files and used link to build the exe but last one I build was in the 90s so is all a bit vague at this point.

  16. #16
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: VB3 - How to word-wrap a long string of Text?

    Quote Originally Posted by DataMiser View Post
    Not sure why that would be hard to convert to VB3. I don't see any code there that should not be supported...
    The first two things that jumped out for me is the InStrRev function which VB3 didn't have, and the use of "With...End With" which VB3 didn't have either.
    The use of "With...End With" would make the code look strange compared to what someone using VB3 would be familiar with.

  17. #17
    Fanatic Member Spooman's Avatar
    Join Date
    Mar 2017
    Posts
    868

    Re: VB3 - How to word-wrap a long string of Text?

    passel

    Good catch .. who knew !!

    Seems that both issues could be overcome
    • InStrRev .. create a loop with a Step -1 feature
    • With/End With .. just repeat typing the Object


    Spoo

  18. #18

    Thread Starter
    Member MorkenTheMonk's Avatar
    Join Date
    Sep 2017
    Location
    Scotland, UK
    Posts
    42

    Re: VB3 - How to word-wrap a long string of Text?

    Hey folks, a quick update...

    Used Elroy's 'PrintWrappedText' function which was pure VB3 with the exception of 'vbCRLf' constants - easily replaced with Chr(13) and Chr(10). There was a wee problem with new paragraphs in the Txt string being translated with double newlines, however a wee condition to see if next_word was Asc(13) or Asc(10) did the trick.

    Many many thanks for all of your guidance and help... very much appreciated.

    Cheers!
    __________________________________________________________________________________________
    MorkenTheMonk
    SCOTLAND

    (Stuck supporting a 16-bit VB3 application over 20 years old! Deep Joy!!!)

  19. #19
    Fanatic Member Spooman's Avatar
    Join Date
    Mar 2017
    Posts
    868

    Re: [RESOLVED] VB3 - How to word-wrap a long string of Text?

    Mork

    Glad you got it working.
    Oh yeah, and a belated Welcome to the Forums ..

    In that regard, it is good practice to mark this thread as RESOLVED.

    To do that, you'll notice that just about your 1st post, there is a little drop down menu named Thread Tools. Click the down arrow, and select the RESOLVED option.

    Spoo

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width