How to get ListView.SubItems - vb.net

I'm trying to make a program that inputs text into a document depending on the user input, and I am currently displaying it as a ListView.
I can't figure out how to get the SubItem from the item, as this is my current code.
For Each item In ListView1.Items
Dim inputString72 As String = "#bot.command()" + vbNewLine
My.Computer.FileSystem.WriteAllText(
SaveFileDialog1.FileName, inputString72, True)
Dim inputString73 As String = "async def " + item.Text + "(ctx):" + vbNewLine
My.Computer.FileSystem.WriteAllText(
SaveFileDialog1.FileName, inputString73, True)
Dim inputString74 As String = " await ctx.send('" + THE SUBITEM OF THE ITEM GOES HERE + "')" + vbNewLine
My.Computer.FileSystem.WriteAllText(
SaveFileDialog1.FileName, inputString74, True)
Next

I think it would be more efficient to use the .net File class. No need to call the method several times in each iteration. From the docs. "The WriteAllText method opens a file, writes to it, and then closes it. " That is a lot of openning and closing. Build a string with a StringBuilder (which is mutable) and then write once to the file.
I used interpolated strings (it is preceded by a $) which allows you to put a variable directly in a string surrounded by braces.
SubItem indexes start at 0 with the first column. The .Text property of the SubItem will return its contents.
Private Sub WriteListViewToFile(FilePath As String)
Dim sb As New StringBuilder
For Each item As ListViewItem In ListView1.Items
sb.AppendLine("#bot.command()")
sb.AppendLine($"async def {item.Text}(ctx):")
sb.AppendLine($" await ctx.send('{item.SubItems(1).Text}')")
Next
File.WriteAllText(FilePath, sb.ToString)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If SaveFileDialog1.ShowDialog = DialogResult.OK Then
WriteListViewToFile(SaveFileDialog1.FileName)
End If
End Sub

Related

reading from txt file and writing in textbox

