Solved

TextBox - Need more functionality.

Posted on 2001-09-08
24
278 Views
Last Modified: 2008-02-07
I'm working on a simple telnet client which at this stage uses two TextBoxes (among other components). One of these has the MultiLine property set and is used for displaying data received from the server and data that has been sent to the user (OutputBox). The other does not have the MultiLine property set, and is used for inputting commands/etc to send to the server (InputBox).

When I append data to the OutputBox I want it to automatically scroll so the newest data (at the bottom of the box) is visible on screen, rather than the old data (at the top).

I also want the OutputBox to display ANSI-formatted text appropriately (and without me having to manually parse the data for ANSI format codes and change font colours/styles accordingly).

How do I get a TextBox (or TextBox style component) with this type of functionality? I've seen these used in many mud clients (what I'm eventually hoping to turn this into), but how it has been achieved is beyond me.
0
Comment
Question by:Subhuman
  • 11
  • 6
  • 5
  • +2
24 Comments
 
LVL 12

Expert Comment

by:roverm
ID: 6466531
Replace the TextBox for a listbox, then insert a new item:

ListBox1.AddItem "thenewstring", 0 '0 is the top index

D'Mzzl!
RoverM
0
 
LVL 12

Expert Comment

by:roverm
ID: 6466533
For example:

With List1
    .AddItem "This is the first inserted line", 0
    .AddItem "and this is the second", 0
End With

Item "and this..." will be displayed as the first line.

D'Mzzl!
RoverM
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6466538
Will that work? I'm skeptical but I'll give it a whirl. The data from the server comes in rather large clumps at times, which aren't going to fit into one line, and while I've never used a ListBox in VB, experience with other implementations thereof suggests to me that VB one's don't allow word-wrapping any more than C++/Java/Etc ones do (not to mention I've never seen another app using a wrapped list box).

Also, it doesn't solve the ANSI issue.
0
 
LVL 12

Expert Comment

by:roverm
ID: 6466550
Yep, you are right. It doesn't solve your lengthy texts and ANSI. However it would work for small texts and no ANSI's ;-).

Ok, replace the textbox for a richtextbox control.

Then look at this PAQ for ANSI:

http://www.experts-exchange.com/jsp/qShow.jsp?qid=10408537

D'Mzzl!
RoverM
0
 
LVL 3

Expert Comment

by:sridhar_PJ
ID: 6466554
Hi Subhuman,
It is possible to scroll the text in the text box. I have done that in my program. Just i m giving the sample code for you. Try this.
Text1.text control multiline property should be True.

Private Sub Command1_Click()
x = 1
st = 10
Do While x < 200
x = x + 1
Text1.Text = Text1.Text & x & vbCrLf
Text1.SelStart = Len(Text1.Text)
Loop
Text1 = Text1 & "Waiting for next loop"
Text1.SelStart = Len(Text1.Text)
Text1.SetFocus
End Sub


Try this if u have any problem let me know.
Regards
Sridhar
0
 
LVL 12

Expert Comment

by:roverm
ID: 6466557
BTW: The RichTextbox control wraps the line if it's too long.
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6466562
So basically the functional part of that was the

Text1.SelStart = Len(Text1.Text)
Text1.SetFocus

- bit. Hopefully it will work without being focused, because it would be extremely annoying having the focus shifting while you're trying to type in the InputBox (incidentally, to fit in with what I've specified above you ought to have used OutputBox rather than Text1, as they are being used for very different things).

-=-=-=-=-=-=-=-

roverm: Where would I find a RichTextBox control? It doesn't appear in the general controls toolbox by default (at least not in VB5, which I'm using), and I've only been using VB for roughly 3 hours, armed with an idiots guide and the online language reference, and haven't chanced across which component package the RichTextBox hides in (took me long enough to find the damn Winsock control).

Thanks for the PAQ link, I'll browse through it and see if it helps any.
0
 
LVL 15

Expert Comment

by:ameba
ID: 6466565
To append text, here is the best way:

    Text1.SelStart = Len(Text1.Text)
    Text1.SelText = yourstring    ' or  yourstring & vbCrLf

To have formatting and to allow for more data - use RichTextBox - the syntax for adding the text is the same.
To add RichTextBox component to toolbox, go to menu Project, Components, and check "Microsoft Rich Textbox Control 6.0"
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6466567
Ahh, sweet. Damn, this topic area is fast.

