Change Font Style on All Instances of a String in a RichTextBox - vb.net

I'm working on a VB.NET 4.5 project in VS2013.
I have a richtextbox on a form and when a button is clicked I need to toggle the BOLD setting on all instances of a specific string found in the richtextbox.
I put together some code based on this question.
Private Sub ToggleBold()
rtxtOutputText.SelectionStart = rtxtOutputText.Find("##$%", RichTextBoxFinds.None)
rtxtOutputText.SelectionFont = New Font(rtxtOutputText.Font, FontStyle.Bold)
End Sub
However when the toggle bold button is clicked it only bolds the first instance of the string "##$%".
How can I set all instances of the string to bold? There can also be several of them strung together ("##$%##$%##$%"), so each of those would need to be bolded too.
(I know I mentioned toggling bold, but I'll set up the toggle portion later, right now I'm just trying to get the bold on all instances working right...)

Just add a loop to it and use the RichTextBox.Find(String, Int32, RichTextBoxFinds) overload to specify from where to start looking. Look from the current index + 1 so that it doesn't return the same again.
You also ought to actually select the word as well, so that you're sure the bold applies to the current instance only and not the text around it.
Private Sub ToggleBold()
'Stop the control from redrawing itself while we process it.
rtxtOutputText.SuspendLayout()
Dim LookFor As String = "##$%"
Dim PreviousPosition As Integer = rtxtOutputText.SelectionStart
Dim PreviousSelection As Integer = rtxtOutputText.SelectionLength
Dim SelectionIndex As Integer = -1
Using BoldFont As New Font(rtxtOutputText.Font, FontStyle.Bold)
While True
SelectionIndex = rtxtOutputText.Find(LookFor, SelectionIndex + 1, RichTextBoxFinds.None)
If SelectionIndex < 0 Then Exit While 'No more matches found.
rtxtOutputText.SelectionStart = SelectionIndex
rtxtOutputText.SelectionLength = LookFor.Length
rtxtOutputText.SelectionFont = BoldFont
End While
End Using
'Allow the control to redraw itself again.
rtxtOutputText.ResumeLayout()
'Restore the previous selection.
rtxtOutputText.SelectionStart = PreviousPosition
rtxtOutputText.SelectionLength = PreviousSelection
End Sub
Credit to Plutonix for telling me to dispose the font.

Related

VB.NET Listbox item color [duplicate]