Can somebody help me with this, im stuck no idea what to do next
give a text file at any location in the computer it contains 15 different integers that can be repeated
make the program so that multiple repetitions of one number are not printed separately, but each number is printed exactly once
and next to it are written in which places he appeared
Imports System.IO
Public Class form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim povratnaVrijednost As DialogResult
Dim nazivDatoteke As String
Try
OpenFileDialog1.AddExtension = True
OpenFileDialog1.Multiselect = False
OpenFileDialog1.Filter = "Tekst datoteke (*.txt)|*.txt;"
povratnaVrijednost = OpenFileDialog1.ShowDialog()
If povratnaVrijednost = Windows.Forms.DialogResult.OK Then
If OpenFileDialog1.CheckFileExists = True And
OpenFileDialog1.CheckPathExists = True Then
nazivDatoteke = OpenFileDialog1.FileName
TextBox1.Text = nazivDatoteke
Dim citac As New StreamReader(nazivDatoteke)
Dim redTeksta As String = ""
Do
redTeksta = citac.ReadLine()
If Not redTeksta Is Nothing Then
RichTextBox1.Text = RichTextBox1.Text + redTeksta
End If
Loop Until redTeksta Is Nothing
citac.Close()
End If
End If
Catch ex As Exception
MsgBox("Greska prilikom otvaranja" + ex.StackTrace.ToString)
End Try
End Sub
End Class
123
Requirement #1:
give a text file at any location in the computer it contains 15 different integers that can be repeated
This requirement implies a couple of other requirements. First, you're expected to read the text file. Second, you're expected to parse the values into numbers (presumably integers).
You can use an OpenFileDialog (documentation) and specify that it can only accept text files:
Using browseFileDialog = New OpenFileDialog()
With browseFileDialog
.Filter = "*.txt|*.txt"
If (.ShowDialog() = DialogResult.Ok) Then
'.FileName will be the text file that the user picked
End If
End With
End Using
To read the text file, assuming you want each line, use the File.ReadAllLines method (documentation):
Using browseFileDialog = New OpenFileDialog()
With browseFileDialog
.Filter = "*.txt|*.txt"
If (.ShowDialog() = DialogResult.Ok) Then
Dim lines = IO.File.ReadAllLines(.FileName)
End If
End With
End Using
To parse the values, use the Array.ConvertAll method (documentation) and inside of the predicate use the Integer.Parse method (documentation):
Using browseFileDialog = New OpenFileDialog()
With browseFileDialog
.Filter = "*.txt|*.txt"
If (.ShowDialog() = DialogResult.Ok) Then
Dim lines = IO.File.ReadAllLines(.FileName)
Dim values = Array.ConvertAll(lines, Function(line) Integer.Parse(line))
End If
End With
End Using
Keep in mind that if you wanted to validate that the lines are all valid numbers, instead of assuming that they are, this step would be different. However, you didn't specify that requirement in your original post so I'm not including how to do that.
Requirement #2:
make the program so that multiple repetitions of one number are not printed separately, but each number is printed exactly once
You can use the Random.Next method (documentation) to generate random values. Be sure to declare the new instance of the random object once so that the seed is only set once. To randomly order the values, use the OrderBy method (documentation) passing the random value in the predicate:
Private ReadOnly _random As New Random()
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Using browseFileDialog = New OpenFileDialog()
With browseFileDialog
.Filter = "*.txt|*.txt"
If (.ShowDialog() = DialogResult.Ok) Then
Dim lines = IO.File.ReadAllLines(.FileName)
Dim values = Array.ConvertAll(lines, Function(line) Integer.Parse(line))
Dim randomlyOrderedValues = values.OrderBy(Function(value) _random.Next())
RichTextBox1.Text = String.Join(", ", randomlyOrderedValues.ToArray())
End If
End With
End Using
End Sub
Default for .AddExtension is True. Default for .Multiselect is False. I have simplified the If statement by comparing the return value of .Showdialog directly to the desired DialogResult. If the path of file don't exist the dialog will show a waring.
Always scope variables as narrowly as possible. I move the Dim nazivDatoteke to inside the If since it is not used anywhere else. StreamReaders require a Using block since they need to be disposed.
Why a RichTextBox for a text file?
As you can see getting the distince items in the array is easy, a single line of code. What is more difficult is finding the indexes in the original array, lines.
I looped through all the items in the distinct array (actually it is an IEnumerable(Of String) but that is not important to this code, it is just easier to type array in my explanation). I created a List(Of Integer) to hold the indexes of each item in the original array, lines. The startIndex where the FindIndex method of an Array is the location of the first occurrence of the String.
On each iteration of the Do loop I look for the matches to the item from the lines array. The FindIndex takes parameters (original array, index to start at, what we are looking for). It stops as soon as it finds a match and returns -1 if no matches are found. You can see the operation of this method be setting a break point and checking the variable values.
If a match is found I added that value to the list and change the startIndex to the position following the found index.
Next I used a StringBuilder to create the string to display. I chose the immediate window for testing purposes but you could show sb.ToString in a text box or add it to a ListBox.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
OpenFileDialog1.Filter = "Tekst datoteke (*.txt)|*.txt;"
If DialogResult.OK = OpenFileDialog1.ShowDialog Then
Dim nazivDatoteke = OpenFileDialog1.FileName
TextBox1.Text = nazivDatoteke
Dim lines = File.ReadAllLines(nazivDatoteke)
Dim distinct = lines.Distinct
For Each item In distinct
Dim lst As New List(Of Integer)
Dim startIndex = Array.IndexOf(lines, item)
Do
Dim FoundIndex = Array.FindIndex(lines, startIndex, Function(line) line = item)
If FoundIndex = -1 Then
Exit Do
Else
lst.Add(FoundIndex)
startIndex = FoundIndex + 1
End If
Loop
Dim sb As New StringBuilder
sb.Append(item)
For Each i In lst
sb.Append($" ({i})")
Next
Debug.Print(sb.ToString)
Next
End If
End Sub
This code displays the distinct items in the list and follow it with the positions (indexes) in the original list.

vb.net statusbar text doesn't show