<looks up... Most popular topics: #1 Visual Basic>

No wonder. ;)
0
 
LVL 15

Expert Comment

by:ameba
ID: 6466571
Of course it's popular - there are many VB programmer - you can be VB programmer after ... 3 hours.  :-)
0
 
LVL 12

Expert Comment

by:roverm
ID: 6466577
3 hours ? Hmmmmm, so I still have got a learning time left ;-)
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6466578
*grins*

*busily saving these pages to disk so I can get at them from my other computer, where I have VB installed*
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 2

Expert Comment

by:YourBuddyToo
ID: 6466863
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6468017
Ok, the OutputBox.SelStart = Len(OutputBox.Text) thing is working a treat. :)

Since I've been using the RichTextBox control, I've been getting a funny 'box' character at the start of each line of output. I tried copying this character and pasting it into the immediate window, inside a print asc("<char here>") command, but it pastes as a new line so I can't actually determine if it's chr(10) or chr(13), or some other character that causes line-breakage. I've tried filtering both out to no avail, but that is likely something wrong with my filter.

I'm also getting special characters occasionally (chr(251, 252 and 255) that I've come across so far), which neither telnet.exe nor GMud display. These are sent from the server like this:

-=-=-=-=-=-=-=-=-=-

By what name are you known (or "new" to create a new character):
[waits here for username]
Password: chr(255)(chr(251)chr(unknown)
[waits here for password]
chr(255)chr(252)Last connected from: [my ip]
Press enter...

-=-=-=-=-=-=-=-=-=-

The positioning of these characters around the password suggests that the combination 255,251 and 255,252 respectively tell the client to mask any input in between. Is this a standard thing that I should implement or just weirdness? I've also attempted to filter these characters out, but again to no avail.

Has anyone got a link to a site documenting the standard telnet escape sequences (or whatever these are called)?

-=-=-=-=-=-=-=-=-=-

Had a look through that thread on ANSI colour support. Pity it's an older one; the thread order has been scrambled making it pretty much impossible to follow. I'll start a new thread for the ANSI stuff once I've got the weird-characters-in-richtextedit issue sorted out.

-=-=-=-=-=-=-=-=-=-

YourBuddyToo: Lots of telnet example code and applications, however most are servers and the clients have little to offer me that I can see. I'm downloading a few anyway to poke around in and will let you know what I come across, if anything.
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6468025
Now onto the code...

-=-=-=-=-={form1.frm}-=-=-=-=-=-

Option Explicit
Dim connected As Boolean   'no longer used but I haven't removed it yet (lazy) ;)

' writes given text to the outputbox.
' having this as a subroutine saves me typing the
' whole lot out every time I need output.
Public Sub OutputText(ByVal theText As String)
    OutputBox.SelStart = Len(OutputBox.Text)
    OutputBox.SelText = theText 'use vbCrLf for linefeed ;)
    OutputBox.SelStart = Len(OutputBox.Text)
End Sub

' theoretically at least, determines if the character is
' stupid (ascii value greater than 127).
Public Function IsNotStupidBit(ByVal theChar As String) As Boolean
    Dim stupidBits(0 To 2) As Integer
    stupidBits(0) = 10
    stupidBits(1) = 255
    stupidBits(2) = 251
    Dim i As Integer
    For i = 0 To UBound(stupidBits)
    '    If stupidBits(i) = Asc(theChar) Then
        If Asc(theChar) <= 127 Then
            IsNotStupidBit = False
            Exit For
        End If
    Next i
    IsNotStupidBit = True
End Function

' removes characters from a string that are deemed 'stupid'
' (see above)
Public Function RemoveStupidBits(ByVal theString As String) As String
    Dim temp As String
    Dim i As Integer
    For i = 1 To Len(theString)
        Dim blah As String
        blah = Mid(theString, i, 1)
        If IsNotStupidBit(blah) Then
            temp = temp & Mid(theString, i, 1)
        End If
    Next i
    RemoveStupidBits = temp
End Function

' duh.
Private Sub Form_Load()
    connected = False     ' obsolete
End Sub

' this button opens the winsock connection
Private Sub ConnectButton_Click()
    Text1.Text = "Connecting..."
    If Winsock1.State = sckClosed Then
        Winsock1.RemoteHost = ConnectionHost.Text
        Winsock1.RemotePort = ConnectionPort.Text
        Winsock1.Connect
        connected = True
    End If
    'If Winsock1.State = sckConnected Then
    '    Text1.Text = Text1.Text & " Connected."
        'OutputText "*** Connected."
    'Else
    '    Text1.Text = Text1.Text & " Failed."
    'End If
