Coding a Euchre Game, Part 4: Tooltips and Menus
Menus and tooltips are so incredibly important to applications, and yet implementing them sometimes seems to be arcane magic. In this post, I’m going to do my best to demystify them.
Menus
To add a menu, you simply drag a MenuStrip control from the toolbox to your form. As with the Timer control from the last post, the control will end up in the grey area at the bottom of the form; however, there will also be a visible component at the top of the form. Use the former to change the name of the control, but mostly you’ll be working with the visual instance at the top.
Now, if you wanted to quickly add a whole set of standard menu items such as File, Edit, Tools, etc., you could click on the smart tag in the upper-right corner of the menustrip and choose “Insert Standard Menu Items,” thus populating the menu with those menus automatically. However, we don’t want standard menus for this game, as most of the menu items would not be relevant. Instead, place your cursor in the editbox on the menustrip and type “&VBEuchre.” This creates a Drop-down menu called VBEuchre. Note how the ampersand (&) forces the following character to be underlined! That’s the character that will automatically be used when navigating with the ALT key. You can also add commands under the “VBEuchre” menu item by typing into the edit boxes. You can specify ALT mnemonics using the ampersand character, or can assign key shortcuts by selecting the menu item and setting its various ShortcutKey properties. You can even define secondary tiers of menus, though we won’t be doing that for this game. The attached picture shows what menu-editing looks like.
Adding command handlers to menu items is identical to adding them to any other control – just double-click them to create the handler and then add your code to it. For “New Game,” this Is very simple:
Private Sub NewGameToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles NewGameToolStripMenuItem.Click
NewGame()
End Sub
NewGame() then has to check to see if a game is already under way, and pops up a “Do you want to quit your current game?” messagebox if so:
Public Sub NewGame()
If GameStarted = True Then
If MessageBox.Show(My.Resources.Command_New,_
My.Resources.Command_NewTitle, MessageBoxButtons.OKCancel, _
MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) <> _
Windows.Forms.DialogResult.OK Then
Return
End If
End If
If InvokedOnce = False Then
NewGameInvoked()
Else
‘ NewGameInvoked is already on the stack. We don’t want to recurse into it.
‘ Throw back up to that method so it can restart itself.
newEuchre = True
End If
End Sub
Note that my variables “GameStarted” and “InvokedOnce” are checking two different things. “GameStarted” means that play is actually happening. “InvokedOnce” is simply a re-entrancy check – the gameplay might not have started yet, but the user might nevertheless be involved in other code in NewGameInvoked such as setting the options or whatever. (In other words, if GameStarted is True, then InvokedOnce must be True, but the converse is not necessarily true.) The “newEuchre” variable will be used exactly like the “exitEuchre” variable from the previous post – it causes the timer to be turned off and an exception to be thrown to start a new game, so those methods now become:
Private Sub TableSleep()
StopPumpingMessagesDuringPause = False
EuchreTimer.Start()
While StopPumpingMessagesDuringPause = False
Application.DoEvents()
End While
If exitEuchre = True Then
Throw New EuchreException(“ExitGame”)
End If
If newEuchre = True Then
Throw New EuchreException(“NewGame”)
End If
End Sub
Private Sub NewGameInvoked()
Begin: Try
Do While exitEuchre = False
‘ (this is where the game actually happens –
I’ve omitted the actual code for brevity’s sake)
Loop
Catch ex As EuchreException
‘ Reset the flag and let it go back through to
‘ the loop to restart the game
If ex.Message = “NewGame” Then
newEuchre = False
GoTo Begin
End If
If ex.Message = “ExitGame” Then
exitEuchre = False
‘ Do nothing; fall through and exit the application
End If
End Try
End Sub
I usually detest using GoTo statements, actually, but in this case it made sense to do so.
Tooltips
Tooltips are another control which get dragged to the form but are acted upon in the grey area. The only changes that need to be made to its properties are changing the name and setting AlwaysShow to True. It seems counterintuitive, but you only need one tooltip per form. This is because the tooltip keeps a list of what each control’s tooltip should be. (This is where many people get confused – they expect the tooltip to be a property on each control, but that’s not the way it works.)
To set a tooltip for a control is a very simple thing. Recall that the labels which represent the places where cards can go on the table are referenced in an array called TableTopCards. Let’s pretend that a card is face down and we want to set a tooltip for it. The tooltip string is in the resource manager and is named CARDNAME_BACK. We would then set the tooltip like this:
EuchreTooltip.SetToolTip(Me.TableTopCards(player, slot), _
My.Resources.CARDNAME_BACK)
And we could clear it like this
EuchreTooltip.SetToolTip(Me.TableTopCards(player, slot), _
Nothing)
Most of the tooltips resource string names in Euchre need to be constructed based on the name and suit of the card, are are thus referenced similar to the image resource names I presented several posts ago. However, there’s a catch: If the Right Bower or Left Bower (the Jack of the trump suit or the Jack in the suit of the same color as the trump suit) are involved, then I want the tooltip to call them Bowers instead of their actual name, so that the user remembers that they are trump cards. So, we add a method in EuchreCard thusly:
Public Function GetDisplayStringResourceName(Optional ByVal TrumpSuit _
As Suits = Suits.NoSuit) As String
If State = States.FaceUp OrElse Table.PeekAtOtherCards = True _
OrElse Table.SelectingDealer Then
Dim FileName As New StringBuilder()
If TrumpSuit <> Suits.NoSuit AndAlso _
(Me.GetValue(TrumpSuit) = Values.LeftBower _
OrElse Me.GetValue(TrumpSuit) = Values.RightBower) Then
If Me.GetValue(TrumpSuit) = Values.RightBower Then
FileName.Append(“CARDNAMERightBower”)
Return FileName.ToString
Else
FileName.Append(“CARDNAMELeftBower”)
Return FileName.ToString
End If
Else
FileName.AppendFormat(“CARDNAME{0}Of{1}”, Rank, Suit)
Return FileName.ToString
End If
Else
Return “CARDNAME_BACK”
End If
End Function
And now we use the resulting string as follows to set the tooltip for an arbitrary card at position “i” in the player’s hand:
EuchreTooltip.SetToolTip(
Me.TableTopCards(EuchrePlayer.Seats.Player, i), _
My.Resources.ResourceManager.GetString( _
Players(EuchrePlayer.Seats.Player).CardsHeldThisHand(i _
).GetDisplayStringResourceName))
That’s it for today. Next time, we’ll discuss modality and user controls. Until then…
–Matt–*
0 comments
Be the first to start the discussion.