A program to highlight words in a word document - vb.net

I want a VB program that will allow me to put words into a text box on VB, (preferably those words are saved when closing the program so they are there for next time) have those words split more than likely with the s.Split to allow for multiple words, for example “famine”, “viewing”, “article”
That's the first part, the second part is I want the program to read the text in any open word document and those words in the text box, that are also in the word document will be highlighted. If it can't be done so it can read any open word document, then is it possible to make it able to attach a word document for it to read?
I want a program that you can write multiple words on, then have those words become highlighted in any word document.

I have been wrote this snippet time ago, it will teach you how to find and highlight word/phrases using Regular Expressions, you could easily adapt it to a WORD document reading, then the most important part of the problem would be solved with this:
#Region " [RichTextBox] FindNext RegEx "
' [ FindNext RegEx ]
'
' //By Elektro H#cker
'
' Examples :
'
' RichTextBox1.Text = "Hello World!, Hello World!, Hello World!"
'
' FindNext(RichTextBox1, "hello", FindDirection.Down, System.Text.RegularExpressions.RegexOptions.IgnoreCase, Color.LightBlue, Color.Black)
' FindNext(RichTextBox1, "hello", FindDirection.Up, System.Text.RegularExpressions.RegexOptions.IgnoreCase, Color.Red, Color.Black)
'
' Private Sub RichTextBox_Enter(sender As Object, e As EventArgs) ' Handles RichTextBox1.Enter
' ' Restore Selection Colors before search next match.
' sender.SelectionBackColor = DefaultBackColor
' sender.SelectionColor = DefaultForeColor
' End Sub
Public Enum FindDirection As Short
Up = 0
Down = 1
End Enum
' FindNext
Private Sub FindNext(ByVal [Control] As RichTextBox, _
ByVal SearchText As String, _
ByVal Direction As FindDirection, _
Optional ByVal IgnoreCase As System.Text.RegularExpressions.RegexOptions = System.Text.RegularExpressions.RegexOptions.None, _
Optional ByVal Highlight_BackColor As Color = Nothing, _
Optional ByVal Highlight_ForeColor As Color = Nothing)
If [Control].TextLength = 0 Then Exit Sub
' Start searching at 'SelectionStart'.
Dim Search_StartIndex As Integer = [Control].SelectionStart
' Stores the MatchIndex count
Dim matchIndex As Integer = 0
' Flag to check if it's first find call
Static First_Find As Boolean = True
' Checks to don't ommit the selection of first match if match index is exactly at 0 start point.
If First_Find _
AndAlso Search_StartIndex = 0 _
AndAlso Direction = FindDirection.Down Then
Search_StartIndex = -1
First_Find = False
ElseIf Not First_Find _
AndAlso Search_StartIndex = 0 _
AndAlso Direction = FindDirection.Down Then
First_Find = False
Search_StartIndex = 0
End If
' Store the matches
Dim matches As System.Text.RegularExpressions.MatchCollection = _
System.Text.RegularExpressions.Regex.Matches([Control].Text, _
SearchText, _
IgnoreCase Or If(Direction = FindDirection.Up, _
System.Text.RegularExpressions.RegexOptions.RightToLeft, _
System.Text.RegularExpressions.RegexOptions.None))
If matches.Count = 0 Then First_Find = True : Exit Sub
' Restore Highlight colors of previous selection
[Control].SelectionBackColor = [Control].BackColor
[Control].SelectionColor = [Control].ForeColor
' Set next selection Highlight colors
If Highlight_BackColor = Nothing Then Highlight_BackColor = [Control].BackColor
If Highlight_ForeColor = Nothing Then Highlight_ForeColor = [Control].ForeColor
' Set the match selection
For Each match As System.Text.RegularExpressions.Match In matches
matchIndex += 1
Select Case Direction
Case FindDirection.Down
If match.Index > Search_StartIndex Then ' Select next match
[Control].Select(match.Index, match.Length)
Exit For
ElseIf match.Index <= Search_StartIndex _
AndAlso matchIndex = matches.Count Then ' Select first match
[Control].Select(matches.Item(0).Index, matches.Item(0).Length)
Exit For
End If
Case FindDirection.Up
If match.Index < Search_StartIndex Then ' Select previous match
[Control].Select(match.Index, match.Length)
Exit For
ElseIf match.Index >= Search_StartIndex _
AndAlso matchIndex = matches.Count Then ' Select last match
[Control].Select(matches.Item(0).Index, matches.Item(0).Length)
Exit For
End If
End Select
Next match
' Set the current selection BackColor
[Control].SelectionBackColor = Highlight_BackColor
' Set the current selection ForeColor
[Control].SelectionColor = Highlight_ForeColor
' Scroll to Caret/Cursor selection position
[Control].ScrollToCaret()
End Sub
#End Region
Also here you can see a video demostration: http://www.youtube.com/watch?v=mWRMdlC5DH8

