VB.Net - Lambda Periodic Table Searcher
Overview
This article is intended to show two programming lessons for beginner programmers.
First, it shows how to combine object arrays, simple user-defined object classes, properties, and simple code, to create OOP (Object Oriented Programming) applications with Visual Studio.
Secondly, it shows how to use simple LINQ queries with Lambda functions, to quickly search a user-defined object array.
Arrays in VS can be arrays of primitive types (Integer, Byte, Boolean etc.), but it's possible to create an array of just about any type you can imagine. A user-defined class typically contains Properties and Public or sometimes Private Methods. In the case of the example programs there are two user-defined classes - ElementDetails, which contains (from each element) the AtomicNumber, the Symbol, the Element (name), the [Type] (the Element's group), and finally the Image Property, which actually returns a dynamic Bitmap created on the fly in the Property Getter. The [Type] Property could have been a String representing the name of the group, but it was advantageous to store two Properties related to the Group - the name, and a color. So, the return type of the Type Property is ElementType, which is the second of the core classes used.
LINQ combined with Lambda gives great results from minimal code. It is possible to query the user-defined array on any of the Properties to retrieve either one element or a group of elements.
The searchForm code
Public Class searchForm
Dim types() As ElementType =
{New ElementType("Alkali metal", 255, 101, 101),
New ElementType("Alkaline earth metal", 255, 222, 174),
New ElementType("Lanthanide", 255, 188, 253),
New ElementType("Actinide", 255, 150, 201),
New ElementType("Transition metal", 255, 190, 191),
New ElementType("Post-transition metal", 203, 203, 203),
New ElementType("Metalloid", 203, 204, 154),
New ElementType("Polyatomic nonmetal", 159, 255, 196),
New ElementType("Diatomic nonmetal", 230, 255, 148),
New ElementType("Noble gas", 190, 255, 255),
New ElementType("Unknown chemical properties", 231, 231, 231)}
Dim elements(117) As ElementDetails
Dim ignore As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim lines() As String = My.Resources.elements.Split(New String() {Environment.NewLine}, StringSplitOptions.None)
For x As Integer = 0 To 117
elements(x) = New ElementDetails(types, lines(x).Split("|"c))
Next
End Sub
Private Sub updateFields(ByVal exclude As Integer, current As ElementDetails)
If ignore Then Return
ignore = True
Select Case exclude
Case 0
If current IsNot Nothing Then
TextBox1.Text = current.Symbol
TextBox2.Text = current.Element
Button1.BackColor = current.Type.Color
Button1.Text = current.Type.Name
Else
clearFields(exclude)
End If
Case 1
If current IsNot Nothing Then
NumericUpDown1.Value = current.AtomicNumber
TextBox2.Text = current.Element
Button1.BackColor = current.Type.Color
Button1.Text = current.Type.Name
Else
clearFields(exclude)
End If
Case 2
If current IsNot Nothing Then
NumericUpDown1.Value = current.AtomicNumber
TextBox1.Text = current.Symbol
Button1.BackColor = current.Type.Color
Button1.Text = current.Type.Name
Else
clearFields(exclude)
End If
End Select
ignore = False
End Sub
Private Sub clearFields(ByVal exclude As Integer)
ignore = True
Select Case exclude
Case 0
NumericUpDown1.Value = 0
TextBox2.Text = ""
Button1.BackColor = SystemColors.Control
Button1.Text = ""
Case 1
NumericUpDown1.Value = 0
TextBox2.Text = ""
Button1.BackColor = SystemColors.Control
Button1.Text = ""
Case 2
NumericUpDown1.Value = 0
TextBox1.Text = ""
Button1.BackColor = SystemColors.Control
Button1.Text = ""
End Select
ignore = False
End Sub
Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged, NumericUpDown1.TextChanged
updateFields(0, elements.FirstOrDefault(Function(el) el.AtomicNumber = CInt(NumericUpDown1.Value)))
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
updateFields(1, elements.FirstOrDefault(Function(el) el.Symbol = TextBox1.Text))
End Sub
Private Sub TextBox2_TextChanged(sender As Object, e As EventArgs) Handles TextBox2.TextChanged
updateFields(2, elements.FirstOrDefault(Function(el) el.Element = TextBox2.Text))
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Button1.Text <> "" Then
Dim frm As New listForm(Button1.Text, elements.Where(Function(el) el.Type.Name = Button1.Text).ToArray)
frm.ShowDialog()
End If
End Sub
End Class
The ElementDetails Class code
'''
''' <summary>
''' @author Paul Long
''' </summary>
Public Class ElementDetails
Private _atomicNumber As Integer
Private _symbol As String
Private _element As String
Private _type As ElementType
''' <returns> the atomicNumber </returns>
Public ReadOnly Property AtomicNumber As Integer
Get
Return Me._atomicNumber
End Get
End Property
''' <returns> the symbol </returns>
Public ReadOnly Property Symbol As String
Get
Return Me._symbol
End Get
End Property
''' <returns> the element </returns>
Public ReadOnly Property Element As String
Get
Return Me._element
End Get
End Property
''' <returns> the type </returns>
Public ReadOnly Property [Type] As ElementType
Get
Return Me._type
End Get
End Property
Public ReadOnly Property Image As Bitmap
Get
Dim img As New Bitmap(120, 80)
Dim g As Graphics = Graphics.FromImage(img)
g.Clear(Me.Type.Color)
g.DrawRectangle(Pens.Black, 0, 0, 119, 79)
Dim sf As New StringFormat
sf.Alignment = StringAlignment.Center
sf.LineAlignment = StringAlignment.Center
g.DrawString(Me.AtomicNumber.ToString(), New Font(searchForm.Font.FontFamily, 12, FontStyle.Bold), Brushes.Black, New Rectangle(0, 0, 120, 25), sf)
g.DrawString(Me.Symbol, New Font(searchForm.Font.FontFamily, 12, FontStyle.Bold), Brushes.Black, New Rectangle(0, 27, 120, 25), sf)
g.DrawString(Me.Element, searchForm.Font, Brushes.Black, New Rectangle(0, 52, 120, 25), sf)
Return img
End Get
End Property
Public Sub New(ByVal elementTypes() As ElementType, ParamArray ByVal fields() As String)
Me._atomicNumber = CInt(fields(0).Trim())
Me._symbol = fields(1).Trim()
Me._element = fields(2).Trim()
Me._type = elementTypes.Where(Function(x) fields(3).Trim().Equals(x.Name)).First()
End Sub
End Class
Conclusion
This article teaches good programming practice through encapsulation, and composition, which are essential elements of good OOP Programming. Using Class objects, arrays and LINQ it's easy to create concise and effective programs in minutes, and your code will be readable industry standard code.
Other Resources
Download here... VB.Net / C#