Thursday, July 31, 2014

Visual Basic 2010 line counter

As I stated I can't use a Label on the left. It is too difficult to attempt to work with in my opinion.


Well this seems to work.


Known Issues


The only noticeable issues I see is if you hold down an up or down arrow key to move the caret in RichTextBox2 (RTB2). RichTextBox1 (RTB1) and Label1 do not update while the arrow key is held down. Once the arrow key is let up then RTB2 will scroll to a new position if necessary and Label1 will update to the line the caret is currently on.


And for some reason VScrollBar1 may have room left between the scroll button and scroll stop at the top or bottom of the scroll after both RTB's are already at the top or bottom of the scroll if I remember correctly.


Controls


The Form contains four controls. A label (Label1), two RichTextBoxes (RichTextBox1 on the left and RichTextBox2 to the right of RTB1) and a VScrollBar (VScrollBar1).


RTB1 and RTB2 must use the same font, font size, font style AFAIK because that can affect the line height of a line which can make scroll values no longer equitable between the RTB's.


WordWrap can not be used.


They both require the same height as well as Forced horizontal scrollbars and NO vertical scrollbars. Their vertical scrollbar is handled by VScrollBar1.


RTB1 is set to not have a tabstop and as read only. By not having a tabstop the RTB1 will not focus when the app launches so RTB2 will have the caret blinking in it rather than having to select RTB2 to remove focus from RTB1.


Anchors are shown in the code except for Label1 which is anchored top/left. Label1 is recentered over RTB2 whenever its text changes.


If you set RTB1's width correctly it is unlikely you will ever need to use the forced horizontal scrollbar in it. However it has to be there since it effects vertical scrolling with regard to displaying RTB1's line number next to the appropriate line in RTB2. Therefore RTB2 also requires this scrollbar forced. Figuring that out was a headache. Anyhow if you don't want to see the forced horizontal scrollbar in RTB1 you can lay a panel over it to cover it and provide the panel with the same backcolor as the form or something.


Code


The code now displays in RTB1 and Label1 the first line of text in RTB2 as Line 1 rather than Line 0.


There are two Pinvoke functions used in the code at the top of it. They appear the same but actually have different variable types in them.


If you have any questions about the rest of the code then ask them and I will attempt to answer them.


Other


You can copy and paste text into RTB2.


The mouse can be used to select text for deletion however this does not move the caret when that is performed so when you release the mouse the Label shows information on where the caret is not where the mouse was released at.


As you press keys in RTB2 both RTB1 and Label1 update constantly.


You can delete all of the text in RTB2 and everything updates.


Images are just two animated .Gifs of app working. May need to zoom in with WebBrowser to see them better.



Option Strict On

' For thread http://ift.tt/1zBjkVd

Public Class Form1

Declare Function SendMessage Lib "user32.dll" Alias "SendMessageW" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

Dim WM_VSCROLL As Integer = &H115

Private Const SB_LINEUP As Integer = &H0
Private Const SB_LINEDOWN As Integer = &H1
Private Const SB_PAGEUP As Integer = &H2
Private Const SB_PAGEDOWN As Integer = &H3
Private Const SB_TOP As Integer = &H6
Private Const SB_BOTTOM As Integer = &H7
Private Const SB_ENDSCROLL As Integer = &H8

Declare Function SendMessage Lib "user32.dll" Alias "SendMessageW" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByRef lParam As Point) As Integer

Const WM_USER As Integer = &H400
Const EM_GETSCROLLPOS As Integer = WM_USER + 221
Const EM_SETSCROLLPOS As Integer = WM_USER + 222

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

Me.CenterToScreen()
Me.BackColor = Color.AliceBlue

RichTextBox1.BackColor = Color.Silver
RichTextBox1.ForeColor = Color.White
RichTextBox1.Font = New Font("Cambria", 12)
RichTextBox1.ScrollBars = RichTextBoxScrollBars.ForcedHorizontal
RichTextBox1.Anchor = CType(AnchorStyles.Left + AnchorStyles.Top + AnchorStyles.Bottom, AnchorStyles)
RichTextBox1.WordWrap = False
RichTextBox1.ReadOnly = True
RichTextBox1.TabStop = False

RichTextBox2.Font = New Font("Cambria", 12)
RichTextBox2.ScrollBars = RichTextBoxScrollBars.ForcedHorizontal
RichTextBox2.Anchor = CType(AnchorStyles.Left + AnchorStyles.Top + AnchorStyles.Right + AnchorStyles.Bottom, AnchorStyles)
RichTextBox2.WordWrap = False
RichTextBox2.ReadOnly = False
RichTextBox2.TabStop = True

VScrollBar1.Value = 0
VScrollBar1.Maximum = 100
VScrollBar1.Anchor = CType(AnchorStyles.Top + AnchorStyles.Right + AnchorStyles.Bottom, AnchorStyles)

Label1.BackColor = Color.SlateGray
Label1.ForeColor = Color.Aqua
Label1.Font = New Font("Book Antiqua", 14)
Label1.Text = "Waiting"
Label1.Left = CInt(RichTextBox2.Left + (RichTextBox2.Width / 2) - (Label1.Width / 2))

