how to keep the scrollbar at the bottom visual basic - vba

In my a form, I have a rich text box with vertical scrollbars. I have set it so that a line is read from a local text file, and added to the existing text in the text box. The following code makes it so that a line is read from the text file, there is 3 seconds of pause, and then another line is read and added to the existing text. This is done the emulate the feeling of a messenger application, so the 3 seconds of pause is absolutely necessary.
However, I have found that whenever a new line is added and there is enough text in the rich text box for the scrollbar to appear, the scrollbar will jump to the top. Every new line is added to the bottom, so this is extremely annoying, because it means the user is sent all the way up to the top of the text every single time there is a new line added.
Is there anything I can do to prevent this? i.e: locking the scrollbar to the bottom? Or having the scrollbar automatically scroll down to the bottom whenever there is a new line added?
If you need any pictures or further code, please let me know.
Dim i As Integer = 0
Call Pause(3)
RichTextBox1.Text = R.ReadLine()
Do Until i = lineCount
Call Pause(3)
RichTextBox1.Text = RichTextBox1.Text + vbCrLf + vbCrLf + R.ReadLine()
i = i + 1
Loop
The pause subroutine:
Public Sub Pause(ByVal seconds As Single)
Dim newDate As Date
newDate = DateAndTime.Now.AddSeconds(seconds)
While DateAndTime.Now.Second <> newDate.Second
Application.DoEvents()
End While
End Sub

After the TextChangedEvent you can try to set the caret to the last postiton and then use ScrollToCaret

Related

Check if data exist in file

