Coding a Euchre Game, Part 4: Tooltips and Menus (Matt Gertz)

Anthony D. Green [MSFT]

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.

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–*

EuchreMenuEdit.jpg

0 comments

Leave a comment

Feedback usabilla icon