I'm using the following code to add items to a listbox:
Dim i As Integer = 0
Dim temp As String
ListBox2.Items.Clear()
While i <= 9
temp = Str(final_average(i)) + " " + Str(i + 1) + " " + Str(cals(i))
ListBox2.Items.Add(temp)
i = i + 1
End While
I want to sort this using the average or final_average(i), but the following code doesn't seem to work:
Dim arr(ListBox2.Items.Count - 1) As Object
ListBox2.Items.CopyTo(arr, 0)
Array.Sort(arr)
ListBox2.Items.Clear()
ListBox2.Items.AddRange(arr)
How do I sort the contents of the listbox?
(Note: This is not homework but part of a bigger project).
Here is the proper way to do it.
A. First create your list items class.
Public Class MyListItem
Implements IComparable(Of MyListItem)
Public FinalAverage As Integer
Public Number As Integer
Public Cals As Integer
Public Sub New(ByVal finalAverage As Integer, ByVal number As Integer, ByVal cals As Integer)
Me.FinalAverage = finalAverage
Me.Number = number
Me.Cals = cals
End Sub
Public Overrides Function ToString() As String
'' the way you want it to be shown in the listbox.
Return String.Format("{0} {1} {2}", FinalAverage, Number, Cals)
End Function
Public Function CompareTo(ByVal other As MyListItem) As Integer Implements System.IComparable(Of MyListItem).CompareTo
'' the way list items are compared for sorting... Return 0 for equal, -1 for smaller, +1 for bigger
If Me.FinalAverage < other.FinalAverage Then Return -1
If Me.FinalAverage > other.FinalAverage Then Return 1
Return 0
End Function
End Class
B. Now use this class to add items to your listbox.
Dim listItems As New List(Of MyListItem)
For i As Integer = 0 To 9
listItems.Add(New MyListItem(final_average(i), i + 1, cals(i)))
Next
listItems.Sort()
ListBox2.DataSource = listItems
And that's it! :)
I have a rather simpler solution to your problem!
Method 1
1) Sort the items in Listbox1:
We will do this by setting the Sorted property of Listbox1 to True. It will keep your old list which was not sorted safely!
listBox1.Sorted = True
2) Send the items to Listbox2:
Copy all the items from listbox1 to listbox2 by saving it to an object collection. They will move in order, and hence, the second one is sorted from A-Z.
Dim objCollection As Object() = New Object(listBox1.Items.Count - 1)
listBox1.Items.CopyTo(objCollection, 0)
listBox2.Items.AddRange(objCollection)
3) Place items in Listbox1 in proper order:
We have both the listbox with sorted items. Now, all we need to do is to place items in the previous order. As I said, your placement of items will be stored safely, we will retrieve it back by setting the Sorted property of Listbox1 to False.
listBox1.Sorted = False
And, you will get a sorted listbox2!
Method 2
Instead of sorting and then copying and then unsorting listbox1, you can first copy all items to listbox2 and then sort listbox2. In this case, there will be no need of unsorting the first one again!
I hope it works perfectly!
Related
I have made 2 variables:
Public a as Integer
Public b as Integer
and I have a text field where 2 values can be inserted like this: "1 - 10"
so I split the value and saved them in those 2 variables a and b.
but I need those 2 values in different forms but all I'm getting is 0.
I also created Dim c as form1 = new form1 in the form2.
What's the problem?
Depending on a relation between Form1 and Form2, you can use this kind of communication (this is for a parent-child relation):
Form 2:
Public ParentFrm as Form1
Public a as Int16
Form 1 - in it's running instance:
Public b as Int16
Dim NewInstanceOfForm2 as New Form2
NewInstanceOfForm2.ParentFrm = Me ' this is to ensure you can talk back to correct instance of parent form
NewInstanceOfForm2.a = 12345
NewInstanceOfForm2.BackColor = colors.Pink
NewInstanceOfForm2.TextBox1.Text = "Hello World!!!"
Since we set the ParentFrm in the Form2, you can communicate the same way back and set things in Form1:
ParentFrm.b = 789
ParentFrm.TextBox3 = "Hi there!!!"
ParentFrm.UpdateForm1FromDatabasePublicFunction()
Siblings can communicate through a common parent. But in all the cases, you need to get to understand instances of the forms. Remember, that you can communicate only with objects (TextBox, Button, DataGridView,...) and Public variables of the form.
You could create a module and define the variable as puclic there, that way they'll always be accessible from anywhere on the application.
Right click the solution, Add New, Module
And inside that module add
Public a, b as Integer
To split the textbox input and store them in these vars use
Dim s as String
Dim sp() as String
s = TextBox1.Text
sp = s.Split("-")
This stores the values in the textbox separated by '-' on sp(0) and sp(1) respectively.
You can then stote them into you public variables.
a = sp(0)
b = sp(1)
And call then from any form you need.
Well, i am not sure what it exactly is you want but here are some suggestions:
if your form1 contains two variables like so:
Public a As Integer = 0
Public b As Integer = 0
and you want to retrieve the value of one of those variables from another form, lets say from Form2, then all you need to do is that:
(Put this code in either a function, or an event of your second Form (for example Form2)):
dim current_a As Integer = 0
current_a = Form1.a
dim current_b As Integer = 0
current_b = Form1.b
If you enter the text (for example: "1 - 10“), into a textbox, but want to get both values (in this case 1, and 10), you only need to grab them by for example creating a loop, to search for these values, like so:
dim textbox_str As String = ""
textbox_str = TextBox1.Text
( in this example, the TextBox1.Text would contain "1 - 10")
dim final_str1 As String = ""
dim final_str2 As String = ""
for each s_ As String In textbox_str
If Not s_ = " " Then
final_str1 = final_str1 & s_
Else
Exit For
End If
Next
(after this, final_str1 would contain "1")
(now extract the second number, by doing the following:)
final_str2 = textbox_str.Replace(final_str1 & " - ", "")
(and now, final_str2 would contain "10")
(so you would have both numbers extracted from that text)
As i said, i do not exactly know what you want, but hopefully this helped you, let me know if it is what you were looking for!
I am using an array to populate my listbox. It worked fine but when I set the listbox.selection.none (I don't want items to be selected) then My listbox adds item to its first index but after that. It keeps the same value in an does not add new values. below is the code what i am using to add items to listbox from array.
Private array(10) As Decimal ' adds student score to array
dim index as integer = 0 '
Private Sub PopulateScoreList() ' method called when button is clicked
If index < 10 Then
' adds value to array at every button click event
array(index) = Math.Round(value, 1)
End If
index += 1
lbxTroopersScore.DataSource = Nothing
lbxTroopersScore.DataSource = array
end sub
Seems like a bug. Toggling the SelectionMode property fixes the problem:
lbxTroopersScore.DataSource = Nothing
lbxTroopersScore.SelectionMode = SelectionMode.One
lbxTroopersScore.SelectionMode = SelectionMode.None
lbxTroopersScore.DataSource = array
Consider a text file stored in an online location that looks like this:
;aiu;
[MyEditor45]
Name = MyEditor 4.5
URL = http://www.myeditor.com/download/myeditor.msi
Size = 3023788
Description = This is the latest version of MyEditor
Feature = Support for other file types
Feature1 = Support for different encodings
BugFix = Fix bug with file open
BugFix1 = Fix crash when opening large files
BugFix2 = Fix bug with search in file feature
FilePath = %ProgramFiles%\MyEditor\MyEditor.exe
Version = 4.5
Which details information about a possible update to an application which a user could download. I want to load this into a stream reader, parse it and then build up a list of Features, BugFixes etc to display to the end user in a wpf list box.
I have the following piece of code that essentially gets my text file (first extracting its location from a local ini file and loads it into a streamReader. This at least works although I know that there is no error checking at present, I just want to establish the most efficient way to parse this first. One of these files is unlikely to ever exceed more than about 250 - 400 lines of text.
Dim UpdateUrl As String = GetUrl()
Dim client As New WebClient()
Using myStreamReader As New StreamReader(client.OpenRead($"{UpdateUrl}"))
While Not myStreamReader.EndOfStream
Dim line As String = myStreamReader.ReadLine
If line.Contains("=") Then
Dim p As String() = line.Split(New Char() {"="c})
If p(0).Contains("BugFix") Then
MessageBox.Show($" {p(1)}")
End If
End If
End While
End Using
Specifically I'm looking To collate the information about Features, BugFixes and Enhancements. Whilst I could construct what would in effect be a rather messy if statement I feel sure that there must be a more efficient way to do this , possibly involving linq. I'd welcome any suggestions.
I have added the wpf tag on the off chance that someone reading this with more experience of displaying information in wpf listboxes than I have might just spot a way to effectively define the info I'm after in such a way that it could then be easily displayed in a wpf list box in three sections (Features, Enhancements and BugFixes).
Dom, Here is an answer in C#. I will try to convert it to VB.Net momentarily. First, since the file is small, read all of it into a list of strings. Then select the strings that contain an "=" and parse them into data items that can be used. This code will return a set of data items that you can then display as you like. If you have LinqPad, you can test thecode below, or I have the code here: dotnetfiddle
Here is the VB.Net version: VB.Net dotnetfiddle
Imports System
Imports System.Collections.Generic
Imports System.Linq
Public Class Program
Public Sub Main()
Dim fileContent As List(Of String) = GetFileContent()
Dim dataItems = fileContent.Where(Function(c) c.Contains("=")).[Select](Function(c) GetDataItem(c))
dataItems.Dump()
End Sub
Public Function GetFileContent() As List(Of String)
Dim contentList As New List(Of String)()
contentList.Add("sb.app; aiu;")
contentList.Add("")
contentList.Add("[MyEditor45]")
contentList.Add("Name = MyEditor 4.5")
contentList.Add("URL = http://www.myeditor.com/download/myeditor.msi")
contentList.Add("Size = 3023788")
contentList.Add("Description = This is the latest version of MyEditor")
contentList.Add("Feature = Support for other file types")
contentList.Add("Feature1 = Support for different encodings")
contentList.Add("BugFix = Fix bug with file open")
contentList.Add("BugFix1 = Fix crash when opening large files")
contentList.Add("BugFix2 = Fix bug with search in file feature")
contentList.Add("FilePath = % ProgramFiles %\MyEditor\MyEditor.exe")
contentList.Add("Version = 4.5")
Return contentList
End Function
Public Function GetDataItem(value As String) As DataItem
Dim parts = value.Split("=", 2, StringSplitOptions.None)
Dim dataItem = New DataItem()
dataItem.DataType = parts(0).Trim()
dataItem.Data = parts(1).Trim()
Return dataItem
End Function
End Class
Public Class DataItem
Public DataType As String
Public Data As String
End Class
Or, in C#:
void Main()
{
List<string> fileContent = GetFileContent();
var dataItems = fileContent.Where(c => c.Contains("="))
.Select(c => GetDataItem(c));
dataItems.Dump();
}
public List<string> GetFileContent()
{
List<string> contentList = new List<string>();
contentList.Add("sb.app; aiu;");
contentList.Add("");
contentList.Add("[MyEditor45]");
contentList.Add("Name = MyEditor 4.5");
contentList.Add("URL = http://www.myeditor.com/download/myeditor.msi");
contentList.Add("Size = 3023788");
contentList.Add("Description = This is the latest version of MyEditor");
contentList.Add("Feature = Support for other file types");
contentList.Add("Feature1 = Support for different encodings");
contentList.Add("BugFix = Fix bug with file open");
contentList.Add("BugFix1 = Fix crash when opening large files");
contentList.Add("BugFix2 = Fix bug with search in file feature");
contentList.Add("FilePath = % ProgramFiles %\\MyEditor\\MyEditor.exe");
contentList.Add("Version = 4.5");
return contentList;
}
public DataItem GetDataItem(string value)
{
var parts = value.Split('=');
var dataItem = new DataItem()
{
DataType = parts[0],
Data = parts[1]
};
return dataItem;
}
public class DataItem
{
public string DataType;
public string Data;
}
The given answer only focuses on the first part, converting the data to a structure that can be shaped for display. But I think you main question is how to do the actual shaping.
I used a somewhat different way to collect the file data, using Microsoft.VisualBasic.FileIO.TextFieldParser because I think that makes coding just al little bit easier:
Iterator Function GetTwoItemLines(fileName As String, delimiter As String) _
As IEnumerable(Of Tuple(Of String, String))
Using tfp = New TextFieldParser(fileName)
tfp.TextFieldType = FieldType.Delimited
tfp.Delimiters = {delimiter}
tfp.HasFieldsEnclosedInQuotes = False
tfp.TrimWhiteSpace = False
While Not tfp.EndOfData
Dim arr = tfp.ReadFields()
If arr.Length >= 2 Then
Yield Tuple.Create(arr(0).Trim(), String.Join(delimiter, arr.Skip(1)).Trim())
End If
End While
End Using
End Function
Effectively the same thing happens as in your code, but taking into account Andrew's keen caution about data loss: a line is split by = characters, but the second field of a line consists of all parts after the first part with the delimiter re-inserted: String.Join(delimiter, arr.Skip(1)).Trim().
You can use this function as follows:
Dim fileContent = GetTwoItemLines(file, "=")
For display, I think the best approach (most efficient in terms of lines of code) is to group the lines by their first items, removing the numeric part at the end:
Dim grouping = fileContent.GroupBy(Function(c) c.Item1.TrimEnd("0123456789".ToCharArray())) _
.Where(Function(k) k.Key = "Feature" OrElse k.Key = "BugFix" OrElse k.Key = "Enhancement")
Here's a Linqpad dump (in which I took the liberty to change one item a bit to demonstrate the correct dealing with multiple = characters:
You could do it with Regular Expressions:
Imports System.Text.RegularExpressions
Private Function InfoReader(ByVal sourceText As String) As List(Of Dictionary(Of String, String()))
'1) make array of fragments for each product info
Dim products = Regex.Split(sourceText, "(?=\[\s*\w+\s*])")
'2) declare variables needed ahead
Dim productProperties As Dictionary(Of String, String)
Dim propertyNames As String()
Dim productGroupedProperties As Dictionary(Of String, String())
Dim result As New List(Of Dictionary(Of String, String()))
'2) iterate along fragments
For Each product In products
'3) work only in significant fragments ([Product]...)
If Regex.IsMatch(product, "\A\[\s*\w+\s*]") Then
'4) make array of property lines and extract dictionary of property/description
productProperties = Regex.Split(product, "(?=^\w+\s*=)", RegexOptions.Multiline).Where(
Function(s) s.Contains("="c)
).ToDictionary(
Function(s) Regex.Match(s, "^\w+(?=\s*=)").Value,
Function(s) Regex.Match(s, "(?<==\s+).*(?=\s+)").Value)
'5) extract distinct property names, ignoring numbered repetitions
propertyNames = productProperties.Keys.Select(Function(s) s.TrimEnd("0123456789".ToCharArray)).Distinct.ToArray
'6) make dictionary of distinctProperty/Array(Of String){description, description1, ...}
productGroupedProperties = propertyNames.ToDictionary(
Function(s) s,
Function(s) productProperties.Where(
Function(kvp) kvp.Key.StartsWith(s)
).Select(
Function(kvp) kvp.Value).ToArray)
'7) enlist dictionary to result
result.Add(productGroupedProperties)
End If
Next
Return result
End Function
I have forgotten how to make an array or whatever out of 8 fields. It looks something like Array.Subcategory[x] afterwards but i've forgotten what its called and how to do it.
It needs to be 1 array with multiple entries but each entry have 8 sub entries.
So for a group of people
1 array entry will contain:
Name
Eye colour
Haircolour
Age
Balls
Smell
???
One array will contain all this data for each array entry.
cheers
You could define a class in VB.NET like this:
public class Entry
public Name as String
public EyeColour as String
public Haircolour as String
public Age as Integer
public Balls as Integer
public Smell as String
end class
Then create a List or Array holding entries like this:
public ListOfEntries as List(of Entry) = new List(of Entry)
public ArrayOfEntries(10) as Entry
Use it like this:
dim e as Entry = new Entry
e.Name = "Test"
e.EyeColour = "Blue"
' add new object to list
ListOfEntries.Add(e)
' add new object at position 0
ArrayOfEntries(0) = e
Another possibility would be to use a Structure (used-defined data type):
' a record of data
public structure Entry
public Name as String
public EyeColour as Integer
'...
end structure
' array of entries
public Entries(10) as Entry
' usage like in the class example
dim e = new Entry
e.Name = "Test"
e.EyeColour = 5
Entries(0) = e
You can do it with types also, which avoids some of the initialization hassels with classes in arrays:
Type foo
Name as String
EyeColour as Integer
...
End Type
Dim bar() As foo
How do I make an array of PictureBoxes in Visual Basic?
I'm trying to make a row of PictureBoxes -that's all the same size, and same picture- to display across the form. How could I do this?
I made the array using this:
Dim blk(10) As PictureBox
and the code to place the PictureBoxes is this:
'Create PictureBoxes
blk(0) = blk_Green()
blk(0).Image = imgl_blk.Images(0)
blk(0).Visible = True
blk(0).SetBounds(10, 10, blk_Green.Width, blk_Green.Height)
For i = 1 To 10 Step 1
blk(i) = blk_Green()
blk(i).Image = imgl_blk.Images(0)
blk(i).Visible = True
blk(i).SetBounds(i * 10, 10, blk_Green.Width, blk_Green.Height)'I will change this according to what it needs to be
Next
imgl_blk is an ImageList, and blk_Green is a ImageBox I've already made on the form.
When I run it, only one of the PictureBoxes will show up, instead of all 10 from the array.
This is what i'm trying to get (Or something like this):
This is what happens instead:
How could I make this work? Thanks in advance!
If you want to create a control array:
Dim blk() As PictureBox
blk = New PictureBox() {PictureBox1, PictureBox2, PictureBox3, PictureBox4}
Then you can reference PictureBox1 with blk(0), PictureBox2 with blk(1), PictureBox3 with blk(2) and PictureBox4 with blk(3).
You're assigning the same Object's reference to all 10 PictureBoxes. You need to instantiate each one of your PictureBoxes separately and then assign each one's Image property.
BTW, you should really look into GDI+'s drawing methods such as Graphics.DrawImage() to do this kind of stuff. It would be a lot faster and less of a memory-hog.
You may try this :
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim Shapes(10) As PictureBox
For i = 1 To 10
Shapes(i) = New PictureBox
Shapes(i).Name = "rect" + Str(i)
Shapes(i).BackColor = Color.Green
Shapes(i).Location = New Point(10 + 50 * i, 20)
Shapes(i).Size = New Size(40, 20)
Shapes(i).Visible = True
Me.Controls.Add(Shapes(i))
Next
End Sub
End Class