Background
Make sure you:
- Have a decent understanding of OOP.
- Know how to draw to the form using
System.Drawing
and Control.CreateGraphics()
.
- Want to learn how to create controls!
About the code...
For this article, I'll show you how to create two controls with a casino theme: dice and cards. While these may be completely useless as controls when creating applications, they should give you a very good understanding of how to code others.
Part 1 - Dice
Of the two controls you'll be creating in this article, the dice are better polished, and thus a better example. However, once you're done here, the cards should have lots of areas you can go and customize.
Open up VS and create a new Class Library project named "Custom Controls". You can delete the default Class1.vb as we won't be using it. Add a user control to the project, and name it Dice
(or Die
). Your new control is a little rectangle. Click it and change these properties:
BackColor
to White.
BorderStyle
to FixedSingle.
Size
to 120, 120.
For the first bit of programming, create a new property: Public Property Pips() as Integer
. When set, make sure you check to see if the number is from 1 to 6. If it is, set Pips
to value
and call Me.Refresh()
. Create another Public
property as a System.Drawing.Brush
called PipBrush
. This is the brush that will paint the pips.
Dim _Pips As Integer = 1
Public Property Pips() As Integer
Get
Return _Pips
End Get
Set(ByVal value As Integer)
If value > 6 Then
Throw New ArgumentOutOfRangeException("Pips", _
"The number of Pips cannot be greater than 6.")
ElseIf value < 1 Then
Throw New ArgumentOutOfRangeException("Pips", _
"The number of Pips cannot be less than 1.")
Else
_Pips = value
Me.Refresh()
End If
End Set
End Property
Dim _brush As Brush = New SolidBrush(Color.Black)
Public Property PipBrush() As Brush
Get
Return _brush
End Get
Set(ByVal value As Brush)
_brush = value
End Set
End Property
The complete code is in the sample project.
Now that everything's set, we need to draw the dots in the Dice.Paint
event. Make sure it's the paint event, and not the load event you're working with! This is because if you put the code in the load event, when the die is obscured by another window, the pips will disappear. Here is the part of the method (the rest is available in the downloadable Custom Controls project):
Dim DrawingArea As Graphics = Me.CreateGraphics()
Dim DefaultSize As New Size(PipSize, PipSize)
Dim pntUpLeft As New Point(8, 8)
Dim pntUpRight As New Point(88, 8)
Dim pntMidLeft As New Point(8, 48)
Dim pntMid As New Point(48, 48)
Dim pntMidRight As New Point(88, 48)
Dim pntBotLeft As New Point(8, 88)
Dim pntBotRight As New Point(88, 88)
Select Case Me.Pips
Case 1
Dim Pip1 As New Rectangle(pntMid, DefaultSize)
DrawingArea.FillEllipse(Me.PipBrush, Pip1)
Case 2
Dim Pip1 As New Rectangle(pntUpLeft, DefaultSize)
Dim Pip2 As New Rectangle(pntBotRight, DefaultSize)
DrawingArea.FillEllipse(Me.PipBrush, Pip1)
DrawingArea.FillEllipse(Me.PipBrush, Pip2)
Case 3
...
Case 4
...
Case 5
...
Case 6
...
End Select
This is the code that draws the dots (pips) onto the die. It's pretty repetitive, so after the first two conditions, you should get the idea. Case 1
is called if there is one pip on the die. Dim Pip1 As New Rectangle(pntMid, DefaultSize)
defines where the dot will be and how big it is. Lastly, DrawingArea.FillEllipse(Me.PipBrush, Pip1)
draws the circle and fills it in. In case you're wondering, PipSize
is a constant equal to 24.
One more note: in the sample project, there is a region called Hidden Properties. What are these? They're properties that were inherited from UserControl
that either we don't want the user to have access to, or they won't effect the control. By following these examples, there are some other useless properties you can hide (or make useful).
Public Shadows ReadOnly Property NameOfProperty() As Type
Get
Return Nothing
End Get
End Property
Part 2 - Cards
I'll get you started on making a basic card control, but for the most part, you can play around with it and um... botch it anyway you please. The only new concept here is placing controls on controls. The card we're making is like a form - you can put any other control on it, as you'll see in a few seconds. First, add another user control to the project, naming it Card
. Then, set its properties like this:
BorderStyle
to FixedSingle.
Size
to 150, 165.
Then add two Label
s to the form:
Label 1
Name
to labPhrase.
Text
to Phrase.
Location
to 3,11.
Label 2
Name
to labAbbreviation.
Location
to 21,66.
Font
to Arial, 48pt.
Text
to ♥X, or any two-character string.
That's it for the designer. Note that the user won't have access to the individual labels you placed, only the card as a whole.
Now we have to find a way to specify which card is which - the number or value of each card, like 9, 10, Jack, Queen, etc. You could just use integers and verify it's in the correct range, but what if someone doesn't know that King = 13 off the top of their heads? Instead of forcing them to count on their fingers and toes, we can create an enum. While we're at it, make another one for the card's suit, too.
Public Enum Suits
JokerBlack = -2
JokerRed = -1
Clubs = 0
Diamonds = 1
Spades = 2
Hearts = 3
End Enum
Public Enum Cards
Joker = 0
Two = 2
Three = 3
Four = 4
Five = 5
Six = 6
Seven = 7
Eight = 8
Nine = 9
Ten = 10
Jack = 11
Queen = 12
King = 13
Ace = 14
End Enum
Notice there are three different items referring to jokers: JokerRed
, JokerBlack
, and Joker
. If any one of these is chosen, the card is a joker. Remember, my ideas are just guidelines; if you find a better way to do something, do it! " />
The CardNumber
and Suit
properties are simple, just storing and retrieving values.
Dim _crdNum As Cards = Cards.Joker
Public Property CardNumber() As Cards
Get
Return _crdNum
End Get
Set(ByVal value As Cards)
Dim old As Cards = _crdNum
_crdNum = value
RaiseEvent CardNumberChanged(old, value)
End Set
End Property
Dim _stSuit As Suits = Suits.JokerBlack
Public Property Suit() As Suits
...
End Property
The UpdateCard()
method is like the paint event in the dice control. Call it whenever you need to show the changes made to a card. Again, refer to the Custom Controls project for more on when the SuitChanged
and CardNumberChanged
events are called and the IsBlack
and IsRed
methods.
Private Sub Card_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
UpdateCard()
End Sub
Private Sub UpdateCard() Handles Me.SuitChanged, Me.CardNumberChanged
Dim strAbbr As String
Dim strPhrase As String
If (Me.Suit <> Suits.JokerRed) And (Me.Suit <> Suits.JokerBlack) Then
Dim IsNotRoyalty As Boolean = Me.CardNumber <> _
Cards.Jack And Me.CardNumber <> Cards.Queen And _
Me.CardNumber <> Cards.King And Me.CardNumber <> Cards.Ace
If IsNotRoyalty Then
strAbbr = Me.CardNumber & strSymbols(Me.Suit)
Else
strAbbr = Me.CardNumber.ToString()(0) & strSymbols(Me.Suit)
End If
If Me.CardNumber <> Cards.Joker Then
strPhrase = Me.CardNumber.ToString & _
" of " & Me.Suit.ToString
Else
strPhrase = "Joker"
strAbbr = "JK"
End If
Else
strPhrase = "Joker"
strAbbr = "JK"
End If
If Me.Suit = Suits.Clubs Or Me.Suit = Suits.Spades Or Me.Suit = Suits.JokerBlack Then
IsBlack()
Else
IsRed()
End If
labAbbreviation.Text = strAbbr
labPhrase.Text = strPhrase
End Sub
And that about wraps it up! I recommend adding a new Windows Application project to your solution to test the controls.
Things to Do
- Create a
Deck
collection.
Public Class Deck
_Inherits System.Collections.ObjectModel.Collection(Of Card)
...
End Class
Make the die resizable and adjust the pip size and position accordingly.
Make the card adjust to when it is resized.
Create Yahtzee! and Texas Hold'Em games with the new controls.
History