ID Number: Q80867
1.00
WINDOWS
Summary:
Printing the Text property of a multiline text box while maintaining
the line structure requires attention to word wrapping and carriage
return/line feeds. The programmer can either track the number of
characters and lines in code or use Windows API functions to
manipulate the Text property. This article demonstrates those
techniques in a Visual Basic example.
This information applies to Microsoft Visual Basic programming system
version 1.0 for Windows.
More Information:
The example below demonstrates the use of the API function SendMessage
to track the number of lines in a multiline text box and to select and
print the lines in the way they appear--with line breaks or word
wrapping intact. This code will work without modification even if the
form and controls are resized at run time. The actual position of word
wrapping will change.
For more information about API functions relating to text boxes, query
on the following words in the Microsoft Knowledge Base:
API text box manipulate
To build the example:
1. Create a form and place on it a label, a text box, and a command
button.
2. Set the following properties at design time:
Control Property Setting
------- -------- -------
Text box TabIndex 0 (zero, or first in tab order)
Text box MultiLine True
Label AutoSize True
Label CtlName aGetLineCount
3. Add the following code to the Global module:
Declare Function GetFocus% Lib "user" ()
Declare Function SendMessage% Lib "user" (ByVal hWnd%, ByVal wMsg%,
ByVal wParam%, ByVal lParam As Any)
' The above Declare must be placed on one line.
Global Buffer As String
Global resizing As Integer
Global Const EM_GETLINE = &H400 + 20
Global Const EM_GETLINECOUNT = &H400 + 10
Global Const MAX_CHAR_PER_LINE = 80 ' Scale this to size of text box
4. Add the following code to the Form_Load and Form_Resize
procedures:
Sub Form_Load ()
' Size form relative to screen dimensions.
' Could define all in move command but recursive definition causes
' extra paints.
form1.width = screen.width * .8
form1.height = screen.height * .6
form1.Move screen.width\2-form1.width\2, screen.height\2-form1.height\2
End Sub
Sub Form_Resize ()
resizing = -1 ' Global flag for fGetLineCount function call
' Dynamically scale and position the controls in the form.
' This code also is executed on first show of form.
Text1.Move 0, 0, form1.width, form1.height \ 2
Text1.SelStart = Text1.SelStart ' To avoid UAE -see Q80669
command1.Move form1.width\2-command1.width\2, form1.height-form1.height\4
aGetLineCount.Move form1.width \ 2 - command1.width \ 2, Text1.height
X% = fGetLineCount() ' Update to reflect change in text box size
resizing = 0
End Sub
5. Add the following code to the Command1_Click event:
Sub Command1_Click ()
'* Pop up an inputbox$ to allow user to specify which line
'* in the text box to print or print all lines.
'* Also check bounds so that a valid line number is printed
OK = 0 ' Zero the Do Loop flag
NL$ = Chr$(13) + Chr$(10)
prompt$ = "Which line would you like to print?"
prompt1$ = prompt$ + NL$ + "Enter -1 for all"
prompt2$ = "Too many lines" + NL$ + "Try again!" + NL$ + prompt1$
prompt$ = prompt1$
Do
response$ = InputBox$(prompt$, "Printing", "-1")
If response$ = "" Then Exit Sub ' if user hits cancel then exit
If Val(response$) > fGetLineCount&() Then
prompt$ = prompt2$
Else
OK = -1 ' Line chosen is in valid range so exit DO
End If
Loop Until OK
If Val(response$) = -1 Then ' Print all lines
ndx& = fGetLineCount&()
For N& = 1 To ndx&
Buffer = fGetLine(N& - 1)
printer.Print Buffer ' or print to the screen
Next N&
Else ' Print a line
Buffer = fGetLine(Val(response$) - 1)
printer.Print Buffer ' or print to the screen
End If
End Sub
6. Add the following code to the general Declarations section of the
form's code:
Function fGetLine$ (LineNumber As Long)
' This function fills the buffer with a line of text
' specified by LineNumber from the text box control.
' The first line starts at zero.
byteLo% = MAX_CHAR_PER_LINE And (255) '[changed 5/15/92]
byteHi% = Int(MAX_CHAR_PER_LINE / 256) '[changed 5/15/92]
Buffer$ = chr$(byteLo%) + chr$(byteHi%)+Space$(MAX_CHAR_PER_LINE-2)
' [Above line changed 5/15/92 to correct problem.]
text1.SetFocus 'Set focus for API function GetFocus to return handle
x% = SendMessage(GetFocus(), EM_GETLINE, LineNumber, Buffer)
fGetLine$ = Buffer
End Function
Function fGetLineCount& ()
' This function will return the number of lines
' currently in the text box control.
' Setfocus method illegal while in resize event
' so use global flag to see if called from there
' (or use setfocus prior to this function call in general case).
If Not resizing Then
Text1.SetFocus ' Set focus for following function GetFocus
resizing = 0
End If
lcount% = SendMessage(GetFocus(), EM_GETLINECOUNT, 0&, 0&)
aGetLineCount.caption = "GetLineCount = " + Str$(lcount%)
fGetLineCount& = lcount%
End Function
7. Add the following code to the Text1_Change event:
Sub Text1_Change ()
X% = fGetLineCount() '* Update label to reflect current line
End Sub
8. Save the project, then run the application.
9. Enter text into the text box and either let it wrap or use the
ENTER key to arrange lines.
10. Choose the button or TAB and press ENTER.
11. Choose the default (which prints all lines) or enter the line
desired. If you choose Cancel, nothing will print.
12. Resize the form and repeat steps 9 to 11 above. The text will
appear on the printed page as you saw it in the text box. Modify
the example to print to the screen, write to a file, and so forth.
Reference(s):
"Microsoft Windows Programmer's Reference Book and Online Resource"
(Visual Basic Add-on kit number 1-55615-413-5)
Additional reference words: 1.00