To illustrate what I was talking about here, I made a simple list box to show the concept. The picture illustrates what it looks like, and the code follows.
The Module1 module is the console application with the Main method (startup).
The ConsoleControl class is an abstract base for console controls. This class is for now incredible trivial, and I just built it to make this point.
Then, the ListBox class is the “control” itself and the ListBox item is a pair of a Long (the value) and a String (the visible representation).
I might be way out here, but I’d love to have something like this.
Module Module1
Sub Main()
'Create a listbox.
Dim Lb As New ListBox()
'Set some properties.
Lb.Height = 4
'Add some items
Lb.Add(4, "One")
Lb.Add(542, "Two")
Lb.Add(9, "Three")
Lb.Add(10, "Four")
Lb.Add(11, "Five")
Lb.Add(12, "Six")
Lb.Add(13, "Seven")
'Let the user make a selection.
Dim Answer As Integer = Lb.Ask()
'Just for testing: Pause to make sure that the console window is restored.
Console.ReadLine()
'Write out the answer and pause again.
Console.WriteLine(Answer.ToString())
Console.ReadLine()
End Sub
End Module
Public MustInherit Class ConsoleControl
Private m_X As Integer
Private m_Y As Integer
Private mWidth As Integer
Private mHeight As Integer
Private mBackgroundColor As System.ConsoleColor
Private mForegroundColor As System.ConsoleColor
Private mHighlightedBackgroundColor As System.ConsoleColor
Private mHighlightedForegroundColor As System.ConsoleColor
Private mInactiveForegroundColor As System.ConsoleColor
Public Sub New()
Me.m_X = 1
Me.m_Y = 1
Me.mWidth = 20
Me.mHeight = 10
Me.mBackgroundColor = ConsoleColor.Blue
Me.mForegroundColor = ConsoleColor.White
Me.mHighlightedBackgroundColor = ConsoleColor.White
Me.mHighlightedForegroundColor = ConsoleColor.Blue
Me.mInactiveForegroundColor = ConsoleColor.Gray
End Sub
Public Property X() As Integer
Get
Return Me.m_X
End Get
Set(ByVal value As Integer)
Me.m_X = value
End Set
End Property
Public Property Y() As Integer
Get
Return Me.m_Y
End Get
Set(ByVal value As Integer)
Me.m_Y = value
End Set
End Property
Public Property Width() As Integer
Get
Return Me.mWidth
End Get
Set(ByVal value As Integer)
Me.mWidth = value
End Set
End Property
Public Property Height() As Integer
Get
Return Me.mHeight
End Get
Set(ByVal value As Integer)
Me.mHeight = value
End Set
End Property
Public Property BackgroundColor() As ConsoleColor
Get
Return Me.mBackgroundColor
End Get
Set(ByVal value As ConsoleColor)
Me.mBackgroundColor = value
End Set
End Property
Public Property ForegroundColor() As ConsoleColor
Get
Return Me.mForegroundColor
End Get
Set(ByVal value As ConsoleColor)
Me.mForegroundColor = value
End Set
End Property
Public Property HighlightedBackgroundColor() As ConsoleColor
Get
Return Me.mHighlightedBackgroundColor
End Get
Set(ByVal value As ConsoleColor)
Me.mHighlightedBackgroundColor = value
End Set
End Property
Public Property HighlightedForegroundColor() As ConsoleColor
Get
Return Me.mHighlightedForegroundColor
End Get
Set(ByVal value As ConsoleColor)
Me.mHighlightedForegroundColor = value
End Set
End Property
Public Property InactiveForegroundColor() As ConsoleColor
Get
Return Me.mInactiveForegroundColor
End Get
Set(ByVal value As ConsoleColor)
Me.mInactiveForegroundColor = value
End Set
End Property
End Class
Public Class ListBox
Inherits ConsoleControl
Private mItems As List(Of ListBoxItem)
Private mViewOffset As Integer
Private mSelectedIndex As Integer
Private mSpacer As String = Nothing
Public Sub New()
MyBase.New()
Me.mItems = New List(Of ListBoxItem)()
Me.mSelectedIndex = -1
Me.mViewOffset = 0
End Sub
Friend ReadOnly Property Items() As List(Of ListBoxItem)
Get
Return Me.mItems
End Get
End Property
Public Function Add(ByVal Value As Integer, ByVal DisplayText As String) As Integer
Dim Item As New ListBoxItem(Me, Value, DisplayText)
Item.Index = mItems.Count
mItems.Add(Item)
Return Item.Index
End Function
Public Property SelectedIndex() As Integer
Get
Return Me.mSelectedIndex
End Get
Friend Set(ByVal value As Integer)
Me.mSelectedIndex = value
End Set
End Property
Public Function Ask() As Integer
Return Me.Ask(0)
End Function
Public Function Ask(ByVal DefaultValue As Integer) As Integer
If Me.mItems.Count > 0 Then
Me.mSpacer = Space(Me.Width)
Dim CursorVisible As Boolean = Console.CursorVisible
Dim FG As ConsoleColor = Console.ForegroundColor
Dim BG As ConsoleColor = Console.BackgroundColor
Console.CursorVisible = False
Me.SelectedIndex = ValueToIndex(DefaultValue)
Do
Me.DrawRegular()
Dim Key As ConsoleKeyInfo = Console.ReadKey(True)
If Key.Key = ConsoleKey.Escape Then
Me.SelectedIndex = -1
Exit Do
ElseIf Key.Key = ConsoleKey.Enter Then
Exit Do
Else
Select Case Key.Key
Case ConsoleKey.UpArrow
If Me.SelectedIndex = 0 Then
Me.SelectedIndex = Me.mItems.Count - 1
Else
Me.SelectedIndex -= 1
End If
Case ConsoleKey.DownArrow
If Me.SelectedIndex < (Me.mItems.Count - 1) Then
Me.SelectedIndex += 1
Else
Me.SelectedIndex = 0
End If
End Select
End If
Loop
Me.DrawDead()
Console.CursorVisible = CursorVisible
Console.ForegroundColor = FG
Console.BackgroundColor = BG
Dim CursY As Integer = (Me.Y + Me.Height)
If CursY >= Console.WindowHeight Then
CursY = Console.WindowHeight - 1
End If
Console.CursorTop = CursY
Console.CursorLeft = 0
Return Me.mItems(Me.SelectedIndex).Value
Else
Return -1
End If
End Function
Private Function ValueToIndex(ByVal Value As Integer) As Integer
'This is only called from the Ask function, and the Ask funktion will only run if mItems.Count>0. No need for extra check.
For I As Integer = 0 To Me.mItems.Count - 1
If Me.mItems(I).Value = Value Then
Return I
End If
Next
Return 0
End Function
Private Sub DrawRegular()
'Make sure that the selection is inside the visible area.
If Me.mViewOffset > Me.SelectedIndex Then
While Me.mViewOffset > Me.SelectedIndex
Me.mViewOffset -= 1
End While
ElseIf (Me.mViewOffset + Me.Height) <= Me.SelectedIndex Then
While (Me.mViewOffset + Me.Height) <= Me.SelectedIndex
Me.mViewOffset += 1
End While
End If
'Draw the visible items.
For I As Integer = 0 To Me.Height - 1
Dim IndexToDisplay As Integer = I + Me.mViewOffset
Console.CursorLeft = Me.X
Console.CursorTop = Me.Y + I
If IndexToDisplay < Me.mItems.Count Then
If Me.mItems(IndexToDisplay).Selected Then
Console.ForegroundColor = Me.HighlightedForegroundColor
Console.BackgroundColor = Me.HighlightedBackgroundColor
Else
Console.ForegroundColor = Me.InactiveForegroundColor
Console.BackgroundColor = Me.BackgroundColor
End If
Console.Write(Me.mItems(IndexToDisplay).DisplayString)
Else
Console.ForegroundColor = Me.InactiveForegroundColor
Console.BackgroundColor = Me.BackgroundColor
Console.Write(Me.mSpacer)
End If
Next
End Sub
Private Sub DrawDead()
'Draw the visible items as inactive.
For I As Integer = 0 To Me.Height - 1
Dim IndexToDisplay As Integer = I + Me.mViewOffset
Console.CursorLeft = Me.X
Console.CursorTop = Me.Y + I
If IndexToDisplay < Me.mItems.Count Then
If Me.mItems(IndexToDisplay).Selected Then
Console.ForegroundColor = Me.ForegroundColor
Console.BackgroundColor = Me.BackgroundColor
Else
Console.ForegroundColor = Me.InactiveForegroundColor
Console.BackgroundColor = Me.BackgroundColor
End If
Console.Write(Me.mItems(IndexToDisplay).DisplayString)
Else
Console.ForegroundColor = Me.InactiveForegroundColor
Console.BackgroundColor = Me.BackgroundColor
Console.Write(Me.mSpacer)
End If
Next
End Sub
End Class
Friend Class ListBoxItem
Private mListBox As ListBox
Private mValue As Integer
Private mText As String
Private mIndex As Integer = 0
Private mDisplayString As String = Nothing
Friend Sub New(ByVal Owner As ListBox, ByVal Value As Integer, ByVal DisplayText As String)
Me.mListBox = Owner
Me.mValue = Value
Me.mText = DisplayText.Trim()
End Sub
Public Property Index() As Integer
Get
Return Me.mIndex
End Get
Friend Set(ByVal value As Integer)
Me.mIndex = value
End Set
End Property
Friend ReadOnly Property OwnerListBox() As ListBox
Get
Return Me.mListBox
End Get
End Property
Public ReadOnly Property Value() As Integer
Get
Return Me.mValue
End Get
End Property
Public ReadOnly Property Text() As String
Get
Return Me.mText
End Get
End Property
Public Property Selected() As Boolean
Get
Return (Me.OwnerListBox.SelectedIndex = Me.Index)
End Get
Set(ByVal value As Boolean)
If value Then
Me.OwnerListBox.SelectedIndex = Me.Index
Else
Me.OwnerListBox.SelectedIndex = -1
End If
End Set
End Property
Friend ReadOnly Property DisplayString() As String
Get
If Me.mDisplayString Is Nothing Then
'This code will only run once per item, but it still needs rewriting. Risk for multiple memory reallocations.
Me.mDisplayString = " " & Me.Text
If Me.mDisplayString.Length > Me.OwnerListBox.Width Then
Me.mDisplayString = Me.mDisplayString.Substring(0, Me.OwnerListBox.Width)
Else
While Me.mDisplayString.Length < Me.OwnerListBox.Width
Me.mDisplayString &= " "
End While
End If
End If
Return Me.mDisplayString
End Get
End Property
End Class
Leave a Reply