So I'm trying to make a listbox with 2 buttons.
Listbox is supposed to display files from a specific folder (I get back to this)
And the two buttons are supposed to be called "Set.." (As in set directory)
and Update (As the list will be refreshed (Something I do every time the Windows Form Runs.
So as of now, when I start my application, and go to the form with the listbox, the listbox is empty. When pressing "Update", the List box picks up files from an address located on my Harddrive (So this is a static address located in my code).
It also finds 7 different extensions (Filetypes), and lists all of them correctly.
My problem is as follows, I want the set Button to open a File Dialog for the user on First-Time Runtime, so the user himself can choose what folder the program "Indexes or Searches" if you will. And then when he runs the application again, and finds the listbox, he can only press Update, and the listbox shows the content of the folder he choose last time.
The Set - button doesn't do anything in my code right now.
Second up, I want each filetype to be labeled or colored with a specific color.
Like; .txt should be blue, .jpg is red, ect..
Running Visual Studio 2013 if that helps.
Also, when checking my code, if you have any suggestions too, how I can improve the code, make it easier, shorter, and just to change things to avoid duplicate codes, please let me know.
Here is from the Design in VS2013
Code:
Private Sub Form_Load(sender As Object, e As EventArgs) Handles Me.Load
FolderBrowserDialog1.SelectedPath = "xxx\xxx\xxx\xxx"
System.IO.Directory.GetCurrentDirectory()
Private Sub updateButtonGame_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles updateButtonGame.Click
If FolderBrowserDialog1.SelectedPath = "xxx\xxx\xxx\xxx" Then
ListFiles(FolderBrowserDialog1.SelectedPath)
End If
End Sub
Private Sub ListFiles(ByVal folderPath As String)
filesListBox.Items.Clear()
Dim fi = From f In New IO.DirectoryInfo(FolderBrowserDialog1.SelectedPath).GetFiles().Cast(Of IO.FileInfo)() _
Where f.Extension = ".z64" OrElse f.Extension = ".nds" OrElse f.Extension = ".BIN" OrElse f.Extension = ".smc" OrElse f.Extension = ".ISO" OrElse f.Extension = ".nes" OrElse f.Extension = ".gb"
Order By f.Extension
Select f
For Each fileInfo As System.IO.FileInfo In fi
filesListBox.Items.Add(fileInfo.Name)
Next
End Sub
Another thing, this is more optional..
My list is completely black, so I choose to have the "Items" in the Listbox turn Light gray.
I played around with something called e.Graphics in hope to achieve Coloring a specific filetype, and it turned ALL items either Black, Red, or whatever I put it to.
But after removing the code, all Items turns into the same color as the Background color of the Listbox. So I can no longer see the elements actually being there, other than the Scroll-bar popping up on the side (Since its many Items in the folder I picked)
Also, I am not that good with coding/visual studio yet, as I started around 1 week ago to date.
Started with VB 2010 and then went to VS2013 to see if I managed to fix some issues, also related to List Box.
If I explained rather poorly, let me know and I'll update with better info.
Project was also first created in VB 2010, and then "Migrated" or opened in VS 2013.
A much, much better way to do this is with a ListView and an ImageList with some standard images for Text, Image, PDF etc in the list, then just set the image key for each item when you add them to the list.
Alternatively, you could emulate the same thing in a listbox (using OwnerDrawFixed) to draw a specified image to indicate the file type. A really good way to implement this is as an ExtenderProvider using code similar to that below as a starting point. As an EP, you can link any cbo or listbox to an image list to provide image cues very much like the ListView works:
The reason you do not see your colored item idiom very often is that whatever colors you pick will not look right on all systems. The more colors, the more likely and more often they wont have enough contrast, be readable etc with the user's color scheme. You also dont need a "Legend" to explain what the colors mean - an image is self explanatory. That said, the DrawItem code would be something like this:
NB: Listbox control is set to OwnerDrawFixed, ItemHeight = 16
Private Sub lb_DrawItem(sender As Object,
e As DrawItemEventArgs) Handles lb.DrawItem
Dim TXT As Color = Color.Black
Dim JPG As Color = Color.Green
Dim PDF As Color = Color.Blue
Dim EXE As Color = Color.Gray
Dim SEL As Color = SystemColors.HighlightText
Dim thisColor As Color = Color.Orange
Dim ndx As Integer = e.Index
' isolate ext ans text to draw
Dim text As String = lb.Items(ndx).ToString()
Dim ext As String = System.IO.Path.GetExtension(text).ToLowerInvariant
' dont do anything if no item being drawn
If ndx = -1 Then Exit Sub
' default
e.DrawBackground()
' color selector
Select Case ext
Case ".jpg"
thisColor = JPG
Case ".txt"
thisColor = TXT
Case ".exe"
thisColor = EXE
Case ".pdf"
thisColor = PDF
End Select
' override color to use default when selected
If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
thisColor = SEL
End If
' render the text
TextRenderer.DrawText(e.Graphics, text, lb.Font, e.Bounds,
thisColor, TextFormatFlags.Left)
' default
e.DrawFocusRectangle()
End Sub
Result:
Works on My SystemTM

Accessing multiple PictureBoxes (or any form control) in Visual Basic?

So I'm making a game in VB for learning purposes and now I'm struggling with this problem:
I'm trying to do a For loop that draws the level map. However, I just can't seem to figure out it. This is an example of what I'm trying to do:
For index as integer = 1 to 192
PictureBox(index).Image = bg(map(x,y)) 'this is causing me problems
x=x+1
if x=16 then
x=0
y=y+1
End If
Next
But since PictureBox(index).Image doesn't seem to be the correct answer, it simply throws me an error.
Is there any way to do this?
EDIT:
Shortly, I need to set PictureBox.Image's from 1 to 192 like this without having 192 lines of code:
PictureBox1.Image = bg(map(0,0))
PictureBox2.Image = bg(map(1,0))
PictureBox3.Image = bg(map(2,0))
PictureBox4.Image = bg(map(3,0))
'etc....
Instead I wan't to set them in a For loop. I don't want to have extra lines of code.
EDIT2:
The PictureBoxes are added in the editor.
In the designer set the property Tag of each PictureBox to the string value composed by the x and y required to pass to the map function
For example:
PictureBox1 should have the Tag property set to "0,0"
PictureBox2 set the Tag property to "1,0",
....
PictureBox17 will have the Tag property set to "0,1"
and so on until you have mapped all your pictureboxes with the correct values.
Then your code could be changed to
' Assuming the PictureBox are all childs of the Form
For Each pic in Me.Controls.OfType(Of PictureBox)()
Dim tag = pic.Tag
' You could omit this check if you have only the pictureboxes
' set with a valid Tag property
if Not string.IsNullOrEmpty(tag) Then
Dim xyCoords = tag.ToString().Split(","c)
pic.Image = bg(map(Convert.ToInt32(xyCoords(0),
Convert.ToInt32(xyCoords(1))))
End if
Next
I'm going to make a huge assumption here and assume that you already have the PictureBox's on the form prior to reaching this code and they have Id's PictureBox1 through PictureBox192. The code would look like the following. You need to:
1. Retrieve the element by its ID
2. Cast/convert it from an object to a PictureBox
3. Set it's Image property appropriately.
Dim pBox As PictureBox ' To store each pic box in
For index as integer = 1 to 192
pBox = Me.Controls.Find(PictureBox&&index) ' Try to find pic box by ID
If Not pBox Is Nothing Then ' If able to find element by this ID
DirectCast(pBox, PictureBox).Image = bg(map(x,y))
End If
x=x+1
if x=16 then
x=0
y=y+1
End If
Next

Changing the text of all the buttons on a form in VB.net

Call me crazy but for the life of me I cannot make this work. I have the following code:
Dim cControl As Control
For Each cControl In Me.Controls
If (TypeOf cControl Is Button) Then
cControl.ForeColor = Color.Black
cControl.Font = New Font(cControl.Font, FontStyle.Regular)
End If
Next cControl
Me.ActiveControl.ForeColor = Color.Blue
Me.ActiveControl.Font = New Font(Me.ActiveControl.Font, FontStyle.Bold)
I am trying to make the font black and regular for all of the buttons on the form (there are a lot) and the button just clicked, bolded and blue.
The second part of the code works (making the font bold and blue), it's the first that is not simply working.
What am I missing?
I've never tried it like that before, but I have used Linq to accomplish what you want.
Dim btn() As Button
btn = Me.Controls.OfType(Of Button)().Where(Function(c) c.Name.Contains("")).ToArray()
This will basically create an array of buttons from your form, then you can just loop through each one.
Dim i As Integer = 0
While i < btn.Count
btn(i).Enabled = True
btnText(i).BackColor = Color.DarkOliveGreen
btnText(i).ForeColor = Color.White
i += 1
End While
If you have a naming convention for your buttons and want to only change certain buttons where the empty quotes are you can have "btnTest".
Then you will have an index of any button that contains the text "btnTest" in it. So that would include "btnTest1", "btnTest2", "btnTestAnything1234" etc.
Hope this helps and you can use it!
Nevermind I found my problem. The buttons are in a group box so I had to reference the group box directly

"Caret Position" in VB.NET for syntax highlighting

I'm trying to make a TextBox with syntax highlighting (for (HTML/CSS) in VB.NET 2008.
I figured that if I use RichTextBox.Find(), I can color specific text, but then I need to call RichTextBox.DeselectAll().
The problem is that the the cursor jumps to the beginning of the RTB.
I'm using WinForms.
Any ideas?
You can get and set the cursor position using the SelectionStart property.
Therefore, you can write,
Dim selStart As Integer = rtb.SelectionStart
'Do things
rtb.SelectionStart = selStart
Imports System.Text.RegularExpressions
Public Class Form1
'Create a Html Keyword Regex
Dim htmlkeywords As New System.Text.RegularExpressions.Regex("<html>|</html>|<head>|</head>|<meta|<p>|</p>|<div>|</div>") <----add as many terms as you like between the () don't forget the pipe symbol between each term in the Regex.
'Then in your Richtextbox textchanged event add this
Private Sub rtText_TextChanged(sender As Object, e As EventArgs) Handles rtText.TextChanged
Dim selStart As Integer = rtText.SelectionStart
Do Until False
For Each keyWordMatch As Match In htmlkeywords.Matches(rtText.Text)
rtText.Select(keyWordMatch.Index, keyWordMatch.Length)
rtText.SelectionColor = Color.Purple
rtText.SelectionStart = rtText.Text.Length 'this puts the caret at the end
rtText.SelectionLength = 0 ' of the word
Next keyWordMatch
Exit Do
Loop
rtText.SelectionColor = Color.Black
rtText.SelectionStart = selStart ' this makes sure that if your caret is behind a word and you press enter to move a text down a line; the caret will stay in position on the next line that you start typing on. You can remove this code to see what I'm talking about
End Sub
rtText is my RichTextBox name. This will change the word you want to whatever color then change it back to black, which you can change which colors do what. Hope this helps!

VB.NET - RichTextBox - Apply formatting to selected text

I have a RichTextBox control on my form. I also have this button, labeled Bold, that I want, if someone selects text in the RichTextBox, then presses the button, the selected text turns bold. Any way to do that? Simple, everyday task for end users. Thanks.
A variation on the above that takes into consideration switching bold on/off depending on the currently selected text's font info:
With Me.rtbDoc
If .SelectionFont IsNot Nothing Then
Dim currentFont As System.Drawing.Font = .SelectionFont
Dim newFontStyle As System.Drawing.FontStyle
If .SelectionFont.Bold = True Then
newFontStyle = currentFont.Style - Drawing.FontStyle.Bold
Else
newFontStyle = currentFont.Style + Drawing.FontStyle.Bold
End If
.SelectionFont = New Drawing.Font(currentFont.FontFamily, currentFont.Size, newFontStyle)
End If
End With
It may need cleaned up a bit, I pulled this from an older project.
You'll want to use the .SelectionFont property of the RichTextBox and assign it a Font object with the desired styles.
Example - this code would be in the event handler for the button:
Dim bfont As New Font(RichTextBoxFoo.Font, FontStyle.Bold)
RichTextBoxFoo.SelectionFont = bfont