I have a code that searches for words in documents and fills a Listview with the found documents. Because the process can be rather lengthly I put a warning in the statusbar.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim foundList As Boolean
Dim docImage As VariantType
Dim PresetName As String
ListView1.Items.Clear()
ToolStripLabel1.Text = "Searching your documents, please wait."
Try
For Each row As DataRowView In CheckedListBox1.CheckedItems
SearchRegX = row("RegX")
Next
If TextBoxFreeText.Text <> "" Then
'look for a space in the search criteria, meaning there are more words
Dim counter As Integer = TextBoxFreeText.Text.IndexOf(" ")
If counter <> -1 Then
'more words were entered to search
Dim varSplit As Object
varSplit = Split(TextBoxFreeText.Text, " ")
'if more than two words are entered our regex doesnt work, so we exit the sub
If varSplit.length > 2 Then
MsgBox("Your search criteria are to complex, use a maximum of two words",, Title)
Exit Sub
End If
iWords = NumericUpDown1.Value
SearchRegX = "(?i)\b(?:" + varSplit(0) + "\W+(?:\w+\W+){0," + iWords + "}?" + varSplit(1) + "|" + varSplit(1) + "\W+(?:\w+\W+){0," + iWords + "}?" + varSplit(0) + ")\b"
Else
'just one word was entered
SearchRegX = "(?i)\b" + TextBoxFreeText.Text + "\b"
End If
End If
If SearchRegX = "" Then
MsgBox("No Keyword was selected",, Title)
Exit Sub
End If
If ListBox1.SelectedIndex > -1 Then
For Each Item As Object In ListBox1.SelectedItems
Dim ItemSelected = CType(Item("Path"), String)
SearchFolder = ItemSelected
'check if the folder of the archive still exists
If (Not System.IO.Directory.Exists(SearchFolder)) Then
Dim unused = MsgBox("The archive " + SearchFolder.Substring(SearchFolder.Length - 5, Length) + " was not found",, Title)
Continue For
End If
Dim dirInfo As New IO.DirectoryInfo(SearchFolder)
Dim files As IO.FileInfo() = dirInfo.GetFiles()
Dim file As IO.FileInfo
docImage = ImageList1.Images.Count - 1
Dim items As New List(Of ListViewItem)
For Each file In files
Dim filename As String = file.Name.ToString
If file.Extension = ".pdf" Or file.Extension = ".PDF" Then
foundList = PDFManipulation.GetTextFromPDF2(SearchFolder + filename, SearchRegX)
If foundList = True Then
If ListView1.FindItemWithText(filename.ToString) Is Nothing Then
items.Add(New ListViewItem(New String() {"", filename.ToString, SearchFolder.ToString}, docImage))
End If
End If
End If
Next
ListView1.Items.AddRange(items.ToArray)
Next
ToolStripLabel1.Text = ListView1.Items.Count.ToString + " Documents found."
Else
MsgBox("No archive was selected",, Title)
End If
SearchRegX = ""
SearchFolder = ""
'now save the search word to our textfile
PresetName = TextBoxFreeText.Text
If PresetName <> "" Then
AddSearchWord()
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Somehow the text doesn't show in the statusbar before the process starts.
What should I change?
I thought about a BackgroundWorker showing an image like waiting but the BackgroundWorker doesn't work because inside my Sub I call a function elsewhere.
This happens because the status strip control is not rendered properly before the pending workload is finished. To do so, you can refresh the status strip manually:
StatusStrip1.Refresh()
That is, if your only goal is to set the text. If you thought about running the code in the background so that the form is still responsive to user input, you'll need asynchronous programming using System.Threading.Tasks or System.Threading.Thread to run the code as a seperate thread. Be aware though that you may face difficulties when trying to access controls outside of the main thread.
Add Async to your button handler declaration:
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Now change your call to PDFManipulation.GetTextFromPDF2() so that it is within a Task:
Await Task.Run(Sub()
foundList = PDFManipulation.GetTextFromPDF2(SearchFolder + filename, SearchRegX)
End Sub)
If foundList = True Then
...

VB.NET how to save listview with savefiledialog

Something's wrong in my code, i want to save listview item into text file using savefiledialog.
I'm getting error "Overload resolution failed because no accessible 'WriteAllLines' accepts this number of arguments."
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles ChromeButton3.Click
Dim s As New SaveFileDialog
s.Filter = "text|*.txt"
s.Title = "Save Your Hits"
If s.ShowDialog = Windows.Forms.DialogResult.OK Then
For Each myItem As ListViewItem In ListView1.Items
File.WriteAllLines(myItem.Text & vbNewLine & myItem.SubItems(1).Text & vbNewLine & myItem.SubItems(2).Text & vbNewLine & myItem.SubItems(3).Text & vbNewLine & vbNewLine)
Next
End If
End Sub
Your error
Overload resolution failed
can be corrected by looking at the documentation. It is a good idea to do this with any unfamiliar method. Just google the method followed by "in .net" The first link that came up is https://learn.microsoft.com/en-us/dotnet/api/system.io.file.writealllines?view=netframework-4.8
And the first topic in the documentation is overloads. I think you can see that none of the overloads match what you tried to pass.
As was mentioned in comments File.Write All lines isn't really appropriate for your purposes. Instead of making all those lines and a double line between records, Make each row a single line separating each field by a comma. I used a StringBuilder which provides a mutable (changeable) datatype (unlike a String which is immutable). Saves the compiler from throwing away and creating new strings on every iteration.
I appended a new line on each iteration containing an interpolated string. An interpolated string starts with the $. This allows you to directly mix in variables enclosed in { } with the literal characters.
After the loop, you convert the StringBuilder to a String and write to the file with the file name provided by the dialog box.
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim s As New SaveFileDialog
s.Filter = "text|*.txt"
s.Title = "Save Your Hits"
If s.ShowDialog = DialogResult.OK Then
Dim fileName = s.FileName
Dim sb As New StringBuilder
For Each myItem As ListViewItem In ListView1.Items
sb.AppendLine($"{myItem.Text},{myItem.SubItems(1).Text},{myItem.SubItems(2).Text},{myItem.SubItems(3).Text}")
Next
File.WriteAllText(fileName, sb.ToString)
End If
End Sub