End Sub

' this button kills the connection
Private Sub DisconnectButton_Click()
    Winsock1.Close
    connected = False
    'OutputText vbCrLf & "*** Disconnected."
    Text1.Text = "Disconnected."
End Sub

' so text can be copied, but the output box can't be
' focused.
Private Sub OutputBox_GotFocus()
    Clipboard.Clear
    Clipboard.SetText OutputBox.SelText, vbCFText
    InputBox.SetFocus
End Sub

' handle data coming in from the server
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    Dim DataArrived As String
    Winsock1.GetData DataArrived, vbString
    'Text1.Text = DataArrived
    RemoveStupidBits DataArrived
    OutputText DataArrived
End Sub

' trap key presses in the InputBox, used to get Enter key
' among other things
Private Sub InputBox_KeyPress(KeyAscii As Integer)
    If KeyAscii = vbKeyReturn Then
        If Winsock1.State = sckConnected Then
            Winsock1.SendData InputBox.Text & vbCrLf
            OutputText InputBox.Text & vbCrLf
        End If
        InputBox.Text = ""
        KeyAscii = 0
    Else
        Text1.Text = ""
    End If
End Sub

' resizes form elements to fit the window.
' at the moment this crashes the app when it's minimised,
' but I think I can fix that.
Private Sub Form_Resize()
    ' Stop form from resizing smaller than it can be drawn
    If Form1.Height < 2200 Then Form1.Height = 2200
    OutputBox.Width = Form1.Width - 225
    OutputBox.Height = Form1.Height - 1890
    OutputBox.SelStart = 0
    OutputBox.SelStart = Len(OutputBox)
    InputBox.Top = Form1.Height - 1065
    InputBox.Width = Form1.Width - 225
    Text1.Top = Form1.Height - 705
End Sub

' detects when the connection is closed by peer
Private Sub Winsock1_Close()
    Text1.Text = "Disconnected."
    Winsock1.Close
End Sub

' detects when connection has successfully completed.
' don't yet know how to check for fail :/
Private Sub Winsock1_Connect()
    Text1.Text = Text1.Text & " Connected"
    InputBox.SetFocus
End Sub

0
 
LVL 1

Author Comment

by:Subhuman
ID: 6468030
Just found a typo in "Public Function IsNotStupidBit(ByVal theChar As String) As Boolean":


If Asc(theChar) <= 127 Then

- should be -

If Asc(theChar) > 127 Then


I'll fix that when I'm back on my other computer. It doesn't appear that it would affect anything though, since I'm getting regular characters coming through just as well as the stupid characters.

So - how can I make the BlahStupidBitsEtc functions work correctly to remove all the weird characters?
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6468191
Ok, I've got that to work. I removed the two StupidBits functions and replaced them with a Parse function:

Public Function Parse(ByVal theText As String) As String
    Dim temp As String
    Dim i As Integer
    For i = 1 To Len(theText)
        Select Case Asc(Mid(theText, i, 1))
            Case 0      'null
            Case 1      'local echo option code (I think)
                If processCommand Then
                    If theCommand = 251 Then
                        localEcho = False
                        processCommand = False
                        theCommand = -1
                    ElseIf theCommand = 252 Then
                        localEcho = True
                        processCommand = False
                        theCommand = -1
                    End If
                End If
            Case 7      'beep
                Beep
            Case 8      'backspace
            Case 9      'horizontal tab
            Case 10     'LF
                temp = temp & vbCrLf
            Case 11     'vertical tab
                temp = temp & vbCrLf & vbCrLf
            Case 12     'form feed
            Case 13     'CR
            Case 251    'will [option code]
                If processCommand Then theCommand = 251
            Case 252    'won't [option code]
                If processCommand Then theCommand = 252
            Case 255    'interpret as command (then one or two chars)
                processCommand = True
            Case Else
                temp = temp & Mid(theText, i, 1)
                processCommand = False
                theCommand = -1
        End Select
    Next i
    Parse = temp
End Function

- and that works nicely.

I picked up a few RFCs from a friend, so I now know what those byte values above represent, and the select case lets me handle each one rather than just ignoring them all as I was attempting to do previously.

