{"id":6423,"date":"2007-03-23T19:31:00","date_gmt":"2007-03-23T19:31:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2007\/03\/23\/coding-a-euchre-game-part-8-remember-me-show-me-help-me-matt-gertz\/"},"modified":"2024-07-05T14:49:00","modified_gmt":"2024-07-05T21:49:00","slug":"coding-a-euchre-game-part-8-remember-me-show-me-help-me-matt-gertz","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/coding-a-euchre-game-part-8-remember-me-show-me-help-me-matt-gertz\/","title":{"rendered":"Coding a Euchre Game, Part 8:  Remember Me, Show Me, Help Me (Matt Gertz)"},"content":{"rendered":"<h2><font size=\"5\"><font color=\"#365f91\"><font face=\"Cambria\">Coding a Euchre Game, <span>Part 8:<span>&nbsp; <\/span>Remember Me, Show Me, Help Me<\/span><\/font><\/font><\/font><\/h2>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">We\u2019re getting close to wrapping up this series.<span>&nbsp; <\/span>In this post, I want to cover several \u201cclean up\u201d topics, and then in the following post, I\u2019ll talk about deployment and will attach the entire codebase for your perusal.<\/font><\/font><\/span><\/p>\n<h2><span><font size=\"4\"><font color=\"#4f81bd\"><font face=\"Cambria\">Settings<\/font><\/font><\/font><\/span><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">You\u2019ll note, from earlier posts, that there are a lot of options around variations in the Euchre rules, options for AI personalities, options for sound, and even options for the names of the players.<span>&nbsp; <\/span>Obviously, it would be really annoying if you had to specify those at the beginning of each session!<span>&nbsp; <\/span>The best thing to do would be to persist the user\u2019s choices for each option and reload them whenever the game is launched.<span>&nbsp; <\/span>Now, in \u201cYe Olde Days,\u201d what you\u2019d typically do is create or open a user options file, figure out a format in which to store this data, and then write it or read it as appropriate.<span>&nbsp; <\/span>This was a mildly annoying process in that you\u2019d have to re-code your format (and potentially add code to be backwards-compatible) every time you added options, plus you\u2019d have to figure out where to store the options, etc.<span>&nbsp; <\/span>Fortunately, there\u2019s a better way to do this in VS2005 \u2013 it\u2019s so easy that once you start using it, you\u2019ll never go back to doing it the old way!<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The mechanism to use to implement setting persistence is My.Settings.<span>&nbsp; <\/span>Using this mechanism allows you to treat each setting as if it were a property, *plus* with one line of code you can save or retrieve settings from an application data file that is automatically created for you \u2013 and you don\u2019t even need to keep track of where the file is!<span>&nbsp; <\/span>There\u2019s also support for versioning, so that you can have different settings for different versions of your app.<span>&nbsp; <\/span>Here\u2019s how you do it:<\/font><\/p>\n<p class=\"MsoListParagraphCxSpFirst\"><span><span><font face=\"Calibri\" size=\"3\">(1)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">Bring up the project\u2019s properties (right-click the project, choose \u201cProperties\u201d), and click on the Settings tab.<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font face=\"Calibri\" size=\"3\">(2)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">You\u2019ll notice a grid appears.<span>&nbsp; <\/span>In the grid, choose a name for the setting (e.g., \u201cPlayerName\u201d), the type of the setting<span>&nbsp; <\/span>(e.g., String), and the default value (e.g., \u201cPlayer 1\u201d).<span>&nbsp; <\/span>Leave the scope as user.<span>&nbsp; <\/span>(If you set it to \u201capplication,\u201d then everyone would share the same options, which would be annoying in this case.)<span>&nbsp; <\/span>Continue to do this for each setting, using Booleans for checkboxes, Integers for the voice indices, etc.<span>&nbsp; <\/span>I\u2019ve attached a picture of what mine look like.<\/font><\/p>\n<p class=\"MsoListParagraphCxSpLast\"><span><span><font face=\"Calibri\" size=\"3\">(3)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">Now, open up the options dialog, and double-click it to automatically create the <span>&nbsp;<\/span>event handler for \u201cLoad.\u201d<span>&nbsp; <\/span>In that event handler, add the code to initialize the dialog with the user settings \u2013 for example:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.PlayerName.Text = <span>My<\/span>.Settings.PlayerName<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.LeftVoiceCombo.SelectedIndex = <span>My<\/span>.Settings.LeftOpponentVoice<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.SoundOn.Checked = <span>My<\/span>.Settings.SoundOn<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.LeftOpponentCrazy.Checked = (<span>My<\/span>.Settings.LeftOpponentPlay = 1)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><span>&#8216; Etc\u2026 for brevity\u2019s sake, I\u2019ve left out a lot of these<\/span><\/p>\n<p class=\"MsoListParagraph\"><span><span><font face=\"Calibri\" size=\"3\">(4)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span><font size=\"3\"><font face=\"Calibri\">Then the other half of this is persisting out the settings, so double-click on the \u201cOK\u201d button to create its click event handler, and add code opposite of what you did before, such as the following:<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>My<\/span>.Settings.PlayerName = <span>Me<\/span>.PlayerName.Text<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>My<\/span>.Settings.LeftOpponentVoice = <span>Me<\/span>.LeftVoiceCombo.SelectedIndex<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>My<\/span>.Settings.SoundOn = <span>Me<\/span>.SoundOn.Checked<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>If<\/span> <span>Me<\/span>.LeftOpponentCrazy.Checked = <span>True<\/span> <span>Then<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>My<\/span>.Settings.LeftOpponentPlay = 1<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>ElseIf<\/span> LeftOpponentNormal.Checked = <span>True<\/span> <span>Then<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>My<\/span>.Settings.LeftOpponentPlay = 2<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Else<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>My<\/span>.Settings.LeftOpponentPlay = 3<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>If<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><span>&#8216; Etc\u2026 again, for brevity\u2019s sake, I\u2019ve left out a lot of these<\/span><\/p>\n<p class=\"MsoNormal\"><span><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font face=\"Calibri\" size=\"3\">That\u2019s *it*; that\u2019s all you have to do.<span>&nbsp; <\/span>The settings will be persisted when the app closes, and loaded when the app is launched. You don\u2019t have to do anything.<span>&nbsp; <\/span>You can even hook up a \u201cReset\u201d button which will call My.Settings.Reset to return the setting to the \u201cfactory defaults.\u201d<span>&nbsp; <\/span>The code to handle this is autogenerated for you in the normally-hidden files settings.settings.vb, application.myapp, etc., and the settings themselves are persisted in a (similarly normally-hidden) application data file called user.config in the user\u2019s personal directory.<span>&nbsp; <\/span>(See <\/font><a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/a65txexh(VS.80).aspx\"><font face=\"Calibri\" color=\"#0000ff\" size=\"3\">http:\/\/msdn2.microsoft.com\/en-us\/library\/a65txexh(VS.80).aspx<\/font><\/a><font size=\"3\"><font face=\"Calibri\"> if you really want to know all of the gory details.) You can also turn off saving the settings at shutdown from the \u201cApplication\u201d tab in the project\u2019s properties (in which case you\u2019d use My.Settings.Save to save them programmatically.)<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><font size=\"3\"><font face=\"Calibri\">One more note before we move on to the next topic \u2013 you should always think twice before storing sensitive information like passwords, etc., using user settings.<span>&nbsp; <\/span>Although nominally confined to the user\u2019s own directory, the data in the user file still stored in clear text, so why take the chance?<\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/span><\/p>\n<h2><span><font size=\"4\"><font color=\"#4f81bd\"><font face=\"Cambria\">Rich Text Box Controls &amp; Help<\/font><\/font><\/font><\/span><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Edit boxes have been a mainstay of applications since graphical interfaces first began, but let\u2019s face it; they\u2019re terrible to deal with regarding formatting.<span>&nbsp; <\/span>Rich Text Box controls are definitely the way to go if you need to do lots of fancy things with text.<span>&nbsp; <\/span>I use a couple of them in my Euchre application, so let\u2019s take a peek at those.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The first one I use is on the table form itself.<span>&nbsp; <\/span>I use the rich text edit control to keep repeat back to the user what\u2019s happening in the game.<span>&nbsp; <\/span>For example, when Player 2 plays a card, I repeat back \u201cPlayer 2 plays the Left Bower\u201d or whatever the card was.<span>&nbsp; <\/span>The idea here is that the user can scroll back through history and see what\u2019s already happened.<span>&nbsp; <\/span>Now, in the actual game of Euchre, players are forbidden from looking through tricks that have already been played, and this might seem to fly in the face of that rule, but this sort of counterbalances the impersonality of the game \u2013 in real life, the player would probably yell \u201cAha! My Left Bower takes all of your pitiful little cards\u2026 come to daddy\u2026mine, mine, all mine\u2026,\u201d which would certainly stick in one\u2019s memory in a way which the AI could never do (at least as coded).<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">So, I need a control that can take a lot of text and which can have a scroll bar.<span>&nbsp; <\/span>That pretty well eliminates the normal edit box as well as the label control, so I\u2019ve used a rich text box control here.<span>&nbsp; <\/span>The initialization is fairly simple:<span>&nbsp; <\/span>set ReadOnly to True, ScrollBars to Vertical, and the backcolor &amp; font to whatever appeals to you (I\u2019ve gone for a light yellow background with Copperplate Gothic <span>&nbsp;<\/span>12pt. as the font).<span>&nbsp; <\/span>I don\u2019t need any validation on the control, so I set CausesValidation to False, and I\u2019ve also set DetectUrls to False since I won\u2019t have any and so I don\u2019t need the control wasting time trying to figure that out.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Now, as far as using it goes \u2013 also very simple.<span>&nbsp; <\/span>The following code does the trick for me:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> <span>Sub<\/span> UpdateStatus(<span>ByVal<\/span> s <span>As<\/span> <span>String<\/span>, _<\/span><\/p>\n<p class=\"MsoNormal\"><span>Optional<\/span><span> <span>ByVal<\/span> WhiteSpace <span>As<\/span> <span>Integer<\/span> = 1)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.StatusArea.AppendText(s)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>If<\/span> WhiteSpace &gt; 0 <span>Then<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>For<\/span> i <span>As<\/span> <span>Integer<\/span> = 1 <span>To<\/span> WhiteSpace<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.StatusArea.AppendText(vbCrLf)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Next<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>If<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.StatusArea.Update()<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Sub<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Where the usage is something like (in the EuchrePlayer class):<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp; <\/span><span>Dim<\/span> s <span>As<\/span> <span>New<\/span> StringBuilder()<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp; <\/span>s.AppendFormat(<span>My<\/span>.Resources.Notice_IPickItUpAlone, GetDisplayName(Table), _<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp; <\/span><span>&nbsp;&nbsp;&nbsp;<\/span>My<\/span><span>.Resources.ResourceManager.GetString( _<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>EuchreCard.GetSuitDisplayStringResourceName(Table.TrumpSuit)))<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp; <\/span>Table.UpdateStatus(s.ToString)<\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">To (in this example) format a string which says \u201cPlayer 1 says &#8216;I\u2019m picking it up and going alone \u2013 trump is spades&#8217;\u201d and then applying it to the control without adding extra line spacing after it.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">So far, so good \u2013 none of that seems earth-shattering.<span>&nbsp; <\/span>However, I\u2019ve got another rich text box that I use for Help.<span>&nbsp; <\/span>Rather than jump in with the control, let\u2019s start at the beginning and talk about Help.<\/font><\/p>\n<h2><font face=\"Cambria\" color=\"#4f81bd\" size=\"4\">Help<\/font><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">There\u2019s nothing magic about supporting Help.<span>&nbsp; <\/span>Help is just another event, albeit one that everyone is familiar with.<span>&nbsp; <\/span>You may have noticed a few posts back that I added a \u201cHelp\u201d menu item to my menustrip control.<span>&nbsp; <\/span>I have two entries in that menu: \u201cAbout\u2026\u201d and \u201cRules\u2026\u201d<span>&nbsp; <\/span>Let\u2019s take these separately:<\/font><\/p>\n<h3><font face=\"Cambria\" color=\"#4f81bd\" size=\"3\">\u201cAbout\u2026\u201d <\/font><\/h3>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\"><span>&nbsp;<\/span>Right-click the project, choose \u201cAdd\u201d and then \u201cWindows Form.\u201d<span>&nbsp; <\/span>Select \u201cAbout Box\u201d from the resulting dialog and give the file a name such as \u201cEuchreAboutBox.\u201d<span>&nbsp; <\/span>Click \u201cAdd\u201d to add it to the project.<span>&nbsp; <\/span>(The \u201cAbout\u201d box will auto populate with the typical application information at runtime, although you can tweak it however you like by opening the form in the usual way.)<span>&nbsp; <\/span>Now, double-click on the \u201cAbout\u2026\u201d menu item on the menustrip and add these two lines to the resulting event handler:<\/font><\/font><\/p>\n<p class=\"MsoNormal\"><span><font face=\"Calibri\" size=\"3\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/font><\/span><span><span>&nbsp; <\/span><span>Dim<\/span> dlg <span>As<\/span> <span>New<\/span> EuchreAboutBox<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>dlg.ShowDialog()<\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">That\u2019s it; all done.<\/font><\/p>\n<h3><font face=\"Cambria\" color=\"#4f81bd\" size=\"3\">\u201cRules\u2026\u201d<\/font><\/h3>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">This is very similar to \u201cAbout\u2026\u201d, but instead I\u2019m going to add a normal \u201cWindows Form\u201d to the project instead of an About Box.<span>&nbsp; <\/span>(You may prefer to have rules come up in the typical \u201csearch\/index\/contents\u201d sort of help, but that\u2019s a topic for a different time\u2026 I mean, it *is* just a card game, and anyway I want to demonstrate another property of the Rich Text Box.)<span>&nbsp; <\/span>To this form I\u2019m just going to add a rich text box and a button.<span>&nbsp; <\/span>The button is labeled \u201cClose,\u201d and all it does is dismiss the form, so I set its its click event to Me.Close(), and otherwise I pretty much leave it alone.<span>&nbsp; <\/span>The rich text box is similarly simple: I choose a font and background color that I like and set those in the properties, I set it to read-only, and give it a name such as \u201cRtfRules.\u201d<span>&nbsp; <\/span>(\u201cScroll Bars\u201d already defaults to \u201cBoth\u201d so I leave it alone.)<span>&nbsp; <\/span>Then, I add one line of code in the Form Load Event to leverage that property I alluded to before:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&nbsp;&nbsp;&nbsp;<\/span><span>Me<\/span>.RtfRules.Rtf = <span>My<\/span>.Resources.VBEuchreRules<\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Which connects the Rich Text Box to an RTF file I have stored in my resource manager.<span>&nbsp; <\/span>Yes, you can add RTF files to the resource manager, the same way you add any other resource!<span>&nbsp; <\/span>In my case, I created a nice-looking &#8220;rules&#8221; file in Word, saved it as an RTF file, chucked it into the resource manager, and reference it as above.<span>&nbsp; If I need to change the RTF file, I just right-click the RTF file (which will show up in my project treeview) and choose &#8220;Open with Word,&#8221; then rebuild once I&#8217;ve saved the file again.&nbsp; Using the Rich Text Box and the RTF file is&nbsp;<\/span>simple, it looks nice, and Rich Text Boxes already have a property which can accept RTF as a target so I\u2019m all set.<span>&nbsp; <\/span>I just need to bring up the Rules form when requested:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> <span>Sub<\/span> RulesToolStripMenuItem_Click(<span>ByVal<\/span> sender <span>As<\/span> System.Object, _<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>ByVal<\/span> e <span>As<\/span> System.EventArgs) <span>Handles<\/span> RulesToolStripMenuItem.Click<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> rulesform <span>As<\/span> <span>Object<\/span> = <span>My<\/span>.Application.OpenForms(<span>&#8220;EuchreRules&#8221;<\/span>)<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>If<\/span> rulesform <span>Is<\/span> <span>Nothing<\/span> <span>Then<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> x <span>As<\/span> <span>New<\/span> EuchreRules<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>x.Show()<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Else<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>CType<\/span>(rulesform, EuchreRules).Activate()<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>If<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Sub<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">This is a *modeless* dialog (so you can see the rules while playing), so I first check to see if the dialog already exists by leveraging the My.Application.OpenForms functionality.<span>&nbsp; <\/span>If it doesn\u2019t exist yet, I create it using Show() (<b>not<\/b> ShowDialog(), which would make it modal).<span>&nbsp; <\/span>If it does exist, then I bring it to the front via Activate(), first casting the object to the form&#8217;s type so that I can access that method.<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">Of course, you can link it up to the F1 key as well.<span>&nbsp; <\/span>Back in the form editor for the main form, select the \u201cRules\u2026\u201d item and set the ShortcutKeyDisplay property to \u201cF1\u201d (without quotes; that\u2019s the text that will display on the menu next to the item)<span>&nbsp; <\/span>and then also set the ShortcutKeys property to <b>F1<\/b>, to indicate the keystroke that will trigger the menu item.<span>&nbsp; <\/span>That\u2019s all it takes!<span>&nbsp; <\/span><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">(As an aside:<span>&nbsp; <\/span>you could also do this without setting the Shortcuts property by handling the KeyUp event yourself, though I don\u2019t recommend it.<span>&nbsp; <\/span>To do this, right-click on the EuchreTable file and choose \u201cView Code.\u201d<span>&nbsp; <\/span>Now, at the top of editor, you\u2019ll see two dropdowns.<span>&nbsp; <\/span>Change the left dropdown to say \u201c(EuchreTable Events).\u201d<span>&nbsp; <\/span>In the right dropdown, select \u201cKeyUp.\u201d<span>&nbsp; <\/span>A handler will be inserted for the KeyUp event, into which you could add this code:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> <span>Sub<\/span> EuchreTable_KeyUp(<span>ByVal<\/span> sender <span>As<\/span> <span>Object<\/span>, _<\/span><\/p>\n<p class=\"MsoNormal\"><span>ByVal<\/span><span> e <span>As<\/span> System.Windows.Forms.KeyEventArgs) <span>Handles<\/span> <span>Me<\/span>.KeyUp<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>If<\/span> e.KeyCode = Keys.F2 <span>Then<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>NewGame()<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>If<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Sub<\/span><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">That\u2019s not as good as using the ShortcutKeys property, though, because it will also accept Alt+F1, Ctrl+F1, etc, and you&#8217;d have to add more logic to check for these keys.<span>&nbsp; <\/span>However, it is useful to know how to add arbitrary event handlers to a form, which is why I mention it at all.)<\/font><\/p>\n<h2><span><font size=\"4\"><font color=\"#4f81bd\"><font face=\"Cambria\">Are we there yet?<\/font><\/font><\/font><\/span><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Almost!<span>&nbsp; <\/span>There are a couple of little clean-up things we need to do first that I thought I\u2019d mention:<\/font><\/p>\n<h3><span><font size=\"3\"><font color=\"#4f81bd\"><font face=\"Cambria\">Tab stops<\/font><\/font><\/font><\/span><\/h3>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">Many people use keystrokes to navigate around a form (instead of the mouse). To support this, we need to make sure that the tab order makes sense.<span>&nbsp; <\/span>For the Euchre game, we\u2019re mostly concerned about the options dialog and the bidding dialogs, to make sure that tabbing moves the selection appropriately.<span>&nbsp; <\/span>(Ideally, I should do this for the cards themselves, to make them selectable by the keyboard, but I\u2019ll leave that as an exercise for the reader. <\/font><span><span>J<\/span><\/span><font face=\"Calibri\">)<span>&nbsp; <\/span><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">To fix the tab order for any form, just choose \u201cTab Order\u201d from the View menu.<span>&nbsp; <\/span>The current order will be shown; just click controls in the order in which you wish tabbing to occur, and then choose \u201cTab Order\u201d again when you\u2019re done.<span>&nbsp; <\/span>You should note that you can nest tabbing orders next within groups of objects, so that (for example) you don\u2019t tab through all of the radio buttons in a group \u2013 the user then tab to the active one and then use arrow keys to select.<span>&nbsp; <\/span>The form editor will do this setup for you automatically when you\u2019re selecting the tab order \u2013 it understands that group boxes contain things and that radio buttons are special.<span>&nbsp; <\/span>I\u2019ve attached a picture of the tab order for the Euchre options dialog to this post so you can see what I mean.<\/font><\/p>\n<p class=\"MsoNormal\"><span><\/span><\/p>\n<h3><span><font size=\"3\"><font color=\"#4f81bd\"><font face=\"Cambria\">Application icons<\/font><\/font><\/font><\/span><\/h3>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">Of course, you will want an icon for an application.<span>&nbsp; <\/span>Visual Studio has a built-in icon editor, and you can get to it by bringing up the resource manager and either adding a new icon (via Add Resource<\/font><span><span>\u00e0<\/span><\/span><font face=\"Calibri\">Add New Icon) or simply adding an existing *.ico file via Add Resource<\/font><span><span>\u00e0<\/span><\/span><font face=\"Calibri\">Add Existing File, which will copy it into your project folder.<span>&nbsp; (Actually, if you already have an existing icon file to be used with a form or application, you need not add it to the RM for reasons that will become apparent below.)&nbsp; <\/span>I won\u2019t attempt to describe the use of the icon editor to you in this post, as it&#8217;s not radically different from any other drawing program and many of you are already familiar with it anyway.<span>&nbsp; <\/span>What\u2019s more important is *how* you use the resulting icon.<span>&nbsp; <\/span>What many people don\u2019t realize is that each form has its own icon property, plus the application has an icon property as well, and these all need to be set to your icon(s) or else you\u2019ll get the default Windows icon for them.<\/font><\/font><\/p>\n<p class=\"MsoListParagraphCxSpFirst\"><span><span><font face=\"Calibri\" size=\"3\">&#8211;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">To set the application\u2019s icon:<span>&nbsp; <\/span>Bring up the project properties, click the Application tab, select \u201cBrowse\u2026\u201d on the Icon field and point to your icon\u2019s file (which will have been copied into the project\u2019s folder).<span>&nbsp; <\/span>This icon is what people will see attached to the EXE.<\/font><\/p>\n<p class=\"MsoListParagraphCxSpLast\"><span><span><font face=\"Calibri\" size=\"3\">&#8211;<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font face=\"Calibri\" size=\"3\">To set a form\u2019s icon, open the form and click the \u201c\u2026\u201d button in the Icon property in the grid.<span>&nbsp; <\/span>Again, browse to the appropriate file.<span>&nbsp; <\/span>This is the icon that people will see in the upper-left corner of the form.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Note that both of these require&nbsp;you to browse to a file rather than use the resource, even&nbsp;though the resource may already be in the resource manager &#8212; this is an exception to the rule.&nbsp; (The icons you point to get copied to separate resource managers which belong directly to the owning object &#8212; so don&#8217;t worry, you won&#8217;t be required to deploy a stand-along icon file!) <\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">I use one 32&#215;32 color icon in my application; you should probably have a 16&#215;16 color icon as well, since that\u2019s what the form is going to show.<span>&nbsp; <\/span>Windows does a pretty good job squishing a 32&#215;32 icon into a 16&#215;16 space, but you might not want to leave it to chance.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">So, I\u2019ve covered all of the points I wanted to touch on regarding the actual coding of the game.<span>&nbsp; <\/span>Next time, I\u2019ll discuss deployment and will then post the final code.&nbsp; Talk to you then!<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">&#8211;Matt&#8211;*<\/font><\/p>\n<p><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Components.PostAttachments\/00\/01\/93\/98\/19\/EuchrePost8picture.zip\">EuchrePost8picture.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Coding a Euchre Game, Part 8:&nbsp; Remember Me, Show Me, Help Me We\u2019re getting close to wrapping up this series.&nbsp; In this post, I want to cover several \u201cclean up\u201d topics, and then in the following post, I\u2019ll talk about deployment and will attach the entire codebase for your perusal. Settings You\u2019ll note, from earlier [&hellip;]<\/p>\n","protected":false},"author":258,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[22,195],"tags":[101,165],"class_list":["post-6423","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-matt-gertz","category-visual-basic","tag-matt-gertz","tag-vb2005"],"acf":[],"blog_post_summary":"<p>Coding a Euchre Game, Part 8:&nbsp; Remember Me, Show Me, Help Me We\u2019re getting close to wrapping up this series.&nbsp; In this post, I want to cover several \u201cclean up\u201d topics, and then in the following post, I\u2019ll talk about deployment and will attach the entire codebase for your perusal. Settings You\u2019ll note, from earlier [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/6423","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/258"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=6423"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/6423\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=6423"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=6423"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=6423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}