End Sub

Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize
Label1.Left = CInt(RichTextBox2.Left + (RichTextBox2.Width / 2) - (Label1.Width / 2))
End Sub

Private Sub RichTextBox2_TextChanged(sender As Object, e As EventArgs) Handles RichTextBox2.TextChanged
If RichTextBox2.Text <> "" Then
RichTextBox1.Clear()
Dim Temp As String = ""
For i = 0 To RichTextBox2.Lines.Count - 1
Temp &= (i + 1).ToString & ". = " & RichTextBox2.Lines(i).Length.ToString & vbCrLf
Next
Temp = Temp.Remove(Temp.Count - 2, 2)
RichTextBox1.Text = Temp
VScrollBar1.Maximum = RichTextBox2.Lines.Count
VScrollBar1.Value = RichTextBox2.GetLineFromCharIndex(RichTextBox2.SelectionStart)
Label1.Text = "RTB2 Line Nr = " & (RichTextBox2.GetLineFromCharIndex(RichTextBox2.SelectionStart) + 1).ToString & ", Length = " & RichTextBox2.Lines(RichTextBox2.GetLineFromCharIndex(RichTextBox2.SelectionStart)).Length.ToString & "."
Label1.Left = CInt(RichTextBox2.Left + (RichTextBox2.Width / 2) - (Label1.Width / 2))
Dim RTB2SP As Point
SendMessage(RichTextBox2.Handle, EM_GETSCROLLPOS, 0, RTB2SP)
SendMessage(RichTextBox1.Handle, EM_SETSCROLLPOS, 0, RTB2SP)
Else
RichTextBox1.Clear()
End If
End Sub

Private Sub RichTextBox2_KeyUp(sender As Object, e As KeyEventArgs) Handles RichTextBox2.KeyUp
Dim RTB2SP As Point
SendMessage(RichTextBox2.Handle, EM_GETSCROLLPOS, 0, RTB2SP)
SendMessage(RichTextBox1.Handle, EM_SETSCROLLPOS, 0, RTB2SP)
VScrollBar1.Value = RichTextBox2.GetLineFromCharIndex(RichTextBox2.SelectionStart)
If RichTextBox2.Text <> "" Then
Label1.Text = "RTB2 Line Nr = " & (RichTextBox2.GetLineFromCharIndex(RichTextBox2.SelectionStart) + 1).ToString & ", Length = " & RichTextBox2.Lines(RichTextBox2.GetLineFromCharIndex(RichTextBox2.SelectionStart)).Length.ToString & "."
Label1.Left = CInt(RichTextBox2.Left + (RichTextBox2.Width / 2) - (Label1.Width / 2))
End If
End Sub

Private Sub RichTextBox2_MouseMove(sender As Object, e As MouseEventArgs) Handles RichTextBox2.MouseMove
Dim RTB2SP As Point
SendMessage(RichTextBox2.Handle, EM_GETSCROLLPOS, 0, RTB2SP)
SendMessage(RichTextBox1.Handle, EM_SETSCROLLPOS, 0, RTB2SP)
If RichTextBox2.Text <> "" Then
Label1.Text = "RTB2 Line Nr = " & (RichTextBox2.GetLineFromCharIndex(RichTextBox2.SelectionStart) + 1).ToString & ", Length = " & RichTextBox2.Lines(RichTextBox2.GetLineFromCharIndex(RichTextBox2.SelectionStart)).Length.ToString & "."
Label1.Left = CInt(RichTextBox2.Left + (RichTextBox2.Width / 2) - (Label1.Width / 2))
End If
End Sub

Dim VScrollFirst As Integer = 0
Dim VScrollSecond As Integer = 0

Private Sub VScrollBar1_Scroll(sender As Object, e As ScrollEventArgs) Handles VScrollBar1.Scroll
If RichTextBox1.Lines.Count > 0 Then
VScrollFirst = VScrollBar1.Value
If VScrollFirst > VScrollSecond Then
For i = 1 To VScrollFirst - VScrollSecond
SendMessage(RichTextBox1.Handle, WM_VSCROLL, CType(SB_LINEDOWN, IntPtr), IntPtr.Zero) ' Scrolls down
SendMessage(RichTextBox2.Handle, WM_VSCROLL, CType(SB_LINEDOWN, IntPtr), IntPtr.Zero) ' Scrolls down
Next
ElseIf VScrollFirst < VScrollSecond Then
For i = 1 To VScrollSecond - VScrollFirst
SendMessage(RichTextBox1.Handle, WM_VSCROLL, CType(SB_LINEUP, IntPtr), IntPtr.Zero) ' Scrolls up
SendMessage(RichTextBox2.Handle, WM_VSCROLL, CType(SB_LINEUP, IntPtr), IntPtr.Zero) ' Scrolls up
Next
End If
VScrollSecond = VScrollBar1.Value
End If
End Sub

End Class





La vida loca


No comments:

Post a Comment