The chr(255) character tells the receiver that the next char should be interpreted as a command (IAC). The chr(251) and (252) are WILL and WON'T commands respectively, which take another parameter -- the command to perform. By the way it's used, I assume the value chr(1) represents Local Echo, which is turned on and off by the WILL and WON'T commands (that's how I'm handling it, at any rate).

I don't have an RFC that defines what the values of this parameter represent though. If anyone has one or knows where to find one...

YourBuddyToo: Interesting to note that one of the clients on that site that supports ANSI colours uses a PictureBox rather than a RichTextBox.

I can't find any documentation for using text inside a PictureBox though, so I'll stick with the RichTextBox. But that's a whole other thread which I'll get to later.

Just a thought - what's the maximum capacity of a RichTextBox? And, how should I go about preventing the box from running out of memory in the middle of an append?

0
 
LVL 15

Accepted Solution

by:
ameba earned 50 total points
ID: 6468404
>Had a look through that thread on ANSI colour support. Pity it's an older one; the thread order has been scrambled making it pretty much impossible to follow

I don't know if it will help, here is sorted version of that thread:
http://us.share.geocities.com/ameba_vb/temp/q10408537.html

> ' resizes form elements to fit the window.
> ' at the moment this crashes the app when it's minimised,
> ' but I think I can fix that.
>Private Sub Form_Resize()
>    ' Stop form from resizing smaller than it can be drawn
>    If Form1.Height < 2200 Then Form1.Height = 2200
>    OutputBox.Width = Form1.Width - 225
>    OutputBox.Height = Form1.Height - 1890
>    OutputBox.SelStart = 0
>    OutputBox.SelStart = Len(OutputBox)
>    InputBox.Top = Form1.Height - 1065
>    InputBox.Width = Form1.Width - 225
>    Text1.Top = Form1.Height - 705
>End Sub

That code is not critical, but here is better way to do it:

Private Sub Form_Resize()
    On Error Resume Next
    If WindowState <> vbMinimized Then
        ' your resize code goes here
        ' ...
    End If
End Sub

>    Text1.Top = Form1.Height - 705

You don't use form name, but *Me* to identify right form instance:
      Text1.Top = Me.Height - 705

Also, we don't use Width and Height properties of the Form to position controls.
Controls should be positioned relative to client coordinates.
     Text1.Top = Me.ScaleHeight - 330
That is what you should use in quick applications, e.g. for 'in house' use.

If you are going to distribute your app, some clients will have Large Fonts, and 330 will have different meaning:
330 - 22 pixels (if settings = Small Fonts)
330 - 27 pixels (if settings = Large Fonts)

So, here is better code:
     Text1.Top = Me.ScaleHeight - 22 * Screen.TwipsPerPixelY

Again, that is not critical part, but I think you should know it.


>Just a thought - what's the maximum capacity of a RichTextBox?

I don't know maximum, but 20 MB files work OK.
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6469326
Ahh, thanks for that. Useful stuff. :)

Is the Text property of a RichTextBox stored as a String? I was looking through the documentation for the String data type. A fixed length String has a capacity of 64k; a variable-length String has a capacity of 2GB.

If it can hold 20MB, I'm going to hazard a guess that it's stored as a variable-length String and thus has a capacity of 2GB (?).
0
 
LVL 15

Expert Comment

by:ameba
ID: 6469435
Well, it is not stored as VB variable-length String, that control is certainly not created in VB.
If you have many MB of text, you should not use wrapping and you should not resize control.

Maybe you can test its capacity and tell us what is practical limit  :-)

WordPad uses the same control (RichEdit).

MS Word is not very good if document is over 30MB.

Normal textbox can hold 20-30K.
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6478427
sridhar_PJ: go to http://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=visualbasic&qid=20182221 and collect your points for the code to keep the TextBox scrolled to bottom.

roverm: http://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=visualbasic&qid=20182223 for the RichTextBox suggestion.
0
 
LVL 1

Author Comment

by:Subhuman
ID: 6478430
ameba: thanks for the general advice. :)
0
 
LVL 15

Expert Comment

by:ameba
ID: 6478944
Thank you :)
0
 
LVL 12

Expert Comment

by:roverm
ID: 6483573
Thanks !

D'Mzzl!
RoverM
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
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…

706 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

19 Experts available now in Live!

Get 1:1 Help Now