Related

Search for a Word in a RichTextbox and set its forecolor in VB.NET

I have made a program that displays an example of a particular piece of code. The available pieces of code come from a database. When the user selects an example the code itself is displayed in a RichTextbox. I also want the words to have coloring just like it would in the compiler.
I have a list of words and their associated RGB colors. I have another method which loops through the list of words and sends each one to this function:
Private Sub FindAndFormatWords(ByVal SearchString As String, ByVal r As Integer, ByVal g As Integer, ByVal b As Integer)
If r > -1 And g > -1 And b > -1 And SearchString <> "" Then
Dim richText As String = rtxtCode.Text.ToLower() 'store the rtxtCode as all lower case
Dim keyText As String = SearchString.ToLower() 'store the SearchString as all lower case
Dim wordIndex As Integer = 0
While (wordIndex < richText.LastIndexOf(keyText, StringComparison.InvariantCultureIgnoreCase)) 'loop through each of the instances of the lowercase searchString in the lowercase textbox
wordIndex = richText.IndexOf(keyText, wordIndex) 'get the index of the next instance of the search string
rtxtCode.SelectionStart = wordIndex 'select the text that contains the search string
rtxtCode.SelectionLength = keyText.Length
rtxtCode.SelectionColor = Color.FromArgb(r, g, b) 'give the selected string color
rtxtCode.SelectionFont = New Font("Verdana", 9, FontStyle.Regular)
wordIndex = wordIndex + keyText.Length + 1
End While
Else
MessageBox.Show("Error (1013): " & SearchString & " failed. Missing information.")
End If
End Sub
This works perfectly well. EXCEPT it does not find the occurrence of a word when it is the very first word. When the word begins at character index 0 in the RichTextbox, it cannot find the word. It will find every occurrence of the word after character index 0.
How can I correct this so that it finds words even at index 0?
Here's your original code refactored a bit, and searching forwards instead of backwards. It already can do a case-insensitive match, you don't have to convert to all lower case:
Private Sub FindAndFormatWords(ByVal SearchString As String, ByVal r As Integer, ByVal g As Integer, ByVal b As Integer)
If r > -1 And g > -1 And b > -1 And SearchString <> "" Then
Dim C As Color = Color.FromArgb(r, g, b)
Dim F As New Font("Verdana", 9, FontStyle.Regular)
Dim wordIndex As Integer = rtxtCode.Find(SearchString, 0, RichTextBoxFinds.NoHighlight)
While (wordIndex <> -1)
rtxtCode.SelectionStart = wordIndex
rtxtCode.SelectionLength = SearchString.Length
rtxtCode.SelectionColor = C
rtxtCode.SelectionFont = F
wordIndex = wordIndex + SearchString.Length
If (wordIndex < rtxtCode.Text.Length) Then
wordIndex = rtxtCode.Find(SearchString, wordIndex, RichTextBoxFinds.NoHighlight)
Else
wordIndex = -1
End If
End While
Else
MessageBox.Show("Error (1013): " & SearchString & " failed. Missing information.")
End If
End Sub
This code correctly finds each occurrence of a word. Even when the word begins at char index 0. You must Imports System.Text.RegularExpressions to use Regex.
Private Sub FindAndFormatWords(ByVal SearchString As String, ByVal r As Integer, ByVal g As Integer, ByVal b As Integer)
If r > -1 And g > -1 And b > -1 And SearchString <> "" Then
Dim pattern As String = SearchString
Dim regx As New Regex(pattern, RegexOptions.Compiled Or RegexOptions.IgnoreCase)
Dim matches As MatchCollection = regx.Matches(rtxtCode.Text)
For Each match As Match In matches
rtxtCode.Select(match.Index, match.Length)
rtxtCode.SelectionColor = Color.FromArgb(r, g, b) 'give the selected string color
Next
Else
MessageBox.Show("Error (1013): " & SearchString & " failed. Missing information.")
End If
End Sub