I need help. I want to check if user exists by entering their ic number and I want to display another rest of their data by using file in visual basic. Unfortunately, an error occurs while doing that. I need help. If the user exists, then It will display automatically name, email, address and so on but if a user doesn't exist, then it shows message box. Here I attached the image of the display screen and the code. Please help me. Thank you.
Public Class Form1
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
Dim userFile As String = "C:\Users\HP\Desktop\userdata.txt"
Dim inputFile As String
If System.IO.File.Exists(userFile) = True Then
Dim objReader As New System.IO.StreamReader(userFile)
Dim intIc As Integer
Dim intCount As Integer = 0
Dim strName As String
Dim strEmail As String
Dim intPhoneNum As String
Dim strAdd1 As String
Dim strAdd2 As String
Dim intPostcode As String
Dim strState As String
Do While objReader.Peek() <> -1
intIc(intCount) = Convert.ToInt64(objReader.ReadLine())
If (intIc(intCount).Convert.ToInt64(objReader.ReadLine())) Then
strName(intCount) = objReader.ReadLine()
strEmail(intCount) = objReader.ReadLine()
intPhoneNum(intCount) = Convert.ToInt32(objReader.ReadLine())
strAdd1(intCount) = objReader.ReadLine()
strAdd2(intCount) = objReader.ReadLine()
intPostcode(intCount) = Convert.ToInt32(objReader.ReadLine())
strState(intCount) = objReader.ReadLine()
lblName.Text = strName
lblEmail.Text = strEmail
lblNum.Text = intPhoneNum
lblAdd1.Text = strAdd1
lblAdd2.Text = strAdd2
lblPostcode.Text = intPostcode
lblState.Text = strState
objReader.Close()
Else
MessageBox.Show("User Does Not Exist")
End If
intCount = intCount + 1
Loop
Else
MessageBox.Show("File Does Not Exist")
End If
End Sub
End Class
Your task, the easy way:
make a new project
add a DataSet to this new project
open the DataSet, in the properties call it something sensible
Right click the surface, add a new datatable, name it Person
Right click the datatable, add a column, name it IC. Right click, add column, name it Name. Keep going until you added all the fields you want to track(email,phone,address1 etc)
save the DataSet
open the form
show the datasources window (view menu.. other windows)
expand the nodes til you can see Person
click the drop down next to Person, switch from DataGridview to Details
drag Person onto the form. Text boxes, labels etc appear. In the tray at the bottom more things appear
add a textbox to the form and call it searchTextBox
add a search button to the form, double click it, add this line of code to the click handler:
personBindingSource.Filter = '[ic] LIKE '" & searchTextBox.Text & "'"
If personBindingSource.Count = 0 Then MessageBox.Show("No records")
double click the form background to add a form load event handler, put this line of code:
If IO.File.Exists("data.xml") Then .ReadXml("data.xml")
switch back to designer, single click the form background and switch to event properties of the form, add a handler to the form closing event:
.WriteXml("data.xml")
That's it, you now have a program that will open, read and fill the DataSet with data from the data.xml file, it will search it when you type something in the ic box, the text boxes use databinding to show values automatically, and when you close the program it will save updates data. The only task now is to load the xml file with data.
When the textboxes were added to the form you should also have seen a bar appear across the top with some left/right controls in and a green plus. Click the green plus, type some data in, click it again, type more data. Navigating back, if you're adding new data, will commit the data. If you're looking at existing data, editing it then navigating will commit it
After you added some data, you can search for existing data using the search box. When you've searched for a single value it should be the only thing shown and the nav will show "1 of 1". To get back to the mode where all data is showing, put a single asterisk in the search box and hit search; it should show the number records in the top bar and you can scroll them with the arrows.
If you already have lots of data in a file, like you use in your question, you can read it in a loop (like you do in your question, except don't use that code exactly cos it has loads of errors) as a one time thing and assign it into the datatable, or you can manipulate it directly into being XML in a text editor. This is easy to do if you have a capable text editor but I'll not offer any particular advice on it in case you don't have a large amount of existing data. Ask a new question if you do

Remove previous selection highlighting in RichTextBox without scrolling

I have a form with a RichTextBox (RTB) and a listBox.
When the end user selects an item in the listbox, any matched text in the RTB is highlighted (full code removed for brevity).
re = New Regex(txtToFind)
For Each m In re.Matches(rtbMain.Text)
rtbMain.[Select](m.Index, m.Length)
rtbMain.SelectionColor = Color.White
rtbMain.SelectionBackColor = System.Drawing.SystemColors.Highlight
Next
When the user left mouse clicks in the RTB I want the previously highlighted text to be cleared. This is the standard windows behaviour - If you manually select some text in an RTB with the mouse, it is highlighted, click anywhere back in the RTB and the highlighting disappears. My programatically selected text remains selected.
I have some partially working code (below). I can clear all the highlighted text, but it is by process of selecting everything, changing the colour back and then deselecting it again. I know it is not efficient, the RTB flickers and I am sure it is not the correct way to do it. Can I emulate the standard windows behaviour?
Also using my code, it scrolls to the first line when entering the RTB a second time.
I get around this the first time by returning the top visible line index before clearing the text and then selecting that line again afterwards and using ScrollToCaret(). This only works on the first pass. Subsequent MouseDown events select the top row regardless of where the user has clicked so nothing can be manually highlighted in the RTB.
Private Sub rtbMain_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles rtbMain.MouseDown
Dim topIndex As Integer = rtbMain.GetCharIndexFromPosition(New System.Drawing.Point(1, 1))
Dim topLine As Integer = rtbMain.GetLineFromCharIndex(topIndex)
If e.Button = Windows.Forms.MouseButtons.Right Then
'Do nothing (Context Menu)
Else
rtbMain.SelectAll()
rtbMain.SelectionColor = Color.Black
rtbMain.SelectionBackColor = Color.White
rtbMain.DeselectAll()
rtbMain.Select(topIndex, 0)
rtbMain.ScrollToCaret()
End If
End Sub
I need my code to emulate the standard windows behaviour - clear selected text highlighting on MouseDown and leave the mouse cursor where the user has clicked.
Any help anyone can offer is gratefully appreciated.
I think you may be overthinking this one.
In the right click event, try RtbMain.SelectionLength = 0

Force a MultiLine TextBox Horizontal ScrollBar to the left

I have a MultiLine TextBox that is updated over a period of time as an app runs, and I've managed to make it so that the TextBox scrolls to the bottom, ensuring that the latest entry is always shown.
However, sometimes the text is quite long and goes off of the side of the TextBox, so the Horizontal ScrollBar scrolls to the right.
How can I amend the code below so that the ScrollBar is always to the left, meaning that the beginning of lines is always visible? Please note that I do not wish to wrap text, as I can't have one entry on multiple lines. Thanks.
Private Sub UpdateCurrentProgress(ByVal Text As String)
If Text = "" Then Exit Sub
Dim Textbox As TextBox = Me.txtCurrentProgress
If Textbox.Text <> "" Then Text = vbCrLf & Text
Textbox.AppendText(Text)
Textbox.Select(Textbox.TextLength, 0)
Textbox.ScrollToCaret()
End Sub
You can select the first char at the current line like this:
Me.TextBox1.Select(Me.TextBox1.GetFirstCharIndexOfCurrentLine(), 0)
If I understand your problem correctly, then you need to get first the last line index and then select the first char of that line.
Dim lineNumber = textBox1.Lines.Count()-1
textBox1.Select(textBox1.GetFirstCharIndexFromLine(lineNumber), 0)

autoscroll to bottom of multiline textbox being updated by backgroundworker

I have a background worker control that is set to perform a task, and update a multiline text box on my main UI using a delegate procedure. this is all working perfectly, however once the updating scrolls off the bottom of the text box, the scroll bars appear, but the continuous refreshing causes the text box to stay locked at the top. Ideally, I would like the text box to auto-scroll itself to the bottom to show the latest entry in real-time. What would be the best way to implement this?
I have tried using the scrolltocaret() method, with and without a SelectionStart = txtlog.Text.Length command preceding it. perhaps I'm putting it in the wrong place?
some code samples below:
Delegate code:
Delegate Sub updateresults_delegate(ByVal textbox As TextBox, ByVal text As String)
Private Sub updatelog_threadsafe(ByVal textbox As TextBox, ByVal text As String)
If textbox.InvokeRequired Then
Dim mydelegate As New updateresults_delegate(AddressOf updatelog_threadsafe)
Me.Invoke(mydelegate, New Object() {textbox, text})
'Me.txtlog.SelectionStart = txtlog.Text.Length
'Me.txtlog.ScrollToCaret()
Else
textbox.Text = text
End If
End Sub
main backgroundworker activity:
For i As Integer = val1 To val2
'generate an IP address from split host parts and current value of i
host = s1(0) & "." & s1(1) & "." & s1(2) & "." & i
Try 'attempt to ping the IP
Dim reply As PingReply = pingsender.Send(host, timeoutval, buffer, options)
If reply.Status = IPStatus.Success Then
name = System.Net.Dns.GetHostEntry(host)'get DNS entry
resulttext += String.Format("{1} - {2}: reply: Bytes={3} time{4} TTL={5}{0}", vbCrLf, name.HostName, reply.Address.ToString, reply.Buffer.Length, getms(reply.RoundtripTime), reply.Options.Ttl) 'print out success text
Else
resulttext += String.Format(" {1}: Ping failed. {2}{0}", vbCrLf, host, reply.Status.ToString) 'print out fail text
End If
updatelog_threadsafe(txtlog, resulttext) 'send text to textbox
System.Threading.Thread.Sleep(1000)
Catch ex As Exception
End Try
Next
I guess my main question is: I'm pretty certain that the textbox.scrolltocaret() is the correct method to use for what I want, but where is the best place for me to put it? I've tried it in the delegate, the main backgroundworker, as well as before & after the runworkerasync() method. none of these worked, and now I'm stumped!
Try it this way:
'textbox.Text = text
textbox.AppendText(text)
The code you commented out wasn't running on the GUI thread, and as M Granja pointed out, AppendText will automatically scroll to the appended text in the box, so no need to call ScrollToCaret.
xxx.SetFocus ' xxx = the name of the textbox
SendKeys "^{END}" ' pop to last line

Show only latest lines in VB Label

Problem
In a VB label, if there are more lines than the fixed height can support, then the additional lines get cut off and the user only sees the first couple of lines.
I need it to be completely opposite. I want to see the latest 5 or 6 lines. What that means is that if there is more lines than the fixed height of the label can show, then instead of simply cutting them off, all the lines should move up with the latest one at the bottom. The top lines can be cut off, but the latest one needs to be in the bottom.
Example of what I am trying to do
If you look at a console and enter a command like dir, then it lists the latest directories, but you see latest read directory at the bottom. Basically, you see the latest directory it read. You only see the latest 5 or 6 directories it read instead of seeing every printed line.
Another Example: Look a textbox. If you type in more text than the height, then you see that the textbox autoscrolls with you on the text and shows the latest lines while the older ones keep moving up and eventually get cut-off until you move the scroll bar up. I need it to be exactly the same, except without scroll bars.
One more example: If you set the TextAlign property of the label to Bottom Center, then you see the text move up as you add more lines. The problem occurs when the label is filled with the lines and the text exceeds the height and gets cut off. That shouldn't happen. The text at top should get cut off, but the latest line should keep coming from the bottom.
Solutions recommended by others
The only solution that I have been given is to create a custom control derived from the label.
Is there any other way that this can be done?
Thank You for your help.
Drop a button and a label on a NEW form (so as not to mess up your existing code) and copy and paste the code below and click the button repeatedly and see if this solves your issue.
obviously if it does you still have to mess with the code so it suits your particular needs.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Static TextLines As Generic.List(Of String) = Nothing
Static SingleLineHeight As Integer = Nothing
Static maxrows As Integer
Static qty As Integer = Nothing
Dim text As String = Nothing
Dim counta As Integer = Nothing
'
'set MAX ROWS
maxrows = 6
' Initalise
If TextLines Is Nothing Then TextLines = New Generic.List(Of String)
If SingleLineHeight = 0 Then
Label1.Text = "Test Line"
SingleLineHeight = Label1.Font.Height
Label1.Text = ""
End If
'
'process
qty = qty + 1
text = "Line Number " & qty
TextLines.Add(text)
Label1.Text = ""
If TextLines.Count > maxrows - 1 Then TextLines.RemoveAt(0)
For counta = 0 To TextLines.Count - 1
Label1.Text = Label1.Text & TextLines(counta) & vbCrLf
Next
End Sub