Link to home
Start Free TrialLog in
Avatar of Subhuman
Subhuman

asked on

TextBox - Need more functionality.

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.
Avatar of roverm
roverm
Flag of Netherlands image

Replace the TextBox for a listbox, then insert a new item:

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

D'Mzzl!
RoverM
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
Avatar of Subhuman
Subhuman

ASKER

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

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

D'Mzzl!
RoverM
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
BTW: The RichTextbox control wraps the line if it's too long.
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.
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"
Ahh, sweet. Damn, this topic area is fast.

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

No wonder. ;)
Of course it's popular - there are many VB programmer - you can be VB programmer after ... 3 hours.  :-)
3 hours ? Hmmmmm, so I still have got a learning time left ;-)
*grins*

*busily saving these pages to disk so I can get at them from my other computer, where I have VB installed*
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.
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

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?
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?

ASKER CERTIFIED SOLUTION
Avatar of ameba
ameba
Flag of Croatia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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 (?).
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.
sridhar_PJ: go to https://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: https://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=visualbasic&qid=20182223 for the RichTextBox suggestion.
ameba: thanks for the general advice. :)
Thank you :)
Thanks !

D'Mzzl!
RoverM