Excel VBA - get double-clicked word in userform multiline textbox

The Task: my goal is to extract the highlighted word from a multi-line TextBox in a UserForm after a double-click.
Used Properties: Whereas it's absolutely no problem to highlight a given string position via the TextBox properties .SelStart and .SelLength, it isn't as easy the other way round: a users DblClick highlights a whole word string, but Excel doesn't reset the .SelStart value at the starting position of the highlighted text as one could assume, the .SelStart value remains there where the user double-clicks.
My Question: is there any possibility to catch the highlighted text starting position directly as set by the application?
My work around: I will demonstrate a very simple work around to reconstruct the high-lighted word just by checking the following and preceding e.g. 20 letters right and left to the actual clicking position (of course, one could use regex as well and refine the example code):
Private Sub TextBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Dim sTxt As String, sSel As String ' edited due to comment below
Dim selPos As Long, i As Long, i2 As Long ' "
TextBox1.SetFocus
' this is the User's DblClick Position,
' but not the starting Position of the highlighted Word
' after DblClick
selPos = TextBox1.SelStart
sTxt = Replace(Replace(TextBox1.Text, vbCrLf, vbLf), "\", ".")
If TextBox1.SelLength > 0 Then
sSel = TextBox1.SelText
Else
sSel = Mid(sTxt, selPos + 1, 5)
' check the preceding 20 letters
i = selPos
For i = selPos To (selPos - 20) Step -1
If i < 0 Then Exit For
Select Case Left(Mid(sTxt, i + 1), 1)
Case " ", vbLf, ":", ".", "?", """", "'", "(", ")"
sSel = Mid(sTxt, i + 2, selPos - i)
Exit For
End Select
Next i
' check the following 20 letters
i2 = selPos
For i2 = selPos To (selPos + 20)
If i2 > Len(sTxt) Then Exit For
Select Case Left(Mid(sTxt, i2 + 1), 1)
Case " ", vbLf, ":", ".", "?", """", "'", ")", "("
sSel = Replace(Mid(sTxt, i + 2, i2 - i - IIf(i = i2, 0, 1)), vbLf, "")
Exit For
End Select
Next i2
End If
' Show the highlighted word
Me.Label1.Text = sSel
End Sub
Additional explanations to found solution in UserForm code module (thx #Rory)
In order to actually get the double-clicked highlighted string from a multi-line textbox, you'll need three steps to solve the timing problem:
As the textbox position properties SelStart and SelLength aren't set yet in the DblClick event,
it's necessary to assign True to a boolean variable/marker (bCheck).
Use the MouseUp event to get the final position properties after checking for bCheck.
In order to count correctly, it'll be necessary to remove e.g. vbLf within the pair of carriage returns Chr(13) (=vbCr) and line feeds Chr(10) (=vbLf) on MS systems.
Caveat: Note that AFAIK Mac systems use only line feeds Chr(10) as ending sign, so IMO you can omit replacing in this case.
Final Code
Option Explicit
Private bCheck As Boolean
' [1] assign True to boolean variable
Private Sub TextBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
bCheck = True ' set marker to True
End Sub
Private Sub TextBox1_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If bCheck Then
bCheck = False ' reset marker to False
' [2][3] extract the highlighted doubleclicked word from multi-line textbox
MsgBox Trim(Mid(Replace(Me.TextBox1.Text, vbLf, ""), Me.TextBox1.SelStart + 1, Me.TextBox1.SelLength))
End If
End Sub
I think it's a timing issue. It seems to work if you use a flag variable and the MouseUp event in conjunction with the DblClick event:
Private bCheck As Boolean
Private Sub TextBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
bCheck = True
End Sub
Private Sub TextBox1_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If bCheck Then
bCheck = False
MsgBox Me.TextBox1.SelStart & "; " & Me.TextBox1.SelLength
End If
End Sub

How to show all validation errors as a list in my messagebox

I am having a problem with my code. I am trying to show all the validation errors in a message box. Can anyone tell me why only one of my errors is showing up in the box? I tried a couple more solutions and looked around but I need a little help please.
Public Class Form1
Private Sub btnCalculate_Click(sender As Object, e As EventArgs) Handles btnCalculate.Click
If Data_Validated_ok() = False Then Exit Sub
End Sub
Private Function Data_Validated_ok() As Boolean
Dim intErrCount As Integer
Dim strErrMessage As String = String.Empty
Dim ctrlError As New Collection
' make sure Premium channel is selected
If Me.lstPremium.SelectedIndex < 0 Then
intErrCount = intErrCount + 1
strErrMessage = intErrCount & ". Premium Channels is a required field." _
& vbCrLf
ctrlError.Add(lstPremium.SelectedIndex)
End If
' make sure a customer type is selected in the Radioboxes
If radBusiness.Checked = False And
radResidential.Checked = False Then
intErrCount = intErrCount + 1
strErrMessage = intErrCount & ".Customer Type is a required field." _
& vbCrLf
ctrlError.Add(radBusiness.Checked, radResidential.Checked)
End If
' make sure a business customer checks at least one option in the listbox
If radBusiness.Checked = True And Me.lstConnections.SelectedIndex < 0 Then
intErrCount = intErrCount + 1
strErrMessage = intErrCount & ". Business Customers must select 1 or more Connection." _
& vbCrLf
ctrlError.Add(lstConnections.SelectedIndex)
End If
' show all errors in a messagebox
If intErrCount > 0 Then
MessageBox.Show(strErrMessage, "Validation Rule(s)", MessageBoxButtons.OK, MessageBoxIcon.Information)
Dim ctrl As Control
ctrl = ctrlError.Item(1)
ctrl.Focus()
Return False
Else
Return True
End If
End Function
How about storing each error in a List(Of String)? Your variable ctrlError is not storing controls, but integers and booleans - you should have casting errors there.
Private Function Data_Validated_ok() As Boolean
Dim errorMsgs As New List(Of String)
' make sure Premium channel is selected
If Me.lstPremium.SelectedIndex < 0 Then
errorMsgs.Add("Premium Channels is a required field.")
End If
' make sure a customer type is selected in the Radioboxes
If radBusiness.Checked = False AndAlso
radResidential.Checked = False Then
errorMsgs.Add("Customer Type is a required field.")
End If
' make sure a business customer checks at least one option in the listbox
If radBusiness.Checked = True And Me.lstConnections.SelectedIndex < 0 Then
errorMsgs.Add("Business Customers must select 1 or more Connection.")
End If
' show all errors in a messagebox
If errorMsgs.Count > 0 Then
MessageBox.Show(String.Join(Environment.Newline, errorMsgs.ToArray), "Validation Rule(s)", MessageBoxButtons.OK, MessageBoxIcon.Information)
Return False
Else
Return True
End If
End Function

How to search in listview

I am trying to create a Loop that will read through the information on my ListView through the SubItem to find the text that matches the text in my Textbox whenever I hit the search button and Focuses the listbox onto the matched text. Below is what I have but it keeps telling me that the value of string cannot be converted. I am also pretty sure that my numbers wont loop correctly but I am not really sure how to cause them to loop endlessly till end of statement.
Dim T As String
T = Lines.Text
For r As Integer = 0 to -1
For C As Integer = 0 to -1
If List.Items(r).SubItems(C).Text = Lines.Text Then
List.FocusedItem = T
End If
Next
Next
End Sub
I don't understand your code, but I do understand the question. Below is example code to search all rows and columns of a listview. Search is case insensitive and supports a "find next match" scenario. If a match or partial match is found in any column the row is selected. TextBox1 gets the text to find. FindBtn starts a new search.
Private SrchParameter As String = ""
Private NxtStrtRow As Integer = 0
Private Sub FindBtn_Click(sender As Object, e As EventArgs) Handles FindBtn.Click
If Not String.IsNullOrWhiteSpace(TextBox1.Text) Then
SrchParameter = TextBox1.Text
NxtStrtRow = 0
SearchListView()
End If
End Sub
Private Sub ListView1_KeyDown(sender As Object, e As KeyEventArgs) Handles ListView1.KeyDown
If e.KeyCode = Keys.F3 Then
SearchListView()
End If
End Sub
Private Sub SearchListView()
' selects the row containing data matching the text parameter
' sets NxtStrtRow (a form level variable) value for a "find next match" scenario (press F3 key)
If ListView1.Items.Count > 0 Then
If SrchParameter <> "" Then
Dim thisRow As Integer = -1
For x As Integer = NxtStrtRow To ListView1.Items.Count - 1 ' each row
For y As Integer = 0 To ListView1.Columns.Count - 1 ' each column
If InStr(1, ListView1.Items(x).SubItems(y).Text.ToLower, SrchParameter.ToLower) > 0 Then
thisRow = x
NxtStrtRow = x + 1
Exit For
End If
Next
If thisRow > -1 Then Exit For
Next
If thisRow = -1 Then
MsgBox("Not found.")
NxtStrtRow = 0
TextBox1.SelectAll()
TextBox1.Select()
Else
' select the row, ensure its visible and set focus into the listview
ListView1.Items(thisRow).Selected = True
ListView1.Items(thisRow).EnsureVisible()
ListView1.Select()
End If
End If
End If
End Sub
Instead of looping like that through the ListView, try using a For Each instead:
searchstring as String = "test1b"
ListView1.SelectedIndices.Clear()
For Each lvi As ListViewItem In ListView1.Items
For Each lvisub As ListViewItem.ListViewSubItem In lvi.SubItems
If lvisub.Text = searchstring Then
ListView1.SelectedIndices.Add(lvi.Index)
Exit For
End If
Next
Next
ListView1.Focus()
This will select every item which has a text match in a subitem.
Don't put this code in a form load handler, it won't give the focus to the listview and the selected items won't show. Use a Button click handler instead.
This is the easiest way to search in listview and combobox controls in vb net
dim i as integer = cb_name.findstring(tb_name.text) 'findstring will return index
if i = -1 then
msgbox("Not found")
else
msgbox("Item found")
end if

Background Worker and SaveDialog

I am very new with Background worker control. I have an existing project that builds file but throughout my project while building files I get the deadlock error.
I am trying to solve it by creating another project that will only consist out of the background worker. I will then merge them.
My problem is I don't know where it will be more effective for my background worker to be implemented and also the main problem is how can I use the SaveDialog with my background worker? I need to send a parameter to my background worker project telling it when my file is being build en when it is done.
This is where my file is being build:
srOutputFile = New System.IO.StreamWriter(strFile, False) 'Create File
For iSeqNo = 0 To iPrintSeqNo
' Loop through al the record types
For Each oRecord As stFileRecord In pFileFormat
If dsFile.Tables.Contains(oRecord.strRecordName) Then
' Loop through al the records
For Each row As DataRow In dsFile.Tables(oRecord.strRecordName).Rows
' Check record id
If oRecord.strRecordId.Length = 0 Then
bMatched = True
Else
bMatched = (CInt(oRecord.strRecordId) = CInt(row.Item(1)))
End If
' Match records
If iSeqNo = CInt(row.Item(0)) And bMatched Then
strRecord = ""
' Loop through al the fields
For iLoop = 0 To UBound(oRecord.stField)
' Format field
If oRecord.stField(iLoop).iFieldLength = -1 Then
If strRecord.Length = 0 Then
strTmp = row.Item(iLoop + 1).ToString
Else
strTmp = strDelimiter & row.Item(iLoop + 1).ToString
End If
ElseIf oRecord.stField(iLoop).eFieldType = enumFieldType.TYPE_VALUE Or _
oRecord.stField(iLoop).eFieldType = enumFieldType.TYPE_AMOUNT_CENT Then
strTmp = row.Item(iLoop + 1).ToString.Replace(".", "").PadLeft(oRecord.stField(iLoop).iFieldLength, "0")
strTmp = strTmp.Substring(strTmp.Length - oRecord.stField(iLoop).iFieldLength)
Else
strTmp = row.Item(iLoop + 1).ToString.PadRight(oRecord.stField(iLoop).iFieldLength, " ").Substring(0, oRecord.stField(iLoop).iFieldLength)
End If
If oRecord.stField(iLoop).iFieldLength > -1 And (bForceDelimiter) And strRecord.Length > 0 Then
strTmp = strDelimiter & strTmp
End If
strRecord = strRecord & strTmp
Next
' Final delimiter
If (bForceDelimiter) Then
strRecord = strRecord & strDelimiter
End If
srOutputFile.WriteLine(strRecord)
End If
Next
End If
Next
Next
You could try this:
Private locker1 As ManualResetEvent = New System.Threading.ManualResetEvent(False)
Private locker2 As ManualResetEvent = New System.Threading.ManualResetEvent(False)
Dim bOpenFileOK As Boolean
Dim myOpenFile As OpenFileDialog = New OpenFileDialog()
Private Sub FileOpener()
While Not bTerminado
If myOpenFile.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
bOpenFileOK = True
Else
bOpenFileOK = False
End If
locker2.Set()
locker1.WaitOne()
End While
End Sub
' Detonator of the action
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim tFileOp As Thread = New Thread(AddressOf FileOpener)
tFileOp.SetApartmentState(ApartmentState.STA)
tFileOp.Start()
' Start BackgroundWorker
BW1.RunWorkerAsync()
End Sub
Private Sub AsyncFunctionForBW(ByVal args As ArrayList)
'[...]
'Change options dinamically for the OpenFileDialog
myOpenFile.Filter = ""
myOpenFile.MultiSelect = True
'Calling the FileDialog
locker1.Set()
locker2.WaitOne()
locker1.Reset()
locker2.Reset()
If bOpenFileOK Then
myStream = myOpenFile.OpenFile()
'[...]
End If
End Sub
It's a little bit complicated but it works.
ManualResetEvents interrupt the execution of code (if they are told to stop) when reached until you use .Set(). If you use .WaitOne() you set it in stop mode, so it will stop again when reached.
This code defines two ManualResetEvents. When you click the Button1 starts the function FileOpener() in a new Thread, and then starts the BackgroundWorker. The FileOpener() function shows a FileOpenDialog and waits in the locker1 so when you use locker1.Set() the function shows the file dialog.
As the myOpenFile is a "global" variable (as well as bOpenFileOK), once the user select the file (or not) you could detect the dialog result (bOpenFileOK) and the selected file.