Eliminate duplicate from a Multi-Line string

I have a text-box control called Textbox1 which contains the following items (in a Multi-line string):
22,23
57,58
20,21
51,52
57,58
20,21
21,22
25,26
35,36
41,42
50,51
22,23
23,24
37,38
44,45
45,46
67,68
72,73
78,79
How do I remove 2-digit duplicates? Instead of 20,21, it does not appear twice and once. If the combination of 2 numbers still exists in another line, then this combination appears once. and so on.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lines() As String = TextBox1.Text.Split(New String() {vbCrLf, vbCr, vbLf}, StringSplitOptions.None)
Dim repeatedElement As String = ""
'First have to sort array
System.Array.Sort(lines)
For Each Line As String In lines
If Not (String.Compare(Line, repeatedElement) = 0) Then
TextBox2.Text += Line & vbCrLf
End If
repeatedElement = Line
Next
End Sub
Here textBox1 is for source text and textBox2 is for result.

Calling a procedure from its non native form

Ok, so
frmResult populates a ListView with various calculations
frmMenu has an export button (see code below). Pressing this is supposed to export the data in the ListView to a txt file. Currently, this button does not work. It says, List View is undeclared - obviously because the code shown below is not 'seeing' data held in frmResult
Question – how do I call the procedures stored in frmResult so that frmMenu can 'see' it.
Public Sub btnExport_Click(sender As Object, e As EventArgs) Handles btnExport.Click
Dim fileSaved As Boolean
Dim filePath As String
Do Until fileSaved
'Request filename from user
Dim saveFile As String = InputBox("Enter a file name to save this message")
'Click Cancel to exit saving the work
If saveFile = "" Then Exit Sub
'
Dim docs As String = My.Computer.FileSystem.SpecialDirectories.MyDocuments
filePath = IO.Path.Combine(docs, "Visual Studio 2013\Projects", saveFile & ".txt")
fileSaved = True
If My.Computer.FileSystem.FileExists(filePath) Then
Dim msg As String = "File Already Exists. Do You Wish To Overwrite it?"
Dim style As MsgBoxStyle = MsgBoxStyle.YesNo Or MsgBoxStyle.DefaultButton2 Or MsgBoxStyle.Critical
fileSaved = (MsgBox(msg, style, "Warning") = MsgBoxResult.Yes)
End If
Loop
'the filePath String contains the path you want to save the file to.
Dim rtb As New RichTextBox
rtb.AppendText("Generation, Num Of Juveniles, Num of Adults, Num of Semiles, Total" & vbNewLine)
For Each saveitem As ListViewItem In ListView1.Items
rtb.AppendText(
saveitem.Text & ", " &
saveitem.SubItems(1).Text & ", " &
saveitem.SubItems(2).Text & ", " &
saveitem.SubItems(3).Text & ", " &
saveitem.SubItems(4).Text & vbNewLine)
Next
rtb.SaveFile(filePath, RichTextBoxStreamType.PlainText)
End Sub
Is this what you mean?
Public Sub Init()
'... (all the code)
End Sub
Private Sub Results_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Call Init()
End Sub
You can call Init() from every form load you want. Maybe you want to create a module and store there your methods.
By the way, you only use Function when your methods needs to return a value.
If your code uses elements of the form (or other objects not constant) you need to pass those to the method, like this:
Public Sub Init(myListView As ListView)
myListView.Items.Add("something")
'...
End Sub
Private Sub Results_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Call Init(ListView1)
End Sub
You can add as many parameters as you need. You have to learn the basics before going ant further.
This is a great piece of literature for those struggling with the basics like myself.
You can write code to access objects on a different form. However, you must fully identify the name of the object by preceding it with the object variable name.
Dim resultsForm As New frmResults
resultsForm.lblAverage.Text = sngAverage.ToString()
In these statements, for example, I have declared an object variable called resultsForm that is linked to the form frmResults. The second statement assigns the string value of sngAverage to the lblAverage label box on the frmResults form.
In my code, I needed to change the line that said:
For Each saveitem As ListViewItem In ListView1.Items
To this:
For Each saveitem As ListViewItem In Results.ListView1.Items
I also needed to make sure that the procedure on formResults was made Public not Private