Table of Contents

Next Page

Microsoft Visual C++ 2005 Express Edition Programming for the Absolute Beginner
Microsoft Visual C++ 2005 Express Edition Programming for the Absolute Beginner
byAaron MillerandJerry Lee Ford, Jr.
Course Technology 2006 (408 pages)
ISBN:159200816X

Written in a straight-forward style, using a games-based approach that makes learning beginning-level programming fun and easy, this book focuses on teaching first time programmers how to program using Visual C++ 2005 Express Edition as a foundation.

Table of Contents
 | Microsoft Visual C++ 2005 Express Edition Programming for the Absolute Beginner
 | Introduction
 | Chapter 1 | - | An Introduction to Visual C++ 2005 Express
 | Chapter 2 | - | Navigating the Visual C++ 2005 Express Edition Environment
 | Chapter 3 | - | Creating an Application Interface
 | Chapter 4 | - | Working with Menus and Toolbars
 | Chapter 5 | - | Storing and Retrieving Data in Memory
 | Chapter 6 | - | Applying Conditional Logic
 | Chapter 7 | - | Processing Lots of Data with Loops
 | Chapter 8 | - | Enhancing Code Structure and Organization
 | Chapter 9 | - | Getting Comfortable with Object-Oriented Programming
 | Chapter 10 | - | Integrating Graphics and Audio
 | Chapter 11 | - | Debugging Visual C++ Applications
 | Appendix A | - | What's on the Companion Web Site?
 | Appendix B | - | What's Next?
 | Index
 | List of Figures
 | List of Tables
 | List of In The Real Worlds

Next Page


Back Cover

Previous Page
Next Page

Back Cover

Microsoft Visual C++ 2005 Express Edition Programming for the Absolute Beginner focuses on teaching first time programmers how to program using Visual C++ 2005 Express Edition as a foundation language. Written for the entry-level user, the book assumes no prior programming or scripting experience. Whether you are a new or experienced C++ developer, this book delivers the tools and libraries you need to write a variety of programs. Written in a straight-forward style, using a games-based approach that makes learning beginning-level programming fun and easy, Microsoft Visual C++ 2005 Express Edition Programming for the Absolute Beginner is the perfect introductory programming book.

About the Authors

Aaron Miller is a software developer with more than 15 years of experience. He has worked in a number of diverse fields, including the computer game industry, healthcare, and embedded systems development. He is passionate about demystifying technology and has long been a mentor to students new to programming.

Jerry Lee Ford, Jr. is an author, educator, and an IT professional with more than 16 years of experience in information technology, including roles as an automation analyst, technical manager, technical support analyst, automation engineer, and security analyst. Jerry has a master's degree in business administration from Virginia Commonwealth University in Richmond, Virginia. He also is the author of 15 other books, including Microsoft Visual Basic 2005 Express Edition Programming for the Absolute Beginner, VBScript Professional Projects, Microsoft Windows Shell Scripting and WSH Administrator's Guide, Learn VBScript in a Weekend, Microsoft Windows Shell Scripting for the Absolute Beginner, Learn JavaScript in a Weekend, and Microsoft Windows XP Professional Administrator's Guide. He has more than five years of experience as an adjunct instructor teaching networking courses in information technology.

Previous Page


Microsoft Visual C++ 2005 Express Edition Programming for the Absolute Beginner

Aaron Miller with
Jerry Lee Ford, Jr.
Image from book
Thomson Course Technology PTR, a division of Thomson Course Technology
25 Thomson Place Boston, MA 02210 .
http://www.courseptr.com

© 2006 by Thomson Course Technology PTR.

All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system without written permission from Thomson Course Technology PTR, except for the inclusion of brief quotations in a review.

The Thomson Course Technology PTR logo and related trade dress are trademarks of Thomson Course Technology and may not be used without written permission.

Microsoft and Visual Basic are registered trademarks of Microsoft Corporation in the United States and/or other countries.

All other trademarks are the property of their respective owners.

Important: Thomson Course Technology PTR cannot provide software support. Please contact the appropriate software manufacturer's technical support line or Web site for assistance.

Thomson Course Technology PTR and the authors have attempted throughout this book to distinguish proprietary trademarks from descriptive terms by following the capitalization style used by the manufacturer.

Information contained in this book has been obtained by Thomson Course Technology PTR from sources believed to be reliable. However, because of the possibility of human or mechanical error by our sources, Thomson Course Technology PTR, or others, the Publisher does not guarantee the accuracy, adequacy, or completeness of any information and is not responsible for any errors or omissions or the results obtained from use of such information. Readers should be particularly aware of the fact that the Internet is an ever-changing entity. Some facts may have changed since this book went to press.

Educational facilities, companies, and organizations interested in multiple copies or licensing of this book should contact the publisher for quantity discount information. Training manuals, CD-ROMs, and portions of this book are also available individually or can be tailored for specific needs.

ISBN: 1-59200-816-x

Library of Congress Catalog Card Number: 2005924928

Printed in the United States of America

06 07 08 09 10 PH 10 9 8 7 6 5 4 3 2 1

Publisher and General Manager, Thomson Course Technology PTR: Stacy L. Hiquet

Associate Director of Marketing: Sarah O'Donnell

Manager of Editorial Services: Heather Talbot

Marketing Manager: Heather Hurley

Acquisitions Editor: Mitzi Koontz

Marketing Coordinator: Jordan Casey

Project/Copy Editor: Karen A. Gill

Technical Reviewer: Jonathan Harbour

PTR Editorial Services Coordinator: Elizabeth Furbish

Interior Layout Tech: Shawn Morningstar

Cover Designer: Mike Tanamachi

Indexer: Kelly Talbot

Proofreader: Gene Redding

Dedication

To my good friends Melissa and Jerusha, angels of encouragement.
—Aaron Miller

Acknowledgments

This book would not have been possible without the hard work of many people. I'd especially like to thank Dave Astle, Ernest Pazera, and the many fantastic members of GameDev.net for their help and advice. I'd also like to thank this book's copy editor, Karen Gill, and technical editor, Jonathan Harbour, for helping me to keep everything on track.

—Aaron Miller

About the Author

Aaron Miller is a software developer with more than 15 years of experience. He has worked in a number of diverse fields, including the computer game industry, healthcare, and embedded systems development. He is passionate about demystifying technology and has long been a mentor to students new to programming.

Jerry Lee Ford, Jr. is an author, educator, and an IT professional with more than 16 years of experience in information technology, including roles as an automation analyst, technical manager, technical support analyst, automation engineer, and security analyst. Jerry has a master's degree in business administration from Virginia Commonwealth University in Richmond, Virginia. He also is the author of 15 other books, including Microsoft Visual Basic 2005 Express Edition Programming for the Absolute Beginner, VBScript Professional Projects, Microsoft Windows Shell Scripting and WSH Administrator's Guide, Learn VBScript in a Weekend, Microsoft Windows Shell Scripting for the Absolute Beginner, Learn JavaScript in a Weekend, and Microsoft Windows XP Professional Administrator's Guide. He has more than five years of experience as an adjunct instructor teaching networking courses in information technology. Jerry lives in Richmond, Virginia, with his wife, Mary, and their children, William, Alexander, and Molly.


Introduction

Whether you're a student, a game mod maker, or just someone who is interested in learning to program, Microsoft Visual C++ 2005 Express Edition is a powerful way to introduce yourself to the C++ programming language. The Express Edition comes complete with the tools that make creating, managing, and maintaining your projects simple and easy. It helps you to become a more effective programmer by allowing you to put projects together quickly, focus only on the important details, and get the hints and help you need when you need them.

Microsoft Visual C++ 2005 Express Edition is part of the Microsoft Visual Studio 2005 line of products. This powerful series includes Visual Basic, Visual C#, and Visual J#. The Microsoft Visual Studio 2005 line has become the top choice of today's professional programmer, garnering awards from leading industry magazines such as PC Week and PC Magazine. You can find versions of each product being used throughout the software engineering world. By mastering the Express Edition toolset, you give yourself a competitive edge when it comes to learning one of the latest technologies available to the programming industry.

WHY VISUAL C++ 2005 EXPRESS EDITION?

With so many products to choose from, it might be hard to decide which best fits your needs. Each language has its strengths. But if you are looking for the most powerful among them, Microsoft Visual C++ 2005 Express Edition is it.

The Express Edition allows you to employ the .NET Framework, a new coding technology that is growing in popularity. The .NET Framework facilitates the construction of applications that can be run on Windows, smart devices like the PocketPC, and the Web. With it, you can write code modules in Visual C++ and use them in Visual Basic, Visual C#, or Visual J#. The .NET Framework features many new enhancements to make your programs more robust and secure.

Microsoft has designed this new version of Visual C++ to be the most flexible and extensible of its languages. It is aimed at writing robust Windows and server-side applications. Unlike the other .NET languages, Visual C++ lets you directly access the hardware that your machine is running on, enabling you to maximize its full capabilities.

Visual C++ 2005 Express Edition has many features and capabilities, some of which are tricky to master. For this reason, Microsoft has put a strong effort into making the product easier to use. The core code library has been redesigned, allowing you to build your programs on a stronger foundation that is easier to read and write. Your own code will now be more streamlined thanks to context-sensitive technology that does a better job of understanding what you type. Improvements in online help, project management, and the ever-popular IntelliSense reference technology place a wealth of information at your fingertips.

New features such as WinForms allow you to rapidly create a program graphically. You can drag and drop buttons, menus, and other interface elements onto a page to quickly get a program up and working. Then you can have the editor generate code for you with a few mouse clicks.


WHO SHOULD READ THIS BOOK?

This book has been designed with several audiences in mind:

  • Those who want to program but have no experience doing so

  • Those who know C++ but not .NET (there's a world of difference)

  • Those who want to develop applications quickly

  • Those who want to become more comfortable with .NET, possibly branching out to other languages such as C#

No Experience Necessary

This book assumes no prior knowledge of C++. It is an excellent starting place if you're interested in learning the basics of the language and how to build your own applications. Each chapter starts with a broad overview to ground you in the concepts being discussed. Then it moves on to a step-by-step approach, explaining precisely what you need to do to get every chapter program up and running. By the end, you will be able to build your own programs from scratch and be well on your way to becoming a competent C++ programmer.

C++ Programmers New to .NET

If you're experienced with programming in C++, be prepared for some changes. Writing code meant solely to run in the Windows environment is quite different from writing code to conform to the .NET Framework's requirements. Even simple commands such as cout and cin have become obsolete as Microsoft has focused on a system of creating code that works reliably on a diverse range of platforms in addition to the Web.

This book reacquaints you with C++ from the .NET perspective. It starts simply, concentrates on the basics of the .NET Framework, and gives examples in each chapter that reinforce the new paradigm. By the end of this book, C++ programmers will have a good grasp of the ground-level basics and the confidence to begin deepening their exploration of the .NET Framework using C++.

Developing Applications Quickly

Visual C++ 2005 Express Edition has been designed with productivity in mind. The improved interface features several optimizations that make the tools you need easier to find and use. The all-new inclusion of WinForms and several interface elements give you the power to rapidly design and lay out a potential application to see how it will look and feel. And when you're ready to build a fully functional program, the automated code generation features make it easy not only to drop in functionality right where you need it, but also to test and improve your code each step of the way. With Microsoft Visual C++ 2005 Express Edition, you'll have programs up and working in minutes.

Branching Out from .NET

The core concept behind the entire Microsoft Visual Studio 2005 product line is cross compatibility between each of its languages. The interface is uniform across the entire product line. Because of this, should you decide to expand your programming knowledge to cover Visual Basic, Visual C#, or Visual J#, you will be branching out into using a product whose look and feel you will already be familiar with. Almost all the productivity-enhancing and help features you will come to rely on in the Visual C++ 2005 Express Edition will be readily available to you in these other Visual Studio products.

Learning Visual C++ 2005 Express Edition offers further advantages. It offers you an excellent springboard if you want to dive into the emerging realm of C# development. By the time you finish reading this book, you should be comfortable with many of the same language structures and methodologies that exist in C#. This advantage allows you to concentrate on the differences, thus accelerating the process of mastering both languages.


WHAT YOU NEED TO BEGIN

You need to download Visual C++ 2005 Express Edition, available at the time of this writing at http://lab.msdn.microsoft.com/express/visualc/. Alternatively, you can order a CD online from http://lab.msdn.microsoft.com/vs2005/get/order/. In addition, you need the following:

  • PC with a speed of at least 600MHz (1GHz recommended)

  • Windows XP, Windows 2000, or Windows 2003 Server

  • At least 128MB of Random Access Memory (RAM) (256MB recommended)

  • At least 1.3GB of hard disk space

  • A display capable of 800×600 256 colors (1024×768 high color, 16-bit recommended)

  • Microsoft mouse or compatible pointing device

A CD or DVD drive is required.


SPECIAL FEATURES OF THIS BOOK

As you learn the language, my goal is to make the process fun, fast, and interesting. Every chapter includes games for the sample programs. At the end of each chapter are challenges to help you hone your skills. This book also includes the following special elements:

Hint

This is where I'll put hints or advice I've learned that can help make your programs lean and mean and Visual C++ easier to use.
Trap

Traps cover common mistakes and problem areas, particularly those that snare new programmers.
Trick

These are shortcuts that I've found, including how to go beyond the rules after you've mastered them.
Image from book
IN THE REAL WORLD

In these sidebars, I share with you many of the experiences I've had while learning C++ and using it in the world of game and business application programming.

Image from book


Chapter 1: An Introduction to Visual C++ 2005 Express

OVERVIEW

With the release of Visual C++ 2005 Express Edition, Microsoft has turned its attention to the needs of a new generation of programmers. The changes that Microsoft has made respond to the growing need of programmers to quickly develop applications that are robust and able to work on multiple platforms. With the seamless integration of the .NET Framework, Visual C++ developers now enjoy the ability to create applications that can run under the Windows operating system, as the core of a server-side applet, or on many other platforms.

This chapter begins your process of becoming a C++ programmer by covering information that orients you to the C++ language, Visual C++, and the .NET Framework. When you're finished with this chapter, you'll be ready to dive right in and create your first program. By developing this application, you'll gain a sense of the steps required to build a program and some of the strengths of developing using the Visual C++ toolset.

In this chapter, you learn the following:

  • What Visual C++ 2005 Express is and what it can do

  • What .NET is and how it works with Visual C++ 2005 Express

  • What Visual Studio is and how Visual C++ fits into it

  • What the five basic steps are to building a Visual C++ application


PROJECT PREVIEW: THE JOKE MACHINE

In this chapter, as with each chapter to follow, you learn how to create a Visual C++ application. Each chapter provides a simple, fun way to learn the language, introduce you to the various tools you need to create each program, and give you a foundation on which to expand your knowledge of C++ and the .NET Framework.

The application that you learn to create in this chapter is a simple program called the Joke Machine. Its purpose is to display to the user two jokes. It is a fully functional Windows application, complete with buttons for closing and minimizing the program, buttons associated with each of the two jokes, and a text box used for displaying the jokes. Although the program is easy to develop, it illustrates the powerful techniques for designing and programming Windows applications.

When you first launch the Joke Machine, it appears in a window, as shown in Figure 1.1.

Image from book
Figure 1.1: The starting screen of the Joke Machine.

Figure 1.2 shows the result of causing the Joke Machine to tell the first joke.

Image from book
Figure 1.2: Clicking the first button triggers the first joke.

Figure 1.3 displays the result of clicking the second joke.

Image from book
Figure 1.3: Clicking the second button triggers the second joke.


A FEW OPENING WORDS

The process of learning something new can be challenging, but it can also be fun and deeply rewarding. This chapter provides a broad overview that will enable you to advance to later chapters.

This chapter starts with a quick overview of Visual C++ and the core concepts that go into making a program. Next, it offers a quick dash of history. The chapter then covers some of the capabilities of Visual C++ 2005 Express and where it fits into the Microsoft family of Visual Studio products. After that, it moves into foundational information about .NET. Finally, you experience creating your first Windows application.

As you read this book, don't worry about trying to understand each detail. You might be using commands before you understand what they mean. This might be somewhat confusing at first, but if you focus on the big picture, you'll progress to understanding the details in no time.

Each program you design and build gives you a better understanding of the tools necessary to create Windows applications. You also gain a solid understanding of the code behind these applications and the principles that make up the C++ language.


A QUICK OVERVIEW OF VISUAL C++ 2005 EXPRESS

The visual in Visual C++ means that you can see and interact with all the tools and code necessary for making an application. It has also come to mean the process by which you create the visual portion of an application that your users will see, also known as the Graphical User Interface (GUI). Within the name, C++ refers to the language that you use to build your applications: the C++ programming language.

Hint

A Graphical User Interface (GUI) is the part of the application that the user sees and can interact with using the mouse.

Visual C++ is a development tool based on the C++ programming language, used to build applications for Windows and the Web. It is used to turn your projects, which begin life as no more than text and graphics files, into complete standalone applications. You can then run these applications without assistance, just like any other tool, game, or application you have used.

You create applications by compiling code. You then translate this code into a format that your computer can read. When you're ready to run a program, you only need to locate it on your computer system and click its icon.

Hint

Compiling is the process of translating the English-like code statements that make up an application into a format that a computer can understand and execute.

The C++ programming language has earned a reputation for being one of the most powerful and flexible languages available. Microsoft Visual C++ gained immediate popularity by offering these advantages to programmers in a set of consolidated tools that were easy to use and understand. As a result, Visual C++ quickly set a standard as one of the most widely used compilers among professionals the world over. Both large and small businesses use it to create Windows and server-side Web components, and game companies use it to create the latest cutting-edge entertainment software.

Visual C++ has gained widespread popularity for a number of reasons. Three of the most important reasons include its support of the following:

  • Drag-and-drop GUI design

  • Rapid application development

  • Object-oriented design and development

Graphical User Interface Development

It is through your program's GUI that your users can interact with and control your program. It is the face of your application. The way you design your GUI affects how easily your users find the program they want, and this impacts how happy they are with the program overall.

One of the best things about using Visual C++ 2005 Express is how quickly and efficiently you can create a professional-looking GUI. When you start a new project, Visual C++ gives you a new blank window to work with. Next to this window is a series of readily usable interface components, such as check boxes, text boxes, menus, and buttons. You can add them to your program by clicking on the element you want and dragging it on top of the window. Visual C++ then lets you position and layer them as needed. The result is a working application that you can create in minutes.

Rapid Application Development

Visual C++ is a Rapid Application Development (RAD) tool. RAD refers to the process of being able to quickly get the skeleton of a program up and running. By dragging and dropping interface components onto a window, you can quickly allow users to preview the way your program will look and feel. Because your users can give you feedback early, RAD can save you work. Rather than spending many long hours writing and testing your program, Visual C++'s RAD capabilities allow you to respond to user expectations early and deliver a product that is more suited to their liking.

Hint

Rapid Application Development (RAD) is a process whereby programmers quickly create a mockup of an application's GUI for initial review by the users for whom the application is intended to demonstrate how the application will ultimately look and operate.

Object-Oriented Programming

One of great strengths of the C++ language is that it is an Object-Oriented Programming (OOP) language. OOP is a way of designing and building applications out of small, organized components. Using it, you can create an application whose parts are well tested, self-contained, and able to be used in other applications. These components can even be extended in new and different ways, saving you time in writing new code.

Whereas the GUI relates to what you see, OOP involves how you build your program and how all of its parts interact. From the perspective of OOP, you build a program out of classes. Classes essentially act as independent units of computer code that can store, process, and provide access to information. When the program runs, the class becomes an object, and the information given to it can then be used to control how the object works. In OOP, the interaction of multiple objects is what gives your program functionality.

In Visual C++, for example, when you drag a button onto a window, the button is a self-contained component. It has everything it needs to draw itself, including its size and the font used on its label. When you press the button, it knows how to communicate with the rest of your program so that it can behave properly.

The great benefit of OOP lies in the fact that you can use powerful objects without having to concern yourself with the details of how the code is used to write the functions. Well-written classes simply drop in to a program. OOP allows you to draw on the expertise of other programmers, such as those at Microsoft when you use the buttons and other interface tools they provide to build your own program. Later, as you become a more competent programmer, you can provide classes for other programmers to use.

Hint

Object-Oriented Programming (OOP) is a software design methodology involving the creation of self-contained modules that store all the code and information necessary to carry out a specific task, in addition to the functionality needed to interact with that module and its information.

A Little Visual C++ History

Visual C++ is built upon the C++ programming language. The C++ language is an outgrowth of an earlier language called C, which itself is older than some programmers writing it! (It was invented in the 1970s.) The C programming language was a powerful language because it more closely modeled how computers worked internally than many other languages at the time. This enabled programmers to gain an unprecedented level of control over how the computer used and stored information, which in turn allowed them to write programs that were fast and flexible. Throughout the 1970s and 1980s, C became extremely popular. It's still widely used today.

One major problem that C had was that many programmers found it easy to write code that caused them headaches. Because the language was so powerful, programmers could create mistakes that were difficult to find. Some mistakes could even be as damaging as the program was powerful. Even when programmers perfected a module, they found it difficult to use that code in other programs.

With the invention of the C++ language in the mid-1980s, the designers sought to provide a way of keeping C's power but integrating OOP principles. The result was a language that improved on many of C's strongest features. C++ has more capabilities, matches the power and speed of C, and makes up for many of the original language's shortcomings.

The initial tools for developing applications in C and C++ were difficult to use. Many required that a programmer understand cryptic files or programs with obscure command-line interfaces. But as the process of programming became more complex and applications became larger, the tools for developing applications began to become more centralized and unified.

Visual C++ represents Microsoft's version of a toolset that brings all the programs and resources that you need to build applications under one roof. It also includes extensions and enhancements that improve the C++ programming language. Initially, Visual C++ was targeted at creating Windows applications. The compiler included numerous optimizations to the Visual C++ compiler targeted at creating both client- and server-side business applications. But as Internet development gained monumental popularity, Microsoft increasingly saw the need to provide tools that would allow developers to create Web-based server and Internet browser applications.

As time went by, strategists at Microsoft began to envision tools that would serve development for what they termed the Next Generation Internet. This new Internet would be made up of many different types of devices, including handheld PDAs and smart devices, not just full-fledged PC servers and client systems, as had been most popular in the past. In 2000, Microsoft released the .NET Framework to serve developers in meeting this new opportunity.

The first attempts at integrating .NET into Visual C++ produced many difficulties for established Visual C++ programmers. It also was challenging for new programmers to understand. Many had trouble with the changes they had to make to their coding style and philosophy to accommodate .NET. But despite these problems, the power that .NET provided was compelling. Businesses reported strong increases in productivity, some managing to produce in months what had taken a year or more.

With improvements to the .NET Framework and the Visual C++ compiler, the release of Visual C++ 2005 Express Edition marks a more successful and simpler integration that brings Visual C++ up to speed with its contemporaries, Visual Basic, Visual C#, and Visual J#. Microsoft has adopted a new emphasis on giving programmers the ability to focus on the language that they are most efficient in. This envisions the .NET Framework as serving as the connecting glue that allows programmers to maximize the strengths of their favorite language to create programs that interoperate with each other. The result is faster development time of larger systems that are greater than the sum of their individual parts.

Trap

To run an application created using Visual C++ .NET, a computer must have the .NET Framework installed on it. Microsoft has upgraded the .NET Framework several times since its introduction. Visual C++ .NET 2002 was designed to work with .NET Framework 1.0. Visual C++ .NET 2003 was designed to work with .NET Framework 1.1, and Visual C++ .NET 2005 works with .NET Framework 2.0. Although an application created using Visual C++ .NET 2002 runs on any computer that has a version of .NET installed on it, an application written using Visual C++ .NET 2003 requires that .NET 1.1 or 2.0 is installed. In similar fashion, an application written using Visual C++ .NET 2005 requires .NET 2.0.
Image from book
IN THE REAL WORLD

The emphasis on the .NET Framework has caused Microsoft to offer a programming library with .NET that somewhat verges away from the widely accepted C++ standard, known as the ANSI/ISO Standard, drafted by the American National Standards Institute. This means that C++ code written in the past might need to be updated if a programmer wants it to function with the .NET Framework. Microsoft and several other companies have been working with the European Computer Manufacturer's Association (ECMA) to develop a new standard for C++ code intended for use with .NET. Programmers can also still write and compile ANSI/ISO Standard C++ code without the .NET Framework.

Image from book


INTRODUCING VISUAL C++ 2005 EXPRESS

Visual C++ 2005 Express Edition has been targeted toward the first-time programmer. Microsoft realizes that a great many hobbyist and programming enthusiasts have not had access to this tool due to pricing. That's why its main purpose is to provide a simplified and streamlined introduction to Windows application development. It provides complete support for the Microsoft .NET Framework and can be used to create applications for Windows and the Web. Because of the redesigned interface and emphasis on creating a tool that is accessible to a new generation of budding professionals, Visual C++ is relatively easy to get started with and can be used to create world-class desktop applications.

If you have not done so yet, now would be a good time to install Visual C++ 2005 Express. You can download a 30-day trial version by connecting to the Microsoft Web page at http://msdn.microsoft.com/vstudio/express/visualc and selecting Download. After you've installed Visual C++, the first time you start it, you see the screen shown in Figure 1.4.

Image from book
Figure 1.4: Visual C++ 2005 Express Edition showing the Start Page.

As you can see, Visual C++ 2005 Express Edition has a standard Windows menu and a default toolbar at the top of its Integrated Development Environment (IDE). When you first launch the program, you see displayed in the middle of the IDE the Start Page. This page is divided into three sections. The Recent Projects section contains links that can quickly load previous projects you've created. The Getting Started section has links that provide you with the material you need in getting ready to start writing programs. The MSDN: Visual Studio 2005 section keeps you informed of the latest happenings in the community and provides a quick and easy way to access articles and information regarding Visual Studio and Visual C++. And if you have a comment or find an error in Visual C++, the Visual C++ 2005 Express Headlines section allows you to give feedback.

Image from book
IN THE REAL WORLD

A large community already supports development of Visual C++ applications, including Microsoft Visual C++ 2005 Express Edition. If you're interested in making games and projects just for fun, Microsoft has created a Web site specifically for you where you can get the latest tips and tricks: http://msdn.microsoft.com/coding4fun/.

Image from book

What can Visual C++ 2005 Express Do?

Visual C++ 2005 Express Edition has been created to support Windows and Web application development. Microsoft designed it to be the entry point for both new and experienced programmers into accessing the full range of capabilities of Visual Studio. With it, programmers have a fully functional, professional-grade compiler that can create such applications as these:

  • Windows games, including those using the DirectX graphics library

  • Windows desktop applications

  • Report and text file generators

  • Tools to support game development

  • File interaction and management systems

  • Database access and management software

Microsoft has placed a heavy emphasis on creating a simplified development experience. Although you might not immediately understand how to create all of these types of programs, one of the great strengths of the .NET Framework is that it takes care of many of the details for doing so automatically. Working with text and graphics or creating an application that supports printing or networking simply involves writing code that accesses the correct .NET library functionality.

What can't Visual C++ 2005 Express Do?

Although you can use Visual C++ to develop applications that run on the Web and serve as the high-end power at the heart of Web server components, it is not a Web development tool per se. ASP.NET forms are not supported. If you want to create responsive, dynamically generated Web content, Microsoft recommends that you use Visual Web Developer 2005 Express Edition.

Programmers who are familiar with C++ and want to bring existing code into Visual C++ should also know that it does not support MFC and ATL technologies. Microsoft does offer support for these technologies in the Visual C++ Standard and Professional Editions, however.

Finally, if you want to develop native Win32 applications or employ DirectX, you must download a separate Software Development Kit (SDK). After you've installed that, you can link to these libraries and develop native Windows and graphical applications or export existing code.


OTHER VISUAL STUDIO 2005 EXPRESS PROGRAMMING LANGUAGES

Visual C++ 2005 Express is just one of several Visual Studio Express development options available. Following are some of the others:

  • Visual Basic 2005 Express. This product offers Windows developers a means of building applications quickly using the easy-to-understand Visual Basic programming language. It is especially aimed at first-time programmers who want to get programs up and running quickly without getting bogged down in the technical details of their computer system.

  • Visual C# 2005 Express. This product offers Windows developers a language that leverages some of the strengths and concepts of C, C++, and Java but is easier to use. It is also aimed at first-time and casual programmers, hobbyists, and students.

  • Visual J# Express. This product, offered to support Java development, allows programmers to create applications for Windows and the Web. Like each of the Express Editions, it streamlines the development process to make program writing simpler.

Image from book
IN THE REAL WORLD

In addition to Visual C++ 2005 Express Edition, Microsoft offers both a Standard and Professional Edition. The Standard Edition is targeted at individual software professionals or small businesses and includes a wider range of development tools than the Express Edition. The Professional Edition is intended for building larger scale, mission-critical business applications and expands on the Standard Edition's options by adding a more powerful compiler and solutions for SQL development. These higher-end products also feature a wider range of tools for building Web applications.

Companies that develop applications using Visual C++ often purchase it as part of a package deal that Microsoft calls Visual Studio. When you purchase the applications this way, you get access not only to Visual C++ but also to other languages and tools that make up Visual Studio, including Visual Basic and Visual C#. Microsoft offers several tiers of Visual Studio. Unfortunately, the products can quickly become quite expensive. At the lower end, Visual Studio .NET Professional Edition is available for roughly $500. It supports Windows, Web, and mobile device development using any of Its supported programming languages, as you might expect. Next in the series is Visual Studio .NET Enterprise Developer, which retails for more than $1,000. This package offers developers an assortment of team-oriented development tools and Microsoft technical support solutions. Finally, at the upper end of the range lies Visual Studio .NET Enterprise Architect, which runs somewhere around $2,500.

Image from book

Visual Basic 2005 Express

Visual Basic is a programming language geared toward rapid application development. It is based on the BASIC (Beginner's All-Purpose Symbolic Instruction Code) language, which is popular for its easy-to-read, English-like statements. Visual Basic has widespread support among business professionals and hobbyists alike, and versions of it are built into Microsoft Word and Excel to support database development and automation.

Visual C# 2005 Express

Visual C# is a relatively new programming language that Microsoft created based on a combination of C, C++, and Java. Microsoft first introduced Visual C# with the initial release of Visual Studio. Although a little more difficult to learn than Visual Basic, C# provides former C, C++, and Java developers with a program development platform that is easy to learn and leverages their existing program development skills.

Visual J# 2005 Express

Visual J# is an enhanced version of Microsoft Visual J++ 6.0, which has been updated to work with the .NET Framework. Although strongly tied to the Java programming language, Microsoft has added numerous extensions to the language. As a result, Visual J# 2005 Express is not compatible with Java, so you won't be able to run programs developed with Visual J# using Sun's Java Virtual Machine. However, Visual J# provides individuals with previous Java programming experience with a great language for Windows application development using .NET.

Image from book
IN THE REAL WORLD

Visual C++ is so powerful that Microsoft relies heavily on it to develop many of its tools and applications. In fact, along with a little help from another language known as Assembly, which supports precise, low-level control over computer systems, Microsoft developed every one of the Visual Studio products using Visual C++!

Image from book


THE MICROSOFT .NET FRAMEWORK

Microsoft envisions a Next Generation Internet made up of many different kinds of devices. It sees users not only communicating and sharing data using PCs and PDAs, but also with mobile devices such as cell phones and set-top boxes such as digital movie recorders. But standing in the way of this interlinking of devices are many challenges, chief among them a common way to develop applications that work well with each other.

Microsoft has developed the .NET Framework as an answer to this challenge. Whether Express or full-featured versions, each of the various Visual Studio programming languages is designed to work with the Microsoft .NET Framework. Microsoft hopes that the .NET Framework provides a seamless standard for interoperability, the capability of applications or libraries that are written in different languages to work well with each other regardless of the platform.

Before .NET

Before the introduction of .NET, developing and releasing a product often involved dealing with a conceptual alphabet soup. Microsoft created and encouraged the use of several versions of the Component Object Model (COM), including COM+ and Distributed Component Object Model (DCOM). Using COM, Windows programmers were able to write programs more quickly by relying on a consistent and unified group of Windows services and system resources, such as data sharing and networking support. This, in turn, allowed programs to rely on Dynamic Link Libraries (DLLs), or files that a program would link to access the functionality it needed.

COM, along with Microsoft Foundation Classes (MFC), represented one of Microsoft's first attempts at creating an OOP standard for building Windows applications. MFC provided a way to build modules that utilized basic Windows functionality. COM, in turn, gave programmers the ability to create component libraries made up of code that could be reused by different languages, such as Visual C++ and Visual Basic.

Before the arrival of .NET, distributing a program often meant distributing the DLLs that gave the program the access to services it needed. A game, for instance, might need several DLLs to give it access to high-speed graphics functions. Because DLLs sometimes changed, when programmers were ready to deploy their applications, they would have to consider whether the DLL they were releasing with their product might conflict with a DLL that was already on the user's system. Things would get really complicated if DLLs depended on other DLLs to function.

Unfortunately, with thousands of different software packages and computer configurations to deal with, programmers didn't always get it right. Sometimes the DLLs they installed replaced files that were already on a user's computer with older or incompatible versions of the same files. This often caused other applications on users' computers to mysteriously break. The situation was so common and difficult to deal with that programmers, even those at Microsoft, ultimately began to refer to it as DLL Hell.

Microsoft's solution to DLL Hell was the .NET Framework. The .NET Framework is now responsible for giving Visual Studio programming languages the functionality that they used to get from DLL files. Because DLL files are not needed to develop Windows applications, deployment packages are now a lot smaller. Today, instead of worrying about what version of DLL files users have installed on their computers, programmers need only to make sure that users have the .NET Framework installed.

.NET Components

The .NET Framework is a collection of programming services that support application development and execution on Windows operating systems, the Internet, Tablet PCs, and even mobile devices such as PDAs (using the Compact Framework). The .NET Framework acts as an interface between the operating system and your applications.

Figure 1.5 depicts the .NET Framework's role in the application development process. As you can see, it enables applications to be developed using any combination of .NET-supported programming languages. It is responsible for translating the code created using these programming languages into a format that can be executed on the intended execution platform, whether it is a PC, a Web server, or a PocketPC device.

Image from book
Figure 1.5: The Microsoft .NET Framework is utilized by multiple languages to build applications for several target platforms.

The .NET Framework is made up of two main components:

  • .NET Framework class library

  • Common Language Runtime (CLR)

The .NET Framework class library is composed of an enormous amount of prewritten code that is available to any Visual Studio programming language. The class libraries are used to define objects within applications.

Hint

A class is the actual, self-contained code that comprises an object, such as a menu, a button, or a text box. When you create a new form or add a control to a form when building an application interface, you are adding new objects based on predefined classes stored in the .NET class library.

The .NET class library contains the code required to create forms, buttons, and other Visual Studio controls. For example, to create a new form within a Visual C++ application, call upon a predefined class that already has everything defined within it to create the new form. This saves you from having to write all the underlying low-level code yourself. If you then drag and drop a Button control onto the form, the .NET class library automatically supplies your application with all the underlying code, defining how the button looks and how your application can interact with it.

The CLR

The CLR provides the .NET Framework with a collection of services that facilitate application execution. These services include the following:

  • Debugging

  • Memory management

  • Compiling

  • Security

  • Exception handling

For your Visual C++ applications to run, you must compile them. When you compile your Visual C++ applications, the Visual C++ statements that make up your applications are translated into Microsoft Intermediate Language (MSIL). One of the jobs of the CLR is to convert MSIL code into binary code that the computer understands.

Hint

Compiling is the process of converting the programming statements that make up a given application into a format that the operating system can execute.

After the original source code for the application is converted to MSIL, it does not matter whether it was written in Visual C++, Visual C#, or any other programming language supported by Visual Studio. Because of this, you can mix and match multiple programming languages to create a single application.

Although all this might sound pretty complicated right now, the good news is that you don't need to understand it all to use it. The process of linking your program to the services or functionality it needs, communicating with other languages, or even distributing your program to other platforms occurs automatically. Microsoft Visual C++ 2005 Express Edition takes care of everything you need to create and deploy your applications. So if you find this material a little intimidating right now, don't worry. Just keep the big picture in mind and try to keep moving forward. As you gain comfort and familiarity with the language and concepts, you'll get the experience you need to start making sense of it all.

Hint

If you want to learn more about the features of the .NET Framework, visit http://www.microsoft.com/net.


BACK TO THE JOKE MACHINE

Now that you have a bit of the foundation of Visual C++ out of the way, it's time to move on to programming this chapter's project, the Joke Machine. Through the development of this game, you will learn the basic steps involved in developing a Windows application. As you create your first Visual C++ application, try to develop an intuitive feel for the overall process involved. The details will become clearer as you practice and will be explained thoroughly in the chapters to come.

Designing the Game

The Joke Machine's design is straightforward, involving basic yet fundamental Windows programming techniques. The game begins by displaying its GUI. It then waits for the user to click on a button before displaying a knock-knock joke. The game continues to run, allowing the user to click either of its buttons as many times as desired. Like other Windows applications, you can minimize or maximize the game and continue to run it until you click the Close button in the upper-right corner of the window.

As you will see as you build the Joke Machine, Visual C++ applications are typically created in five steps, as outlined here:

  1. Create a new Visual C++ project.

  2. Create the GUI.

  3. Modify form and control properties.

  4. Add program code.

  5. Test the application's execution.

Each of these steps is demonstrated in detail in the sections that follow.

Step 1: Creating a New Visual C++ Project

The first step to developing any application is to create a project for it. Before you can do this, you need to launch Visual C++ 2005 Express Edition if you have not already done so. Next, create the project by selecting File, New, New Project.

Visual C++ displays the New Project dialog box, as shown in Figure 1.6.

Image from book
Figure 1.6: The New Project dialog box allows you to control the creation of a new project.
Hint

A Visual C++ project stores all the code and form data, such as pictures and text, which make up your Visual C++ application.

The New Project dialog box displays several options available for configuring the type of application you want to create. You can specify the type of project, the template to use, and the file name and location.

The Project Types category allows you to choose whether you will be creating a .NET project, a Win32 application (a Windows program that does not use the .NET Framework), or an empty project that you will build from scratch later. For the purposes of the examples in this book, you will be building .NET projects. Make sure CLR is highlighted in the Project Types section on the left side of the New Project dialog box.

Next to Project Types is a category called Templates. This lists all Visual Studio installed templates that are designed to work with Visual C++. Templates are generic projects that include the settings you need to get your own project up to speed quickly. Because the Joke Machine is a Windows application, you must select the Windows Forms Application.

Hint

A template is a collection of files, property, and Visual C++ compiler settings that Microsoft provides as a starting point for rapidly creating a particular type of Windows application.
Image from book
IN THE REAL WORLD

Visual C++ 2005 Express Edition provides many different project templates. They are all designed to assist developers in getting the settings for Visual C++ and their application configured quickly. The following types of projects are available from the New Project dialog box:

  • Windows Forms Application. Creates an application with a Graphical User Interface that is designed to run on the Windows desktop. The application is built using forms and controls that the Visual C++ development environment provides.

  • Windows Forms Control Library. Creates a module intended to provide custom-designed controls to a Windows application. The behavior and appearance of the control are contained within the module.

  • CLR Console Application. Creates a text-based .NET application that is typically run from the Windows command prompt. This is useful for developing tools or other programs that have little need for user interaction or mouse control.

  • Windows Service. Creates an application that provides additional services to the Windows operating system.

  • ASP.NET Service. Creates an application that provides support for XML-based Web services.

  • CLR Empty Project. Creates a minimal .NET project to which files can be added later. This is for experienced developers.

  • Class Library. Creates a module that is intended to provide functionality to other applications.

  • Win32 Console Application. Creates a native Windows application that does not take advantage of the .NET Framework.

  • Empty Project. Creates a minimal native Windows project to which files can be added later. This is for experienced Win32 developers.

  • Makefile Project. Creates a project that is designed to be built outside the Visual C++ IDE. This is for experienced developers.

These templates save developers time because they reflect the most common settings that developers need. Without templates, simply configuring the compiler might take as long as building a program!

Image from book

The last step of creating a new project involves giving it a name. In the Name field of the New Project dialog box, enter The Joke Machine. When you type this text, Visual C++ mirrors the name in the Solutions field. Whenever you create a new project, you create a new solution by default. Solutions contain projects, just as projects contain the material that makes up your application. Click OK.

Hint

A Visual C++ solution is a container that stores all the projects that make up your Visual C++ applications. In the case of the Joke Machine, the entire application consisted of a single project. More complex applications might be made up of more than one project. You will learn more about projects and solutions in later chapters.
Trick

By default, Visual C++ places new projects in the folder of the current user, under C:\Documents and Settings\Username\My Documents\Visual Studio\Projects. You can change this location if you want. To do so, select Options from the Tools menu. In the Options dialog box that appears, locate the Projects and Solutions section. Under Visual Studio Projects Location, you can type a new file location or choose one by selecting the ellipsis icon next to the directory name.

As you can see, Visual C++ creates a new project for you. This project contains a blank window, as shown in Figure 1.7. The window is referred to as a form and serves as the basis for all the Graphical User Interfaces you create in this book. By default, the form is named Form1. You don't have to change the name in this chapter, but you will learn how to do so in the next.

Image from book
Figure 1.7: Visual C++ presents a blank form when you begin a new project based on a Windows Forms Application template.

The project that Visual C++ 2005 Express Edition has created is a fully functional application. You could run it if you wanted to, but it wouldn't be an interesting experience. Although all the code necessary to manage and display the window is written for you, you get only the bare minimum functionality needed to drive all Windows applications. You can move the window around, maximize or minimize it, or close the application. To make the Joke Machine more exciting, you need to build in a user interface.

Trick

To run the application, press the F5 key. A dialog box appears, asking you if you want to build the project. Select Yes. Visual C++ performs a few steps, and then your application appears.

Step 2: Creating the User Interface

To create the interface for the Joke Machine, you need to add controls to the form. Controls are the user interface elements that the player interacts with as he plays the game. Visual C++ provides an extensive list of controls, located in the Toolbox window, which is displayed on the left side of the IDE.

Hint

A control is an element of your program's GUI, such as a menu, text box, or button.

You can add controls in one of two ways. You can select the control you want and double-click it using the left mouse button. The control then appears on your form. By default, though, Visual C++ begins layering each control you add on top of the last, beginning in the upper-left corner.

An easier way of adding controls involves simply clicking and dragging. If you left-click on any form element, you can drag it over your form and drop it. This allows you to position the control exactly where you want it.

After the form is on your control, you can adjust its position and size. Just click once on the control you want to move. A border appears around it, and you can drag it anywhere you like on the form. You can also resize the control using the mouse or by clicking on the small white squares that intersect the border (shown in Figure 1.8) and dragging.

Image from book
Figure 1.8: You can resize many form controls by dragging their borders.

The first control you will add is a label. Begin by bringing your mouse over the Toolbox tab on the right side of the IDE. The Toolbox window expands, showing you a range of controls to choose from. Find the Label control and drag it to the upper middle of your form. Don't worry about precise placement. Just try to position it somewhere near the top and middle of the form.

Next, locate the Button control in the Toolbox window. Select the button and drag it to the form. Try to position it in the middle of the form. When you are finished, add a second button below it. Notice that the buttons have a default name of Button1 and Button2. By default, Visual C++ adds placeholder text to many of the controls that you add. You can change this text, which is described in the next section.

The final control to add is a text box. Drag the text box to the form and resize it, as shown in Figure 1.8, by clicking it once and dragging the white squares that border the control. Position it below the label and two buttons you've added. You should have an interface that looks like the one shown in Figure 1.9.

Image from book
Figure 1.9: Visual C++ adds descriptive text to controls as you add them to a form.

Step 3: Customizing Control Properties

Now that you've added the necessary controls that make up the interface for the Joke Machine, it's time to customize its appearance. Each control has settings that determine the look of the control, including its size, color, and description. You need to select each control in turn and edit the properties associated with it. This gives the Joke Machine a more easily understood, professional interface.

First, select the label. Its description currently reads label1. It needs to display Joke Machine. To change the text linked to this control, click on the label. After you do this, a new window appears on the right side of the IDE. This is the Properties window. The name of each of label1's properties is listed in this window.

Scroll down and locate the Text property under the Appearance category. As you can see, by default, the label's text description is simply 1abel1. However, if you click on the description, Visual C++ allows you to change it. To replace the string you see, click on the text label1 and replace it with Joke Machine. Now click anywhere on the form or on another property, and you will see the label change.

You need to make the same change for both Button controls. First click the button displaying the text button1. Under Appearances, again scroll down and find the Text property. Change the text for button1 to Joke 1. Repeat for the second button, replacing the text button2 with Joke 2.

As you change the text for the controls, you might need to realign them. Again, don't worry about getting the controls into perfect position. The application still functions no matter where you put the controls.

Step 4: Adding a Little Programming Logic

At this point, you have a Graphical User Interface for your application, but it doesn't do much. If you build the application, you see that the buttons animate when you press them, and the text box shows a blinking cursor. But it does nothing else.

If you want to give the Joke Machine life, you need to add code. You add code by associating C++ programming statements with the controls you want to use to drive the application. In the case of this chapter's application, you link code to the two buttons, which in turn display text in the text box.

To add code to any application, you need to activate the Code Editor and enter the necessary statements at the correct location. You start the Code Editor by double-clicking the form or any one of its controls. When you do so, Visual C++ automatically generates program statements associated with the element that you've clicked and positions your cursor at the right point within the code.

To make the Joke Machine tell jokes when the user clicks a button, just add a few lines of code. Double-click on the button you've labeled Joke1. You're automatically switched to the Code Editor, as shown in Figure 1.10.

Image from book
Figure 1.10: You can give controls functionality by adding code to them in the Code Editor.
Trick

You can switch to either the Code Editor or your program's interface with a single click. Look near the top of the IDE shown in Figure 1.10. You see two tabs: Form1.h and Form1.h [Design]. Form1h is associated with the view of the computer code, whereas Form1.h [Design] links to the interface for your application.

The tabs that Visual C++ displays exist to help manage detail. Because the IDE has so many features, you can't show them all at once. Microsoft's solution to this problem is to overlap or overlay windows on top of one another.
Trick

You might notice that the Code Editor window you see in Figure 1.10 is a lot larger than your own. It has been expanded to make viewing and editing the code easier. You can create this effect several ways. One is by closing the windows in the IDE as you finish using them. However, because a lot of application building involves finding different windows, it can be annoying to constantly have to close and reopen them.

Another, more convenient, way to manage space is to activate the thumbtack option for the windows. Each window has a small thumbtack icon in the upper-right corner that you can click. When you click this icon, the window automatically shrinks to a tab that displays on the borders of the IDE's current window. In Figure 1.10, you can see several tabs on the bottom, left, and right sides of the IDE. Each represents a window that you can access. Moving your mouse over the tab causes the window to expand temporarily. To keep any window open permanently, click on the thumbtack icon again.

As you can see, Visual C++ has already generated some code for you. In later chapters, I cover what this code does in greater detail. For now, you only need to enter the statements shown in bold to get your application up and running. (Note that the code Visual C++ generates for you does not contain the \ character, which I have added here to make the program more readable.)

private: System::Void button1_Click(System::Object^ sender, \
        System::EventArgs^  e)
        {
          textBox1->Text = \
          "What kind of ties can't you wear? Railroad ties!";
        }

Without covering all the technical details in depth at this point, the two lines you've entered basically compose a statement that changes the contents of the TextBox control's Text property. The code you've added is to the button's module, which handles all instances of the button being clicked. When you click the button, this module of code is activated, and the statements within it are executed.

Now add code for the second button. Return to the form designer view for Form1 by clicking on the tab labeled Form1.h [Design]. Then double-click on the Button2 control. Again, you should be returned to the Code Editor window. You see the module that handles instances of Button2 being clicked. Add the line of code shown next, in bold, inside the two new statements.

private: System::Void button2_Click(System::Object^ sender, \
        System::EventArgs^  e)
        {
          textBox1->Text = \
          "Where is the ocean deepest? On the bottom!";
        }

As with the previous C++ statements, the code that you've added displays the joke in quotation marks when you run the application and click the Button2 control.

Step 5: Testing the Execution of the Joke Machine

The design and development of the Joke Machine is complete. It is now ready to run. But before you can do this, you need to build the project. Building the project instructs Visual C++ to bring together all your changes and create a program from them.

To build the project, select Build from the Build Solution menu. In the Output window of the IDE are several messages that confirm that Visual C++ is creating your application. The final message should read like this:

========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

If you don't get this result, make sure that you didn't make typos in the code that you added. When the program is finished building, you can run it by selecting the Start Debugging option from the Debug menu.


SUMMARY

Congratulations! You have completed the first step on the road to becoming a Visual C++ programmer. This chapter has covered a lot of ground for an introductory chapter, but don't worry if you didn't understand all the details. If you stay focused on the larger picture, the material will become much more intuitive and natural.

In this chapter, you learned about what Visual C++ 2005 Express is and what it is not. You also learned a bit of the history behind Visual C++ and where it fits into the Microsoft Visual Studio line of products. This chapter also covered the .NET Framework, including how it works and how Visual Studio products make use of it.

In addition, you learned the five basic steps involved in developing a Visual C++ application. You then put this information together and developed your first Visual C++ application, the Joke Machine.

Before you move on to the next chapter, take a few more minutes to see if you can improve on the Joke Machine by implementing the following list of challenges.


CHALLENGES

  1. Improve the Joke Machine by adding new buttons that display new jokes.

  2. The Joke Machine currently displays only the text string of Form1 in the Windows title bar. Replace this text string with the phrase The Joke Machine. (Hint: Click on the form and modify the form's Text property.)

  3. The Joke Machine's TextBox field currently allows the entry of text. Technically, it should display only jokes. Prevent the text box from accepting text. (Hint: Click on the TextBox1 control and set the Readonly property to True.)


Chapter 2: Navigating the Visual C++ 2005 Express Edition Environment

OVERVIEW

The key to building programs quickly and effectively in Visual C++ is to be familiar with the Integrated Development Environment (IDE). Now that you know the capabilities of Visual C++ 2005 Express Edition, it is time to familiarize yourself with how the IDE works. In this chapter, you will learn about the most common and widely used elements that make up the IDE and how to use them.

In this chapter, you learn the following:

  • How to work with the IDE menu and standard toolbar

  • What the basics are of working with the Form Designer and Code Editor

  • What IntelliSense is and how to use it to your advantage

  • How to work with the Toolbox, Solution Explorer, and Properties windows


PROJECT PREVIEW: THE CLICK RACE GAME

The game project that you learn to develop in this chapter is called the Click Race game. The object of this simple game is for the player to see how many clicks he can score in 30 seconds. Two buttons are provided, but because simply clicking is a bit easy, the game challenges the player by forcing him to alternate between the two buttons. To play well, the player must be able to quickly switch between buttons and click each accurately.

The Click Race game starts up as shown in Figure 2.1. The game buttons that the user must click to score points are located at the bottom of the game window. At the start of the game, these buttons are disabled (grayed out).

Image from book
Figure 2.1: Starting up the Click Race game.

The game begins when the player selects the Start Game button. When this happens, the game button on the left side of the window is enabled, as demonstrated in Figure 2.2.

Image from book
Figure 2.2: Players score points by clicking on the currently active game button.

The player scores a point by clicking on the button. After the button is clicked, the left game button is disabled and the right game button is enabled, as demonstrated in Figure 2.3.

Image from book
Figure 2.3: To score another point, the player must click on the second game button.

The Click Race game allows the player to score as many points as possible within a 30-second period. Gameplay stops at 30 seconds when both game buttons are disabled. The total number of points scored by the player is displayed, as demonstrated in Figure 2.4.

Image from book
Figure 2.4: Plays ends at 30 seconds when both game buttons are disabled.

After you have successfully created the Click Race game, you'll have learned how to build a program that dynamically responds to events that the player generates. You'll also have learned how to work with the Visual C++ Timer control.


GETTING COMFORTABLE WITH VISUAL C++ 2005

Visual C++ applications are created using Visual C++'s built-in IDE. The Visual C++ IDE provides tools such as a compiler, which translates application code into a finished executable program; a debugger, which assists in tracking down and fixing errors in code; and several other tools for managing projects.

The IDE of the Visual C++ 2005 Express Edition features a main menu, numerous toolbars, and many different windows. Because so much functionality is built into the development environment, it is not possible to show all the available toolbars and windows at any one time. If it was shown, the interface would be crowded and unusable. To solve this interface problem, Microsoft has devised several clever techniques that allow the representation of resources to share the same workspace.

Figure 2.5 shows the Visual C++ 2005 Express Edition IDE with a new project ready to go.

Image from book
Figure 2.5: The Visual C++ IDE has room to show only a portion of the available toolbars and windows at any one time.

As Figure 2.5 demonstrates, the default layout of the Visual C++ IDE features a number of different elements. Each of the key elements shown in Figure 2.5 is covered in detail later in this chapter.

One handy feature of the IDE is AutoDock. AutoDock allows you to reposition menus, tool palettes, and other interface elements in the IDE by clicking and dragging them to where you want them to go. When you move them near the edge of the IDE, an outline appears. The outline indicates where the IDE will reposition that element should you release it. This allows you to easily reorganize and customize the IDE to suit your individual preference and work style.

Trap

You should take care when repositioning interface elements within the IDE. So many are available that you can quickly misplace or accidentally rearrange them.
Trap

If you find that you have accidentally messed things up and want to restore the IDE to its default layout, you can. Just click on the Tools menu and select Import and Export Settings. Select the Reset All Settings radio button option at the bottom of the Import and Export Settings Wizard. Select Next. You have the option to save your settings or overwrite them. Select the Next button, and then select Finish.

From time to time, you will either accidentally or deliberately close a window within the IDE. Don't panic if you later discover you need it back. Instead, click on the Window menu and select the appropriate window to display it again. You see a list of the available windows at the bottom of the menu. The Window menu is only capable of showing a limited number of the available windows. If you don't see the window that you are looking for, select the Other Windows option and look for it in the submenu that appears. This submenu displays all windows that you have opened. When you find the window you are looking for, click on it and select the Activate button.

Because the IDE is so packed full of features, Visual C++ 2005 Express Edition employs a few neat organizational tricks to make everything fit. In some cases, two or more windows might share the same space in the IDE. Above the windows, Visual C++ displays a tab that identifies each associated window by name. By clicking the tab, you can quickly jump from window to window.

Another useful feature that you'll see a lot in the IDE is the presence of a thumbtack at the top of windows such as the Solution Explorer and Properties windows. The thumbtack conceptually represents pinning a window so that it remains docked (fixed in place). This feature is known as autohide. When the thumbtack is clicked, autohide is disabled, and the window remains in place. However, when you click the thumbtack, autohide is activated, and the window automatically folds away when your mouse leaves the window's area. Tabs are again used to represent the available windows. If you use your mouse pointer to hover over a tab, the window associated with the tab unfolds, allowing you to use the window as long as your mouse remains in its area. This feature frees up space in the IDE for other windows without having to close any of them. If you want to later fix the window in place, all you need to do is click on the thumbtack icon. For example, look at Figure 2.6. You see that the Solution Explorer window has been docked as a tab on the left side of the IDE to provide additional room for the Properties window.

Image from book
Figure 2.6: Microsoft has implemented several clever organizational tricks to make the IDE more manageable.
Hint

The IDE is highly customizable. Click on the Tools menu and then select the Customize option to configure which of the IDE's many toolbars are displayed. In addition, you can customize any number of IDE features, such as how the Form Designer looks and how the Code Editor behaves, by clicking on the Tools menu and selecting Options.

Navigating the IDE Menu

The Visual C++ 2005 Express Edition IDE includes a comprehensive menu, which lists and centralizes the various tools and commands you need to build applications. Visual C++'s IDE is a dynamic tool. Its interface and functionality change, depending on the particular development task you need to accomplish.

The following list identifies the IDE menus and summarizes the functionality they provide:

  • File. Menu options for opening and saving projects and solutions.

  • Edit. Use text-editing options such as Undo, Copy, Cut, and Paste.

  • View. Switch between the Form Designer and Code Editor and access other windows such as the Toolbox, Solution Explorer, and Properties windows.

  • Project. Add new forms, controls, and components to a project.

  • Build. Build or compile a standalone version of your application.

  • Debug. Test the execution of an application or step through a program that has been stopped with an error or a breakpoint.

  • Data. Configure connections to data sources such as a local database.

  • Tools. Explore different options, including the Options submenu, where you can customize the IDE and various project settings.

  • Windows. Select and arrange open windows.

  • Community. Connect to the online development community to ask a question or obtain sample programs.

  • Help. Get access to Visual C++'s integrated help system, including access to both local and online help topics.

Working with Toolbars

Like many Windows applications, Visual C++ 2005 Express Edition makes it easy to access certain commands using toolbars. By default, Visual C++ automatically displays its Standard toolbar, shown in Figure 2.7. The items displayed by toolbars can change dynamically based on what you happen to be doing at the time.

Image from book
Figure 2.7: The Standard toolbar provides access to the most commonly used IDE commands and windows.

The Visual C++ 2005 Express Edition IDE includes more than a dozen toolbars, each of which provides quick access to various commands. For some of the toolbars, you can configure whether they are displayed by clicking on the View menu and then selecting the Toolbars option. Alternately, you can configure the display of all the available toolbars by clicking on the Tools menu and selecting Customize.

Trick

You can also configure the display of toolbars by right-clicking on any visible toolbar and selecting the desired toolbar from the list that appears.

Each of the icons on a given toolbar performs a specific command or task. Unfortunately, far too many toolbar icons are available to cover each in detail in this book. However, you can find out about the specific function for each toolbar icon by placing your cursor over it. An explanation of the icon's function appears, giving you a sense of what the icon does based on the description displayed.

Form Designer Basics

The Form Designer, shown in Figure 2.8, allows you to construct the Graphical User Interface (GUI) for your program by dragging and dropping interface components. This is one of the major ways in which Visual C++ is truly visual. By default, the Form Designer is located in the same window space as the Getting Started window and the Code Editor window (which you use later to enter programming commands).

Image from book
Figure 2.8: Visual C++ automatically creates a new form containing basic Windows elements each time you open a new Visual C++ project.
Trick

As you make changes to your form, you might notice that an asterisk appears in the tab for the window just to the right of the form name. This asterisk acts as a reminder. It indicates that you have made changes to the form but have not yet saved your work. Because it is easy to get distracted by all the tasks that go into making up a program, I strongly recommend that you save whenever you make a change to your Visual C++ application that you want to keep. As an old saying goes, save early, and save often.

As you have already learned, you create an application window using a form. An application can have more than one form. As you saw when you created the Joke Machine in Chapter 1, "An Introduction to Visual C++ 2005 Express," you create an application by adding controls to it. These controls are copied over from the Toolbox. You can customize controls that are added to your form by altering their properties, such as the control's size or text description. When you have positioned all the elements of your form as you like, you can click on each form element and add code that will control the behavior of that element.

If you like having your controls lined up and arranged in an orderly fashion (which often is the mark of a well-designed GUI), the Form Designer makes this easy. You can simplify relocating and aligning controls by following the automatic guides that appear on the form as you drag a control onto your form. The guidelines appear as blue bars. They provide visual feedback that shows the location of each control relative to the location of nearby controls on the form, as demonstrated in Figure 2.9. This can greatly aid you in creating a slick, professional-looking application.

Image from book
Figure 2.9: As you drag elements to a form, alignment indicators appear to assist you in aligning form controls.
Trick

If you need to line up or adjust multiple controls on your form, the Format menu provides a number of options to do so. For example, if you have three buttons in various positions on the form and want all of them centered, you can select all of them by holding down the Shift or Ctrl key as you click on each button and then click on Format, Align, and select the Centers option. If you then want to center the buttons in the form, you can select Format, Center in Form, and click both the Horizontally and Vertically options.
Hint

You might find yourself needing to lock controls in place. This often happens if you accidentally click near them and move them or have the tricky task of trying to position many elements all in one tight space. To lock the controls, select the control you want to lock and then click on the Format menu and select the Lock Controls command. This locks whatever controls were highlighted. Locked controls are indicated by a dotted outline and a single small square in the upper-left corner of the control.

If you later decide that you need to release a control, click on it once and select the Lock Control command again.

Understanding the Code Editor

The Code Editor is your window into the underlying software commands that make up your application. It displays both the code that is generated automatically when you add interface elements and the code that you will later write to drive your application's behavior. The easiest way to access it is to double-click on a form or one of the controls on the form. This automatically switches you from the Form Designer view to the Code Editor view, as shown in Figure 2.10. It also conveniently places your cursor at the start of the body of code related to the element that you selected.

Image from book
Figure 2.10: The Code Editor has two drop-down lists (Scope and Functions) used to quickly navigate within an application source code.
Trick

As you become more comfortable with Visual C++, you might want to customize how the editor functions. You can do so by clicking on the Tools menu and selecting Options. When the Options window appears, select the Text Editor option located on the left side of the Options window. Under the General options, you can toggle basic editor behavior, such as how the editor displays scrollbars or handles margins. For more specific control, you can select how the editor treats individual language options like tabs and word wrapping by selecting and expanding the options next to each language provided.

Program code associated with a form and any of the controls placed on that form is stored within the form. Therefore, if a Visual C++ application contains more than one form, the code associated with each form is stored and displayed separately.

Trick

In addition to storing program code alongside a form, you can store the code in a separate module, which you can then use to refer to a form and its controls.

At the top of the Code Editor are two drop-down lists. The first drop-down list is the Scopes list, from which you can select the different forms or modules associated with your project. The second drop-down list is the Members list, which immediately repositions the cursor at significant blocks of code, such as that relating to any control you've added or initialization of a form. By using these two drop-down lists together, you can locate the important commands or data that relate to your application. In conjunction, the two lists allow you to rapidly move between documents and within a single document, sparing you the effort of having to remember where everything is.

Visual C++ Assisted Code Development

Visual C++ 2005 Express Edition saves you a great deal of time by creating blocks of code that your application needs. Rather than having to figure out how to code a button or text box, for example, Visual C++ creates code associated with the interface component when you drag it to your application. This is one of the fundamental strengths of Object-Oriented Programming (OOP). All the interface components in the Toolbox are essentially blocks of code that you can use without having to concern yourself with the details of how they function.

When you drop a component onto your form and click on it, Visual C++ generates just enough code to allow you to govern how the control functions. For example, as you saw in Chapter 1 when you created the Joke Machine, Visual C++ automatically generates a great deal of code for your project.

To see another example of this in action, create a new project and place a label, a text box, and a button on the form. Then double-click on the form. You are taken to a file containing the code for your form. Visual C++ automatically places your cursor at the following statement:

private: System::Void Form1_Load(System::Object^  sender,
          System::EventArgs^  e) {
          }
Trick

Actually, the format of the code statements that you see when performing the preceding steps varies slightly from the statements presented here. To make things fit onto the pages of this book, I had to split some programming statements into multiple pieces.

Above this function, you can see numerous other commands relating to managing the form. This code is also automatically generated and is placed in your project after you create it. At the moment, you might not understand it all, but as you can see, Visual C++ saves you from having to create this code yourself.

When you clicked on the form, Visual C++ automatically positioned your cursor at the block of code controlling what happens when the application first runs. If you switch back to the form and double-click on the button you've added, code is automatically generated for you. As soon as you do this, the Code Editor defines a new procedure for you, as demonstrated in the next program listing.

private: System::Vo1d Form1_Load(System::Object^ sender,
          System::EventArgs^  e) {
          }
private: System::Void button1_Click(System::Object^ sender,
          System::EventArgs^  e) {
          }

You now need to type only the Visual C++ code statements that you want to be executed in relation to these interface components, as was demonstrated in the Joke Machine project. Later, in Chapter 8, "Enhancing Code Structure and Organization," I cover the benefits and purpose of functions in more detail.

Color Coding, Automatic Indentation, and Spacing

In Chapter 1, you might have noticed when creating the Joke Machine that the Visual C++ editor did several things automatically to make writing your code easier. For instance, certain programming commands were color-coded to make them stand out. This was a function of settings in the editor designed to help you identify keywords, which are programming commands that drive the C++ language. As your programs grow longer and your code becomes increasingly complex, you will come to appreciate this feature. Automatic color coding acts as a visual indicator that highlights the key parts of your program. By doing so, Visual C++ makes your code easier to read and understand, and it makes the learning process faster.

Another great feature to help you organize your code is automatic indentation. When you finish typing a line of code, Visual C++ attempts to recognize the code and apply the proper indentation that goes with the code statements. You can see this demonstrated in Figure 2.11. Automatic indentation is another feature that visually organizes your code, which again makes the learning process faster and your code easier to comprehend.

Image from book
Figure 2.11: The Visual C++ Code Editor automatically color-codes statements and indents them to make them easier to read.

IntelliSense

IntelliSense is a powerful feature that is so useful you will probably come to find it indispensable. It has become an important part of all of the Visual Studio products. In fact, IntelliSense might come to serve as your main resource when seeking help on how to program.

IntelliSense is responsible for displaying the information-rich pop-up boxes that appeared as you typed in code for the Joke Machine back in Chapter 1. As you type in the Visual C++ IDE, IntelliSense continuously scans your program statements in search of a match. As you type words that IntelliSense recognizes, it brings up a window displaying all the possible matches and options relating to the code that you are typing.

To better understand IntelliSense, let's look at a couple of examples. In the first example, shown in Figure 2.12, I created a form that contained a button and a text box. I then double-clicked on the button to open the code designer. I entered the word textBox1 followed immediately by a period. In response, IntelliSense activated and displayed a pop-up window showing all the possible coding options available to me. In this example, I clicked on Text, which represents the TextBox control's Text property, and IntelliSense automatically appended the word to my code. All that remained for me to do was to finish writing the code, as shown in the next program statement example.

Image from book
Figure 2.12: IntelliSense provides dynamic assistance as you enter your code statements.
textBox1->Text = "This is a test!";

IntelliSense can help in the formation of more complex programming statements, too. For example, with the next code statement, my intention was to gray out and prevent the user from being able to click on the Button1 button. I started the statement by keying in the name of the Button1 control followed by an arrow (composed of a minus sign and a greater than sign run together). IntelliSense then activated, as shown in Figure 2.13, and displayed a pop-up window showing me all of my available options. As I typed the word ehable, the button property Enable became highlighted. By pressing or clicking Enter, IntelliSense automatically appended that word to the code.

Image from book
Figure 2.13: IntelliSense can assist you in the creation of complex code statements and in reducing typos.
Trick

You can use the Ctrl and Spacebar keys together to automatically activate IntelliSense. If you do so on a blank line, IntelliSense shows you all information relating to properties or commands that you can use within your form. It can also be a handy tool for helping you to remember the format of various properties or commands. For example, imagine that you have created a form and are having trouble remembering the name of the Text property. In this scenario, you could activate IntelliSense using Ctrl and Space. A long list would appear in the window. As you started typing the word, IntelliSense would automatically jump down to the relevant section. From there, you could press the Enter key, and the proper spelling would be placed in your code automatically. You can see an example of this demonstrated in Figure 2.14.

Image from book
Figure 2.14: You can manually activate IntelliSense by using the Ctrl and Spacebar keys.

What's in the Toolbox?

The Toolbox window, shown in Figure 2.15, contains all the controls that are available to your Visual C++ applications. By dragging and dropping an icon from the Toolbox onto a Visual C++ form, you automatically add its functionality to your application. For example, in this book, you learn how to work with controls such as Label, Button, and TextBox.

Image from book
Figure 2.15: The Toolbox window provides access to the controls you can use to create a Windows application.

The Label control allows you to place text within the body of your form so that you can identify important controls or other application-specific information. The Button control allows you to add buttons to your form as needed. The TextBox field provides the ability to display text and retrieve input from the user. You can customize each of these controls with various options, and you can add code to alter each of the control's behaviors as your program runs. As you can see from the list, the Label, Button, and TextBox are just a few of the many controls available to you.

By default, the Toolbox window displays a list of controls with their names to the right. Toolbox controls are organized into the following groups:

  • Common Controls. This grouping contains the most frequently used controls when building Windows applications.

  • Containers. These controls provide a way of organizing other controls you add to your form in groups.

  • Menus and Toolbars. This group of controls provides menu and toolbar functionality.

  • Data. These controls give your application database connection and processing capabilities.

  • Components. These controls provide access to low-level services provided by your application or the operating system.

  • Printing. This grouping facilitates management of printer services and functionality.

  • Dialogs. This list of controls provides access to frequently used Windows dialog boxes.

  • All. This contains an ungrouped list of all available controls, displayed alphabetically.

The list of usable controls is quite extensive. Because of this, you might find yourself scrolling quite a bit to access them all. However, the Visual C++ IDE provides a few management techniques to make the list more workable.

One option is to collapse the categories that you don't need. You can do this by clicking on the minus symbol next to each category name. The minus sign changes to a plus sign, and the category shrinks, leaving only the category name. To recover the list, just click on the plus symbol to expand the category.

As you gain familiarity with the purpose of the controls and the icons associated with them, you can also choose to view the list using only the control icons. To do this, right-click on the Toolbox. A list of options appears. By default, List View is selected. Select it to turn off the names associated with controls, and you will see only the control icons. To restore the names, select List View again.

You can also group icons in your own category. From the menu that appears when you right-click on the Toolbox, select Add Tab. You are given the option of naming your new category. Then you can click and drag controls, moving them to your new category. Or you can select a control, right-click, select Copy, position your cursor within your newly created category by clicking any of its items, and then select Paste. The result is a duplicate of the desired control, conveniently grouped in your own custom category.

Unfortunately, this book does not have adequate space to cover all the features available to you in the Visual C++ 2005 Express Edition, such as every Toolbox control available. You will, however, gain enough familiarity with how to work with several of the most important controls and other features. This provides a solid foundation to later expand your education to cover more of the details.

Trick

If you want to access advanced controls, Visual C++ provides a further Toolbox customization feature to allow you to do so. These additional controls are available by right-clicking on the Toolbox and selecting Choose Items. This opens the Choose Toolbox Items dialog box, where additional controls are listed on two tabs. The first tab is .NET Framework Components. It stores controls that are designed to work with the .NET Framework. The second tab is listed as COM Components. The controls listed here are legacy controls that are designed to make Visual C++ backward compatible with previous programs written in earlier versions of Visual C++. To add a control, select it and click on OK. To see the control, click on Show All.

Working with Solution Explorer

Solution Explorer allows you to manage all your projects. It is the window that displays the most important files and data associated with your applications. Solution Explorer, as demonstrated in Figure 2.16, is organized in a hierarchical format. At the top of the hierarchy is the solution, followed by the project. Projects contain files with the code and data that form your program.

Image from book
Figure 2.16: Using Solution Explorer, you can manage the projects and files that make up your Visual C++ applications.

You can also use the Solution Explorer to locate and open any file associated with the project by double-clicking on it. If you select a file that is associated with both the Form Designer and the Code Editor, you can select which tool you want to work with by clicking on the appropriate icon, as shown in Figure 2.16.

Understanding How to Use the Properties Window

Properties are central to the development of any WinForm-based Visual C++ application. When you set or change the values assigned to a form using the Properties window, you can specify its initial appearance and behavior. This establishes the initial settings that the form has when the application starts. To dynamically change how the form behaves when it is running, you can later add program code that alters the values of almost any one of its properties.

Controls are similar to the form in this respect. Any control that you add to your form when creating your application's Graphical User Interface also has a collection of properties associated with it. When you alter such properties as a control's associated text, size, color, or location in the Properties window, you establish the initial settings that your user sees when the application first runs. As with forms, you can also dynamically alter these values in code to control the behavior of the specific control.

You got a brief introduction to properties when you created the Joke Machine in Chapter 1. Whenever you select either the form or a control that you have dragged onto it, the Properties window automatically appears, as shown in Figure 2.17.

Image from book
Figure 2.17: Examining the properties associated with an application's Form control.
Hint

If the Properties window does not appear, you can quickly access it by pressing the Alt and Enter keys. You can also bring up the window by selecting View, Other Windows, and Properties Window.

As you can see, the elements within the Properties window are divided into two columns. Listed in the left column of the window are the names of all the properties associated with either the form or one of its controls. The right column displays the possible values that you can select or assign to each value.

As with the Toolbox window, the Properties window has a lot of options. The Visual C++ IDE provides two means of filtering the list to display the properties you're looking for. You can sort the list alphabetically or by category. Sorting helps when you remember the name of the property but can't quite recall what category it falls under. Alternatively, sorting by category allows you to group properties functionally. This can aid you in finding the properties that are associated with a certain kind of functionality, such as controlling how the control or form appears or how it responds to certain user commands. You can switch between Category and Sort views by clicking on the Categorized or Alphabetic icon located at the top of the Properties window, as shown in Figure 2.17.

You can change properties in one of two ways, depending on the acceptable range of values that the property has. For some, you can simply type the value you want to initialize the property to. You do this by clicking in the column on the right next to the property. The property name highlights, and you see a flashing text cursor in the column to the right of it. What you can enter depends on the requirements of the property. In the field associated with some properties, you can simply enter text. Other properties require data in a specific format and generate an error dialog box if you do not enter the expected values. A button's size, for instance, must be specified as two numbers separated by a comma.

Some properties are limited to a specific range of options. For these, Visual C++ provides a handy selection mechanism. Beside these properties is an iconic down arrow. Selecting the down arrow produces a drop-down list of values to choose from. For instance, if you want to alter the color of a button you've added, you click the property (in either the left or right column) and then click the iconic down arrow that appears in the right column. This produces a drop-down dialog box filled with color options, as shown in Figure 2.18. Because it limits your range of choices, the list displayed by the drop-down dialog box is useful because it prevents you from entering invalid values.

Image from book
Figure 2.18: When the available range of values for a property is limited, the Properties window produces a drop-down list for your selection.

For some properties, such as the Icon or Font property, you'll notice a special iconic ellipsis symbol (…). This symbol indicates that the property has an even more extensive range of options than a drop-down list would allow for. When you click the ellipsis, the Visual C++ IDE brings up a dialog box displaying several configuration choices. For example, Figure 2.19 shows the dialog box that appears, allowing you to modify the values associated with the Font property.

Image from book
Figure 2.19: When properties have a wide range of possible options, selecting them initiates a separate dialog box where you can choose the values to customize the property.

Some properties also have properties associated with them. The Font property, for instance, displays an icon of a plus sign next to it by default. Clicking the icon reveals suboptions that allow you to customize characteristics such as whether the font is bold or italic, or what its point size is.

Trick

The Properties window displays the list of properties that you can edit before your program runs. These are known as design time properties. They are by no means the full list of properties that your program has access to. Another range of properties that are available but aren't displayed in the Properties window are the runtime properties. You can only alter runtime properties in code by using the IDE. Your application, in turn, sets the property when it executes the line of code that contains that property and the value you assign to it. For example, the font type and size associated with a control are always available at design time, whereas the text entry for a control that holds user input, such as a TextBox control, isn't available until your application is running. You can, therefore, only set runtime properties by using commands in the code section of your program.

The Component Tray

Most of the controls you drag from the Toolbox onto your form appear on the form as a visual representation of what you will actually see after you run the program. A button or text box, for instance, appears exactly as it would when your application launches. Some controls, however, must be abstractly represented. These controls have no visual shape or representation that the user can interact with. Visual C++ has no way of showing them as an object that appears on your form.

A good example of this type of control is the Timer control. A Timer control enables your application to perform certain activities after a given duration. The Click Race game that you will learn about later in this chapter, for instance, employs a Timer control to set the maximum time limit that the user has for playing the game. The Timer control, however, cannot appear on the form because it is not an object that the user can manipulate, see, or respond to. It is abstract.

How can a formless control be shown in the Design view of your application? For these specialized components, the IDE offers the Component Tray. The Component Tray is a storage area that appears below your form. It is represented as a gray box that simply holds a list of icons. All abstract controls that are related to your application but otherwise cannot be visually represented appear within it. Figure 2.20 demonstrates the Component Tray.

Image from book
Figure 2.20: The Component Tray uses icons to represent all controls that affect your application but that the user cannot see or manipulate.

As you can see in Figure 2.20, the Timer control has been added to the form. You can select it and set its properties just like any other control that you can add to a Visual C++ form.

Other Windows

The Visual C++ IDE contains a number of other specialized windows. Some only appear under specific conditions or are useful in certain situations. For example, the Error List window displays the line number and details of program errors if you attempt to run an application that has errors in its code. Table 2.1 lists these additional windows, which are discussed, where relevant, in later chapters.

Table 2.1: Additional IDE Windows
Window | Description
Bookmark | Displays a list that allows you to navigate to saved bookmarks within your code
Command | Allows you to bypass menu control so that you can directly activate features of the IDE
Call Browser | Presents a mapping of all modules of code that are linked to the current module of code
Output | Displays any command-line output that the application produces
Class View | Provides the ability to view objects and their members
Error List | Displays information about any errors that your program has encountered when attempting to compile your code
Task List | Displays a project management to-do list to which you can add tasks of varying priority


BACK TO THE CLICK RACE GAME

In the Click Race game, the player is required to click as quickly as possible on two buttons to score points. The game creates pressure by limiting the amount of time the player can click to a 30-second period. And because clicking a single button would be too easy, the game requires the player to alternate between the left and right button when clicking. As a result, the player not only must be quick with the mouse, but accurate with his aim when it conies to clicking on a button.

Designing the Game

The game is composed of a single window, given by the form, and six controls added to the form. The form controls are summarized in Table 2.2.

Table 2.2: Form Controls for the Click Race Game
Control | Description
TextBox1 | Text box that displays the number of valid mouse clicks
Label1 | Descriptive label for the text box
Button1 | One of two game buttons
Button2 | One of two game buttons
Button3 | Button used to start game play
Button4 | Button used to close the game
Timer1 | Timer control used to control the length of a game

Step 1: Creating a New Visual C++ Project

To create the Click Race game, you must first create a new project. The steps for doing so are short and easy.

  1. If you have not already done so, launch Visual C++ 2005 Express Edition.

  2. When the IDE appears displaying the Start page, select File and then New Project. The New Project dialog box appears.

  3. In the Project Types section, make sure that CLR is highlighted. (It should be by default.)

  4. Under Templates, select Windows Forms Application. This instructs the IDE to provide your project with the access to the forms and controls you need to create a Windows application.

  5. Type The Click Race Game as the name of your new application in the Name field located near the bottom of the New Project window.

  6. Click on OK to close the New Project dialog box.

When you complete these steps, the Visual C++ IDE places you in the Design view of your new project. You should see a blank form ready for controls to be added to it.

Step 2: Creating the User Interface

Now let's add the necessary controls that make up the Click Race game's interface. Figure 2.21 shows all the controls you will be using.

  1. Start by adding a text box to the upper middle of the form, as shown in Figure 2.21.

  2. Next, add a label and position it above the text box. Visual C++ automatically names the label Label1.

  3. Add the first button to the left side of the form. Visual C++ assigns it the name Button1.

  4. Add the second button to the right side of the form, as shown in Figure 2.21. It has the default name of Button2.

    Trap

    Be careful not to mix the buttons up. When you begin adding code to control the behavior of the application based on button clicks, you will need to add it to the right button. If you get confused about the name of any control, select it and look under Properties for the (Name) field. The value to its right will be the name used to refer to the component in code.

  5. Add the third button centered near the bottom form. Visual C++ assigns it the name Button3.

  6. Add a fourth button just beneath the third button. This button appears with the label Button4.

  7. Add a Timer control to your form. This control does not appear on your form, but rather in the Component Tray. By default, it is named timer1.

Image from book
Figure 2.21: The design view of the Click Race game's interface.

You have now successfully built the interface for the Click Race game. Your result should look something like that shown in Figure 2.21. (Don't worry if your elements are not lined up exactly right.)

Step 3: Customizing Form and Control Properties

The first step in customizing the Click Race game is to get the game to display its title when you run it. This involves changing a single value, but you must bring up the Properties window for the form. To do this, click anywhere on the form except where you have placed the controls. When the Properties window appears, locate the Text field that appears under the Appearance category (or under T if you are viewing the list alphabetically, as was mentioned earlier in this chapter in the section "Understanding How to Use the Properties Window"). The default value is Form1. Replace this with The Click Race Game.

Trap

Make certain that you edit the Text property and not the (Name) property beneath the Design category, which also displays the value Form1. The Name property is associated with code (and won't accept spaces anyway).

Now let's move on to modifying the individual controls you've added. The first control that you must modify is the TextBox1 control. Table 2.3 shows the properties that need to be modified and their corresponding value.

Table 2.3: Property Changes for the TextBox1 Control
Property | Value
BackColor | Info
ForeColor | HotTrack (on the System tab)
ReadOnly | True
Font | Arial
Font | Regular
Font | Size 14
Size | 132,29

Next, bring up the Properties window for the Label1 control by clicking on it. Table 2.4 shows the changes you need to make.

Table 2.4: Property Changes for the Label1 Control
Property | Value
Font | Arial
Font | Bold
Font | Size 12
Text | Number of Clicks

You're almost done. For Button1, Button2, Button3, and Button4, consult Table 2.5 to see what values to set the button properties to.

Table 2.5: Property Changes for the Button Controls
Button Name | Property | Value
Button1 | Text | Click Me!
 | Font | Arial
 | Font | Regular
 | Font | Size 9
Button2 | Text | Click Me!
 | Font | Arial
 | Font | Regular
 | Font | Size 9
Button3 | Text | Start Game
 | Font | Arial
 | Font | Regular
 | Font | Size 9
Button4 | Text | Exit
 | Font | Arial
 | Font | Regular
 | Font | Size 9

You need to modify one more control. timer1, which appears in the Component Tray, must have its Interval property changed. By default, Interval is 100. This value represents the delay, in milliseconds, before the Timer control registers that a single interval has passed. Intervals are simply a means of grouping milliseconds into blocks of time so that you can count them easily. You can set the interval to 1, in which case the timer's interval would represent a single millisecond. Or you can group them by thousands, in which case each interval represents a single second. Because we want the player to be able to play for only 30 seconds, it would be more convenient if each timer interval were the equivalent of a single second. So let's change the value to 1000, as illustrated in Table 2.6.

Table 2.6: Property Changs for the Timer1 Control
Property | Value
Interval | 1000

You've now made all the property modifications required for the Click Race game.

Step 4: Adding a Little Programming Logic

Now you are ready to move on to controlling the application's behavior by adding code. Start by double-clicking anywhere on the game's form (but not on the controls you've added). Visual C++ automatically places you in a section of code that it generates, as shown in the next listing. Actually, you will see a slight difference between the listing here and what is displayed in the IDE. At the end of the first line is a backslash character. In the C++ language, this is the way you indicate that two lines of code belong together. Here the backslash is used to make the code a bit easier to read. Beyond that minor change, however, the code should be the same.

private: System::Void Form1_Load(System::Object^ sender,
          System::EventArgs^  e) {
      }

If you scroll above this block of code, you will see that Visual C++ generates a lot of code to drive your application. Unfortunately, much of it will likely not make sense at this stage. Rest assured, though, that you don't need to understand everything that's happening to write a working program.

What is important to understand is that the code you see manages the way your application behaves when it runs. Much of the code handles initializing your application and configuring the resources it needs. For instance, you will see references to the values you've entered in the Properties window, such as the names of the buttons or the font they use. In later chapters, you will come to have a better grasp of why Visual C++ creates what you see, but for now, try to focus on adding the code for the Click Race game where it is needed.

Trap

The code that Visual C++ generated is grouped into labeled blocks. It is important not to delete or change the values of what you see in these blocks. If you do so, your application might stop working.

The code that you will be adding allows for three things. First, it allows the player to start and end the game. You will also add statements that keep track of the number of clicks and display them to the player. Finally, you will add code that manages the timer.

The majority of what you will be doing is adding C++ statements to create regions of code known as functions. These functions are created automatically when you double-click on the form or one of its controls. There is a wide variety of functions and many details associated with them, which we'll cover in Chapter 8, but you only need to concentrate on adding the statements to each function, as specified.

Hint

Functions are regions of code that are designed to perform a specific task, such as responding to events generated when a user clicks on one of an application's form controls.

Let's get started. The first step is to add the statements that will keep track of the number of times the two buttons have been clicked and the length of time the player has been playing the game. Locate the section of code displayed in the next listing. This section is reserved for form variables, which are C++ statements that store information. (You'll learn more about form variables in the coming chapters.) Add the lines in bold to your code.

private:
  /// <summary>
  /// Required designer variable.
  /// </summary>
  Int16 intClickCounter;  // Stores number of clicks
  Int16 intTimerCounter;  // Stores timer value
Trick

The text that appears after two slashes is called a comment. Comments are text descriptions of how certain program statements function in your application. Visual C++ ignores everything after the two slashes, so you can type whatever you want. Comments are not required, but they're one of the marks of a professional programmer, and you should get used to adding them. The details on good commenting are covered in later chapters.

Next, you want to guarantee that the values that control the behavior of the Click Race game are set a certain way as soon as the player launches the application. When the player first plays, both of the buttons on the left and right sides of the form should be disabled (grayed out). The timer should be set to 0, as should the number of clicks. To do this, add the following code to the Form1_Load function:

private: System::Void Form1_Load(System::Object^ sender,
          System::EventArgs^  e) {
        // Initialize game's starting values
        intClickCounter = 0;
        intTimerCounter = 0;
        button1->Enabled = false;
        button2->Enabled = false;

Now click on the Form1.h [Design] tab to return to the Design view. Double-click on Button1. Just as when you double-clicked on the form, this action causes Visual C++ to generate a function associated with handling Button1, called button1_Click. Here your application defines what happens when the player clicks on the game's left button. Type the statements shown in bold in the next listing. This code performs four steps. First, the statement right beneath the comments describing this block of code increases the counter holding the number of clicks by one. Next, it copies the value of the counter to the Text property of textBox1, which in turn causes it to be displayed to the player. The next statement disables the game's left button. The final statement enables the right button.

private: System::Void button1 Click(System::Object^ sender,
          System::EventArgs^  e) {
        // Increment the number of clicks, display them, and
        // then disable the left button and enable the right one
        intClickCounter++;
        textBox1->Text = intClickCounter.ToString();
        button1->Enabled = false;
        button2->Enabled = true;
      }

The game's right button must perform almost the same steps. Switch back to the Design view by clicking the Form1.h [Design] tab. Double-click on Button2. This action, in turn, switches you back to the Code Editor. Visual C++ has added a function that corresponds to Button2, called button2_Click. Add the statements in bold to control the game's behavior when the player clicks the right game button. As you can see, the first two lines below the comment are identical to what you added under button1_Click. The difference is that this time the left button is enabled and the right button is disabled.

private: System::Void button2_Click(System::0bject^ sender,
          System::EventArgs^  e) {
        // Increment the number of clicks, display them, and
        // then disable the right button and enable the left one
        intClickCounter++;
        textBox1->Text = intClickCounter.ToString();
        button1->Enabled = true;
        button2->Enabled = false;
      }

Next, it is time to control what happens when the player clicks the game's Start button, which is button3 in the code. Switch back to Design view by clicking the Form1.h [Design] tab. Double-click on Button3. Once again, Visual C++ generates code and returns you to the Code Editor. Now you will notice that the cursor has been placed at a new function named button3_Click. You are going to add functionality that is similar to the code you added to the Form1_Load function. The code sets the game's counter and timer values to 0. Although you already did this in the Form1_Load function, doing it here ensures that the timer count and number of clicks are not carried over from a previous game, but are fresh for each new game. The code also enables the left mouse button and disables the right. Finally, it starts the timer and ensures that textBox1 is cleared for a new game. To give Button3 this functionality, add the code in bold in the next program listing.

private: System::Void button3_Click(System::0bject^ sender,
          System::EventArgs^  e) {
        // Start the game by making sure the timer and counters
        // are at 0, the left button is enabled, and the
        // right button is disabled
        intClickCounter = 0;
        intTimerCounter = 0;
        button1->Enabled = true;
        button2->Enabled = false;

        timer1->Enabled = true; // Begin timer
        textBox1->Text = "";    // Clear text box
      }

Now let's control the behavior of the program when the player clicks the Exit button. As before, click on the Form1.h [Design] tab to return to the Design view, and then double-click Button3. You will be switched back to the Code Editor and placed at a new function named button4_Click. You need to add only one statement, which closes the entire application. To do this, add the code in bold, exactly as shown in the next listing.

private: System::Void button4_Click(System::Object^ sender,
          System::EventArgs^ e)  {
        // End the application when the user clicks the
        // exit button
        Close();
      }

The final step to complete the game is to add code that controls the behavior of the timer. Click on the Form1.h [Design] tab to return to the Design view, and then double-click on the timer1 control. You are taken back to the Code Editor, where Visual C++ has added the timer1_Tick function to your application. You want the code associated with the timer to increment its counter each interval, which is also known as a timer tick. Recall that you earlier defined a tick as 1 second in the Properties window of the timer1 control. Now you will add code that is activated once per second. The code adds 1 to the timer's count and tests the final result to see if it equals 30. If the timer counter reaches 30, both game buttons are disabled, thus ending the game. To make this happen, add the bold statements in the next listing.

private: System::Void timer1_Tick(System::Object^ sender,
          System::EventArgs^  e) {
        // Update the timer
        intTimerCounter++;
        if( intTimerCounter == 30 )
        {
          // If the timer reaches 30, disable
          // the buttons
          button1->Enabled = false;
          button2->Enabled = false;
        }
      }

Step 5: Testing the Execution of the Click Race Game

Congratulations! You've just finished building your first complete game! But before you can see the results of all your hard work in action, you need to compile and run the program. To do this, select Build Solution from the Build menu or simply press the F7 key.

In the Output window are the results of your program being compiled. When you're finished, Visual C++ displays the following:

========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

If the result instead claims 0 succeeded and 1 or more failed, your program has an error. Any error is probably the result of a typo, so carefully check the code you typed if this occurs. The details of several of the most common errors you might see are covered in Chapter 11, "Debugging Visual C++ Applications."

When you're ready to run the program, select Start Debugging from the Debug menu. Visual C++ launches the program for you automatically. You can then begin testing, which is the final phase to developing any application. In this phase, programmers make sure the program works as intended.


SUMMARY

This chapter provided detailed coverage of the most commonly used windows in the Visual C++ 2005 Express Edition IDE. This included learning how to work with its menu and toolbars. You also learned how to work with the Form Designer and the Code Editor. In addition, you learned about IntelliSense and how to use it effectively. On top of all this, the chapter presented additional information on how to work with and take advantage of the Toolbox, Solution Explorer, and Properties windows.

Before you move on to Chapter 3, "Creating an Application Interface," take a few minutes to further improve the Click Race game by implementing the following challenges.


CHALLENGES

  1. See if you can redesign the color scheme of the Click Race game. Try altering the foreground and background colors of the buttons and the form itself or altering the font properties to see if you can create a unique-looking Windows application.

  2. If you double-click on the Click Race game's window, you can resize it, resulting in a less-than-attractive appearance. Prevent this behavior by locking the dimensions of the window into place. (Hint: Set the FormBorderStyle property to one of the Fixed border styles in the drop-down list that appears.)

  3. When the time runs out, the timer1 control keeps going even though the game is over. The game still works because timer1 is reset when the game restarts. However, allowing timer1 to keep running is an inefficient waste of CPU resources and a bad programming practice. Reprogram the game to disable the timer when it is no longer needed. (Hint: Add timer1->Enabled = false immediately after the buttons are disabled.)

  4. Add a second text box that displays the amount of time remaining.


Chapter 3: Creating an Application Interface

OVERVIEW

Your application's Graphical User Interface (GUI) is the first impression that you make on your user. The quality of the interface determines how easy the application is to use. It also might help determine how popular it becomes.

In this chapter, you learn how to develop a great-looking interface for the Visual C++ applications you write. In the process, you learn how to create programs that have the same look and feel of professional Windows applications that users are familiar with using every day. You gain an understanding of how to create a Status Strip, give your users help with ToolTips, and display an icon in the System Tray that represents your application and allows users to quickly gain access to it.

This chapter teaches you how to utilize two built-in dialog boxes that enhance the display of information and make it simple to obtain user input. You also learn valuable techniques in the process of programming this chapter's game, the Speed Typing game.

In this chapter, you learn the following:

  • How to display text in an application's Status Strip

  • How to give controls useful information via ToolTips

  • How to associate a custom icon with your application

  • How to use the System Tray to display your application's icon

  • How to use MessageBox::Show to show messages

  • How to control the order in which controls are accessed by tabbing

  • How to specify the starting location of your application on the Windows desktop

  • How to determine the style of border that frames your application


PROJECT PREVIEW: THE SPEED TYPING GAME

The game project that you learn how to develop for this chapter is the Speed Typing game. The Speed Typing game challenges the player to type as quickly and accurately as possible. The game begins by displaying a sentence. The player must reproduce the sentence without errors. The Speed Typing game only gives the player 15 seconds to type the complete string. If the player is successful, he advances to the next level, which contains another sentence to type. If the player makes a typo or runs out of time before typing the complete sentence, the game registers a strike against him.

At each successive level, the sentences become more and more challenging to type. The game ends when the player either manages to complete five levels or accumulates three strikes. At game's end, the player is ranked as having the skill level of beginner, intermediate, advanced, or expert. Figures 3.1 through 3.5 demonstrate the overall flow of the Speed Typing game.

Image from book
Figure 3.1: The Speed Typing game begins when the player clicks on the Go button.
Image from book
Figure 3.2: Players advance by typing the required text string within the allotted amount of time.
Image from book
Figure 3.3: Players who fail to type the required text in time receive a strike.
Image from book
Figure 3.4: Players who make a typo when keying in the required text string receive a strike.
Image from book
Figure 3.5: The player's typing skill level is analyzed and displayed at the end of gameplay.

As a result of designing the user interface and programming the code for this game, you will have a much better understanding of how Windows GUIs work. This includes the opportunity to gain experience implementing several techniques that enhance user interfaces and make applications simpler to use.


PUTTING TOGETHER A GRAPHICAL USER INTERFACE

Your program's GUI is like a professional calling card. It is the first thing that users see when they activate your program. Years of experience using Windows GUIs have set a certain level of expectation among users, and your application will be measured against what they have used before. One of the most important things that users expect is a clean, well-organized layout. Controls and information should be arranged in orderly and related groups. This makes the user's workflow faster and more efficient.

Another aspect of interface design that users like to see is logical tab ordering. Tab ordering determines which controls are activated when the users selects the Tab key to jump between them. Although most users interact with your program with the mouse, power users—those who become extremely proficient at using your application—appreciate shortcuts. A sensible tab ordering helps them navigate through and activate controls without having to spare the time to reach for their mouse.

Status Strips that can generate important messages are another popular feature that users like to see. Status Strips give the user feedback at a glance on the state of the application. The useful thing about them is that they can provide information that the user wants to know without interrupting the user's workflow.

There are other features that, while not strictly expected, are nice to see in an application. One that shortens the learning curve to using your application is ToolTips, which are helpful information boxes that appear when the mouse pointer is placed over a control. Another is a uniquely identifiable icon that distinguishes your program and can be represented as a distinct desktop or Start Menu icon. Depending on the nature of your application, users might also want to see that icon posted in the System Tray, which is typically on the right side of the Windows Taskbar.

In this chapter, you learn how to implement each of these features in your application. Two of the most popular features, however—menus and toolbars—have enough detail that I will save them for Chapter 4, "Working with Menus and Toolbars."

Specifying a Windows Starting Position

By default, Windows chooses the location where your application's windows are displayed. This can be, depending on Windows' own internal logic, in the middle of the screen or in some other location entirely. You can, however, control this behavior and ensure that your application always starts in the same position each time it is launched. The form's StartPosition property controls this behavior. You can set its values to any of the values shown in Table 3.1.

Table 3.1: Values Supported by the Form StartPosition Property
Property | Description
Manual | The form's Location property determines where the form is displayed, and the form's Size property specifies what its bounds are.
CenterScreen | The form is centered in the middle of the screen, and the form's Size property specifies its bounds.
WindowsDefaultLocation | This displays the form at a location that Windows chooses, but the form's Size property specifies its bounds.
WindowsDefaultBounds | This displays the form at a location that Windows chooses using bounds (size) that Windows chooses.
CenterParent | The form is centered within the bounds of its specified parent, which could be the Windows desktop or another form in the application.

The various options shown in Table 3.1 give you design time control over where the application will appear. They also allow you to determine whether your window's size relates to the bounds of the screen resolution that Windows is running in or an initial size that the application determines.

Specifying Windows Border Style

By default, users can, at runtime, resize the border of an application you create with Visual C++. Although this lets users customize the application to their liking, it can result in some undesired consequences. As you can see in Figure 3.6, an application that is resized can suddenly look unprofessional. The careful spacing you create the application with can be changed, resulting in far too much empty space on any given side of the window.

Image from book
Figure 3.6: Unless you specify otherwise, Visual C++ allows users to alter the size of your application's window.

You can prevent this situation by controlling the form's border style using the FormBorderStyle property. Table 3.2 lists the available FormBorderStyle properties that your application can use.

Table 3.2: Available Options for the FormBorderStyle Property
Value | Description
None | Displays the form without a border
FixedSingle | Sets up a fixed single-line form border
Fixed3D | Sets up a fixed three-dimensional form border
FixedDialog | Sets up a thick fixed-form border
Sizable | Sets up a resizable border
FixedToolWindow | Sets up a tool window border that cannot be resized
SizableToolWindow | Sets up a tool window border that can be resized
Hint

A tool window is one that does not appear in the Windows Taskbar when the application is running.

Dynamically Altering Title Bar Messages

Chapter 2, "Navigating the Visual C++ 2005 Express Edition Environment," introduced you to the form's Text property. This field controls the display of the application or window's name in the form's title bar, as shown in Figure 3.7.

Image from book
Figure 3.7: By default, Visual C++ displays a form's name in its title bar.

Normally, you set the form's Text property to display the title that you want at design time, using the Properties window. But you can also set it at runtime, as shown in the next listing.

private: System::Void button1_Click(System::Object^   sender,
          System::EventArgs^ e) {
          this->Text = "Speed Typing Game";
        }

In this example, a single programming statement is associated with the click event for button1. When the user clicks the button, the code updates the text in the title bar by assigning the string shown in quotes to the Text property, as illustrated in Figure 3.8.

Image from book
Figure 3.8: Programmatically changing the text string displayed in the window's title bar.
Trick

Note the use of the keyword this in the previous example. The this keyword in Visual C++ is used inside of an object to gain access to the object's own properties and code. In the previous listing, using this inside of the button1_Click function of form1 gives you access to all of form1's properties and functions.

Changing the contents of the text string for your application dynamically at runtime can be useful. You could, for instance, update a form's name to reflect the name of the file that a user has loaded. Microsoft Excel and Microsoft Word are two examples of applications that employ this technique whenever a user loads a new document. The advantage of doing this is that you use valuable and limited screen real estate to convey important information, but you do so without disturbing the user.

If you do use this capability, however, you should do so consistently and sparingly. In many applications, users do not expect dynamic changes to the text string displayed on the title bar. As such, they might not even notice that you've made a change unless changes are an expected convention of your application.

Trick

If you want to send the user frequent updates about the status of his work in an application, you should establish a Status Strip on your form, as discussed later in this chapter.

Controlling Tab Order and Focus

When users begin using your application, the most normal mode of interaction is to use the mouse to click or select the program's individual controls. However, in time, many users learn to use shortcuts to speed up their workflow. One such shortcut, used in many applications, is tabbing between controls. By pressing the Tab key on the keyboard, users can instantly switch to different controls. When they reach the control of interest, these power users normally, depending on the type of control, use a combination of arrow keys or the Enter key to set the control to the desired setting. This trick is especially common in applications that have numerous dialog boxes or dialog boxes that have a dense number of controls.

When the user repeatedly presses the Tab key, focus is said to move from control to control. The control in focus gives visual feedback in a way that is appropriate to the control's function. Buttons, for example, highlight, whereas text boxes often display a blinking cursor.

Hint

Focus is the state that defines a form's currently selected control, which accepts and processes keyboard input.

The tab ordering is determined by the way that you add controls to the form. Visual C++ keeps track of each control you place on a form by assigning it a tab index number. This means that the first control placed on a form is assigned an index number of zero, and subsequent controls are given a number that increases by one. So in theory, you could control the tab ordering on your application by keeping track of how you add controls to its form. But in practice, programmers find this a headache to manage. Instead, most prefer the freedom of designing their GUIs in a more freeform manner, adding, arranging, and even deleting controls as necessary and then specifying tab ordering later.

Trick

If you change the default setting of a control's TabStop property, you can cause the control to be skipped when the user tabs through your controls. By default, each control's TabStop property is set to True; setting the property to False causes your application to exclude it from its internal List.

One way that you can specify tab ordering is to do so manually. After you've added a control to a form, you can click on the control, open the Properties window, and locate the TabIndex property. By setting the property's value, you can control in which order your application gives it focus. If, for example, you give a control the value of 0, it is the first in focus when your application launches. You can then set the next control to a value of one higher, causing it to be the next in focus when the user presses the Tab key.

Manually assigning each control's TabIndex property has its drawbacks, however. One problem is that it can be a slow process to click on each control and scroll down to the correct property. Another is that it can be confusing to try to remember the ordering as you go along, which becomes more true when you build applications with many controls. The worst problem, however, is that manual specification doesn't prevent you from accidentally giving two or more controls the same index number. Visual C++ does not issue an error message in this case; instead, it reverts to some internal ordering scheme.

A faster way to specify the tab ordering is to place the IDE in a special mode that allows you to determine the order with a single mouse click on each control. To activate this mode, select the Tab Order option from the View menu. This tells Visual C++ to display boxed numbers in the upper-left corner of each control, which represent the ordering. See Figure 3.9 for an example.

Image from book
Figure 3.9: Modifying the default tab order of the controls Located on a Visual C++ form.

When the Tab Order viewing mode is selected, you can't move or otherwise edit your controls. When you click a control, however, you automatically alter its TabIndex property. The first control you click is assigned the value of 0, and each one thereafter is assigned a value of one greater. When you have clicked all controls, the count begins again, causing any control you click next to be assigned 0. After you are finished ordering all your controls, you can exit the Tab Order viewing mode by selecting its option a second time from the View menu.

Adding a Status Strip to Your Application

A great feature that can keep your users up to date on their work in your application is the Status Strip. A Status Strip is a window that displays real-time information as your application runs. It is typically located near the bottom of your application's window, but it can be positioned anywhere you expect the user to glance frequently as he is using your program. The information that is appropriate to put in a Status Strip depends on the type of application. A word processor, for instance, might show its user the current page number and line number, whereas a financial application might display the date and time of a particular transaction. Any information that you think the user will constantly want to know but not want to constantly look up is a good candidate for a Status Strip.

The StatusStrip control replaces the StatusBar control found in previous versions of Visual C++. It expands on the capabilities of the standard status bar by adding the ProgressBar, DropDownButton, and SplitButton controls.

Trick

Although the IDE automatically places the Status Strip at the bottom of the form by default, you can move it to any edge of the form by setting the Dock property, which supports any of the following values: Right, Left, Top, Bottom, and Fill.

A Status Strip can display different types of information, including hints, error messages, and icons. It can also be divided into panels that allow you to display different types of information. Figure 3.10 illustrates a form displaying time and date information.

Image from book
Figure 3.10: A Windows Status Strip displaying a time and date in two separate panels.

To add a Status Strip to your Visual C++ application, you must drag the StatusStrip control from the Toolbox to your application's form. After it's added, you can select the type of control you want to appear in the Status Strip by choosing one of the options shown in Table 3.3.

Table 3.3: Available Controls Within a StatusStrip Control
Control | Description
StatusLabel | A text string to be displayed in the Status Strip
ProgressBar | A visual meter that you can fill to reflect the portion of a task that has been completed
DropDownButton | A vertical list containing programmer-defined options that the user can select from
SplitButton | A programmer-defined menu of buttons that can have submenus of buttons

To better understand the Status Strip, let's create an example that uses two controls: StatusLabel and ProgressBar. This example shows you how to update text and the progress indicator dynamically.

  1. Create a new Visual C++ application.

  2. Add a Button control and a StatusStrip control to your application's form.

  3. Modify the button's Text property to Push Me.

  4. Select the statusStrip1 control, click the drop-down arrow, and select the StatusLabel control. This control, named toolstripStatusLabel1, is now part of your Status Strip.

  5. Modify the Status Label's Text property to read Push the button.

  6. Next, select the ProgressBar control by again clicking on the drop-down arrow. You will now have a ProgressBar control next to your StatusLabel control.

Press the F5 key to run your application. You should see that Push the button is displayed on the left in the Status Strip. Stop your application and return to Design mode. Now you will edit the controls you've added to the Status Strip using Visual C++'s Items Collection Editor. The Items Collection Editor, which is shown in Figure 3.11, makes editing controls easy. It groups all the information found in each control's Properties window in one screen and allows you to organize the position of controls. It also allows you to conveniently add and subtract controls.

  1. Click on the Status Strip control. (Be sure not to select one of the controls within it.)

  2. Under Data, locate the property named Items.

  3. Click the word (Collection) to reveal the ellipsis (…) button, and select it. The Items Collection Editor dialog box appears, as shown in Figure 3.11.

  4. Select the control named toolstripStatusLabel1.

  5. Set the BorderSides property to All.

  6. Modify the BorderStyle property from Flat to Sunken.

  7. Click on OK to close the Items Collection Editor.

Image from book
Figure 3.11: You can modify Status Strip controls directly or by using the Items Collection Editor.
Trick

You can also activate the Item Collections Editor by right-clicking on a Status Strip and selecting Edit Items.

Press F5 to run your application. The StatusLabel you added to your Status Strip is isolated in its own box, as is common in many applications. But the changes you can make to your Status Strip at design time are limited. To make the Status Strip truly useful, you must be able to alter its contents dynamically as your program runs. You can only do this in code.

To see an example of this, let's change the sample application's Status Strip information whenever the button is clicked. Double-click the button to bring up Visual C++'s Code Editor. Add the following code, shown in bold, which changes the text of the toolstripStatusLabel1 and toolstripProgressBar1 controls.

private: System::Void button1_Click(System::Object^  sender,
          System::EventArgs^  e) {
          toolStripStatusLabel1->Text = "Button Presses: ";
          toolStripProgressBar1->PerformStep();
        }

Press F5 to run your application again. The code you've added updates the ProgressBar dynamically by causing two of its controls to change in value each time the button1_Click function is activated. If you click on the button, you see the text within the status bar change to read Button Presses. Also, each time you press the button, the ProgressBar increments until the bar is filled. Figure 3.12 shows the result of several button presses.

Image from book
Figure 3.12: Status Strips provide an effective means of communicating important information as the application runs.
Trick

If you want, you can create Status Strip controls that respond to user clicks. Just as with any control, you can double-click on the controls you've added to a Status Strip. Visual C++ activates the Code Editor and generates a click event function for the control you want to edit. For example, you could alter the toolstripStatusLabel1 control in the previous example to change the wording when clicked.

private: System::Void toolStripStatusLabel1_C1ick
          (System::Object^  sender,
          System::EventArgs^  e) {
          toolStripStatusLabel1->Text = "Label Clicked!";
        }

Posting a Notify Icon in the System Tray

The NotifyIcon control allows you to update the System Tray with an icon, as shown in Figure 3.13. Placing an icon in the System Tray gives your user an alternative means of receiving updates or communicating with your Visual C++ applications. You might, for example, want to post an icon in the System Tray to allow your application to inform the user that an error has occurred. Or you might create an application that manages the user's screen resolution and which appears in the System Tray each time Windows is started. You can even program your application to perform certain behaviors when your user clicks on the icon.

Image from book
Figure 3.13: The Windows System Tray provides single- and double-click access to various Windows utilities, processes, and applications.
Hint

The System Tray is the area of the Windows Taskbar that contains icons and is positioned on the right side, usually just to the left of the system clock. By default, it contains volume control options and any number of other icons based on active system processes or utilities and applications you have installed.

You can add a NotifyIcon control to your application by selecting it from the Toolbox and dropping it onto your form. The NotifyIcon control, like the Timer control you added to the Click Race game in the previous chapter, appears just below your form, in the Component Tray. After it's added, you can access its properties, which include the following:

  • Icon. Specifies the name and location of the icon to be displayed n the System Tray

  • Text. Specifies text to be displayed as a ToolTip when the user moves the pointer over the icon

  • Visible. Enables or disables the display of the icon in the System Tray

By default, the Visible property is set equal to True at design time. This means that your application automatically posts the icon when it runs. However, even if you set the Visible property, you need to associate an icon with your application.

Here's an example to help illustrate how this works. Let's modify the sample application created in the previous section. When you follow the steps in the next section, the application posts an icon to the System Tray. It also can close when the user clicks the icon.

  1. Add a NotifyIcon control from the Toolbox to the form. It appears in the Component Tray.

  2. In the Properties window, set the Visible property to True.

  3. Currently the application has no System Tray icon associated with it. Next to the Icon property, click the word None. Then click the ellipsis button (…) that appears.

  4. In the Open File dialog box that appears, locate the file app.ico in the project's directory.

  5. Select the file, and select Open.

  6. Set the Text property to the name of your project. In this example, I'm simply using "Chapter 3 Example 1," but you can set the property to whatever message you like.

Try running your application by pressing F5. When the application launches, you see the icon appear in the System Tray. When you place your mouse cursor over it, you should also see the message you set in the Text property. Now let's add code to make it close the application when clicked.

Double-click the NotifyIcon control. This action causes Visual C++ to generate the notify Icon1_MouseDown function within Code Editor. Add the following code, in bold:

private: System::Void notifyIcon1_MouseDown(System::Object^
          sender, System::Windows::Forms::MouseEventArgs^   e) {
         Close();
      }

Again, press F5 to run the application. When the icon appears in the System Tray, click it. The application should close as a result. Obviously, this simple example isn't very useful, but it illustrates that you can control your program through the icon you post in the System Tray.

Leveraging the Convenience of Built-In Dialog Boxes

Many applications need to interact with their user to display information dynamically. Applications can present this information on a form or within a separate window. Visual C++ provides a convenient way of implementing separate windows in the form of dialog boxes. Often, you can initiate dialog boxes with minimal code. This section covers one of the simplest and easiest to implement.

The MessageBox::Show Method

You learned in previous chapters how to alter TextBox and Label controls to display information to the user as your application runs. But what if you need to give important information to them that you want to make certain they don't miss? A dialog box can be especially useful in this case. Applications frequently use dialog boxes to show information such as alerts, notices, and error messages.

To show a dialog box that displays a message, Visual C++ uses the MessageBox::Show method. The MessageBox::Show method is functionality provided by the .NET Framework to display standard Windows notification dialog boxes. It displays a window, an icon, and an optional number of buttons, as shown in the example in Figure 3.14.

Image from book
Figure 3.14: The MessageBox——Show method is perfect for displaying a small amount of text.

The MessageBox::Show method comes in a wide variety of formats. You can send it a simple text message consisting of a single line of text, or you can control the title of the message, the number of buttons, and the type of icon it uses. Actually, the MessageBox::Show method has exactly 21 different variants. Each of these variants indicates a different way to use the method. As an example, look at Figure 3.15 to see what happens when you type MessageBox::Show( (type just the opening parenthesis). IntelliSense activates, offering guidance on the possible formats. Note the up and down arrows bordering the text reading 1 of 21. You can use both arrows to scroll through all the different format possibilities.

Image from book
Figure 3.15: Twenty-one different formats of the MessageBox——Show methods are supported.

Regardless of which format you choose to use, all require the same basic information to execute. Table 3.4 illustrates the parameters required.

Table 3.4: Papameters Available to the MessageBox::Show Method
Parameter | Description
Text | The text string to be displayed in the pop-up window
Caption | The text string to be displayed in the pop-up window's title bar
Buttons | The button or group of buttons to be displayed in the pop-up window
Icon | The type of icon to be displayed in the pop-up window
DefaultButton | The button to serve as the default button
Options | Display options that affect how the pop-up window and its text are displayed

The Text and Caption parameters are simply text strings. You can place any message you like in quotes. The dialog box attempts to accommodate the size of the text you supply for the Text option of the message, but you should try to keep the message brief. This is even truer for the Caption option, which is limited to the width of the title bar and might be cut off if it's extremely long.

The Buttons parameter is slightly more complex. You can use it to specify any of six different sets of buttons. However, you access the options through a namespace that holds each of the button choices. To access this namespace, you must type MessageBoxButtons::, which reveals the types of buttons that the message box understands. IntelliSense automatically activates to show all options within the namespace. To create a dialog box with an OK button, for instance, type MessageBoxButtons::OK. Table 3.5 shows the available options.

Table 3.5: Buttons Available to the MessageBox::Show Method
Button | Description
AbortRetrylgnore | Displays an Abort, a Retry, and an Ignore button
OK | Displays an OK button
OKCancel | Displays an OK and a Cancel button
RetryCancel | Displays a Retry and a Cancel button
Yes/No | Displays a Yes and a No button
YesNoCancel | Displays a Yes, a No, and a Cancel button
Hint

A namespace holds and hides information that relates to a specific programming task, such as defining message box buttons. You access the hidden information by using the name of the namespace, followed by two colons.
Trick

Whenever you see two colons dividing two words in Visual C++ code, you are seeing a namespace being used. Namespaces are a central feature of Microsoft Visual C++ 2005 Express Edition that provides access to almost all the functionality of .NET. IntelliSense reveals all the code and data options available within a namespace as soon as you type a namespace it recognizes followed by two colons.

The MessageBox::Show method also allows you to display an icon. Icons provide users with quick visual feedback as to the nature of the dialog box you have presented. You access the message box icons through the MessageBoxIcon namespace. If you type MessageBoxIcon::, IntelliSense activates, showing several options. For example, to have your dialog box display an error icon, you type MessageBoxIcon::Error. Table 3.6 identifies the various icons supported.

Table 3.6: Icons Available to the MessageBox::Show Method
Button | Description
Asterisk | Displays an Asterisk icon
Error | Displays an Error icon
Exclamation | Displays an Exclamation Mark icon
Hand | Displays a Hand icon
Information | Displays an Informational icon
None | Displays the pop-up window without displaying an icon
Question | Displays a Question Mark icon
Stop | Displays a Stop icon
Warning | Displays a Warning icon

Visual C++ also allows you to specify which button is the default. This is a convenience that allows the users to simply press Enter to select the most likely response to the dialog box you present them with. You specify which button to make the default button by position, prefacing the button name with MessageBoxButton::.If, for instance, you have a dialog box that has both an OK and a Cancel button and you want the focus to be on the Cancel button by default, specify MessageBoxButton::Button2. (You might need to look at how each dialog box uses the various button options to determine which is the first, second, and if applicable, third button.) Table 3.7 lists the available selections.

Table 3.7: Default Button Value Options for the MesageBox::Show Method
Button | Description
Button1 | Makes the first button the default
Button2 | Makes the second button, if present, the default
Buttons3 | Makes the third button, if present, the default

You can also specify any of the values listed in Table 3.8 for the Options parameter. You must preface these by the specifying code MessageBoxOptions::. For example, if you want to right align the text, specify MessageBoxOptions::RightAlign.

Table 3.8: Options Values for the MessageBox::Show Method
Button | Description
DefaultDesktopOnly | Displays the pop-up window on the active desktop
RightAlign | Displays the text in the pop-up window as right aligned
RtlReading | Displays the text in the pop-up window as left aligned

To help make the Messagesox:: Show method a bit easier to understand, look at a few code examples that you can use in your own code. The first creates a pop-up window that asks the user a question, displaying Yes and No buttons and the Stop icon. The Yes button is the default button, and the text is aligned to the right (including the caption text).

MessageBox::Show("Click on Yes to continue or No to Stop.",
                   "MessageBox::Show Example 1",
                   MessageBoxButtons::YesNo, MessageBoxIcon::Stop,
                   MessageBoxDefaultButton::Button1,
                   MessageBoxOptions::RightAlign);

When executed, this example generates the pop-up window shown in Figure 3.16.

Image from book
Figure 3.16: Prompting the user for permission to continue.

Next, let's look at an example using only two parameters. As the following statements show, the MessageBox::Show method is supplied with only the Text and Caption parameters.

MessageBox::Show("This is an informational message.",
                   "MessageBox::Show Example 2");

When executed, this example generates the pop-up window shown in Figure 3.17.

Image from book
Figure 3.17: Displaying a simple informational message.

In addition to displaying informational messages, you can use the MessageBox::Show method to capture the user's response, as demonstrated in the following example.

Windows::Forms::DialogResult buttonClicked;
button Clicked = MessageBox::Show("Please click on a button",
                                     "MessageBox::Show example 3",
                                     MessageBoxButtons::AbortRetryIgnore);
MessageBox::Show( String::Concat( "You clicked on the ",
                    buttonClicked, " button." ) );

In this example, the user is asked to click on one of the three buttons that the pop-up window displays. A value representing the button that the user clicked is assigned to a variable name buttonClicked. When the user selects from the three buttons that are presented, a second MessageBox::Show method is called to display the user's response. Figure 3.18 shows the first dialog box displaying the three available options, and Figure 3.19 illustrates one of the choices being made.

Image from book
Figure 3.18: Prompting the user to select from three options.
Image from book
Figure 3.19: Viewing the results of the button selection the user made.
Hint

A variable stores data (such as a string or integer) needed by your application as it runs.

As you can see in Figure 3.19, the MessageBox::Show method displays the name of the button clicked. Table 3.9 defines the range of values that the MessageBox::Show method might perform. These values are found in the DialogResult namespace. To access this namespace, type Windows::Forms::DialogResult. (As you can see by the number of double semicolons, DialogResult is contained within the Forms namespace, which in turn is contained within the Windows namespace.)

Table 3.9: Return Values Associated with the MessageBox::Show Method
Value | Description
OK | The OK button was pressed.
Cancel | The Cancel button was pressed.
Abort | The Abort button was pressed.
Retry | The Retry button was pressed.
Ignore | The Ignore button was pressed.
Yes | The Yes button was pressed.
No | The No button was pressed.
None | The dialog box was closed without a button being pressed.


CREATING A STANDALONE EXECUTABLE

All the sample applications you have created so far have worked within the Visual C++ IDE. This version of your application is referred to as the debug version. Debug versions are meant to allow you to test your application. However, when you are ready to officially release your application, you want to give users a standalone program designed to be run by itself, outside of the IDE. This requires that you generate a release version of your application (also sometimes called a runtime version).

Trick

The executable file that Visual C++ creates and stores in the Debug folder of your project is not optimized for normal execution. It includes information that allows Visual C++ to provide hints and help on how the program is running. When the application is running outside of the Visual C++ IDE, this information is unnecessary and can even slow down your program in some cases. So although you can distribute this executable file, the release is often smaller and more efficient.

When you are ready to generate the release version of your application, you need to change its build configuration options. You do this by selecting Configuration Manager from the Build menu. Figure 3.20 shows the dialog box that appears. To create a release build, select Release from the Active Solution Configuration drop-down list. Then select Rebuild Solution from the Build menu. In your project's folder, you will have both a Release and a Debug folder. Inside it is a version of your application that can be released to others.

Image from book
Figure 3.20: The Configuration Manager allows you to build debug or release versions of your application.


BACK TO THE SPEED TYPING GAME

Now that you have a good introductory foundation on creating an application interface, it is time to move on to this chapter's game project. The Speed Typing game will be created using the same five steps covered in previous chapter projects. When you are finished, you will have created a game that uses many of the techniques outlined in this chapter in one complete application.

Designing the Game

The Speed Typing game runs in a single window. It is composed of one form and the 12 controls listed in Table 3.10.

Table 3.10: Form Controls for the Speed Typing Game
Control Type | Control Name | Description
Label | lblInstructions | Instructions on how to play the game
Label | lblSourceText | The Textbox field containing the current sentence that the player must copy
Label | lblEntryText | The Textbox field where the player must type the matching sentence
TextBox | txtDisplay | TextBox control that contains the source text string to copy
TextBox | txtEntry | TextBox control that contains the player's typed input
Button | btnGo | Button control that the player uses to start the game
Button | btnDone | Button control that the player clicks when finished typing a sentence
Button | btnExit | Button control that the player clicks to end the game
Timer | tmrControl | Timer control that controls the amount of available time to type In each sentence
ToolTip | tipControl | ToolTip control that allows the game to display ToolTip messages
StatusStrip | stsControl | StatusStrip control that holds the StatusLabel control
StatusLabel | stsLabel | StatusLabel control that is used to display messages as the game runs

Step 1: Creating a New Visual C++ Project

To start developing the Speed Typing game, you must first open a new project in Visual C++ by following these steps:

  1. If you have not already done so, launch Visual C++ 2005 Express and then click on File and select New Project. The New Project dialog box appears.

  2. Select the Windows Forms Application template.

  3. Type The Speed Typing Game as the name of your new application in the Name field located at the bottom of the New Project window.

  4. Click on OK to close the New Project dialog box.

Step 2: Creating the User Interface

Next, begin by adding the necessary elements that will make up the game's user interface. The following list describes the steps you need to follow to set up the application's GUI:

  1. Expand the form so that it can accommodate a wide text box.

  2. Add the ToolTip control to your form. By default, Visual C++ assigns the control a default name of toolTip1. It is displayed at the bottom of the Form Designer window in the Component Tray.

  3. Add the Timer control to your form. By default, it is assigned a name of timer1 and is displayed in the Component Tray.

  4. Add a TextBox control to the form. Its default name is textBox1. Expand and reposition it in the middle of the form.

  5. Add a second TextBox control to the form. Its default name is textBox2. Expand and reposition it under the previous TextBox control.

  6. Add a Label control to the upper-left corner of the form. Its default name is label1.

  7. Add a second Label control to the form just above the first TextBox control. Its default name is label2.

  8. Add a third Label control to the form just above the second TextBox control. Its default name is label3.

  9. Add a Button control to the lower-left corner of the form. Its default name is button1.

  10. Add a second Button control to the lower-right side of the form. Its default name is button2.

  11. Add a third Button control to the upper-right corner of the form. Its default name is button3.

  12. Add a StatusStrip control to your form. Its default name is statusStrip1.

  13. Click once on the StatusStrip control and select the StatusLabel control from the drop-down list. By default, its name is toolStripStatusLabel1.

Step 3: Customizing Form and Control Properties

The controls need to be customized. As in the previous chapter games, you can customize the controls using the Properties window. You can also customize the control names so that the name appears in the code that Visual C++ generates. By customizing the control names, your code becomes more logical and organized.

Image from book
IN THE REAL WORLD

The way that you name code depends on the naming convention you choose to follow. A naming convention is a consistent way of spelling out the important aspects of your code, such as events that your application needs to respond to or the way that program statements reference data. Naming conventions make programs easier to read and understand because the spelling and formatting provide reliable hints as to how the code works.

Before I explain the naming convention I will be using in future chapters, you need to understand a few rules about what sort of names Visual C++ accepts. These rules include the following:

  • Names must begin with either an alphabetic character or the underscore character (_).

  • Names can only consist of alphabetic characters, numbers, and the underscore character (_).

  • Names cannot match Visual C++ keywords.

Following a naming convention is often considered a mark of professionalism because in professional environments programmers often have to read and understand each other's code. Many different naming conventions are available for you to follow, each of which has its proponents and critics. To get used to using a naming convention, you should first become comfortable with being consistent about how you spell the names of controls, objects, or other custom coding statements that you write in your program. Try, for example, to make them descriptive and clear in terms of function and purpose.

Programmers often follow a consistent spelling in identifying variables. You have several patterns to choose from. One that I have used for quite some time and will use throughout the examples in this book is called camelCase. This style of naming variables is popular and derives from the "hump" that capitalizing words in the middle creates. The format for camel-Case involves using two or more words, run together, often with some words within the name shortened by common abbreviations.

Working with the names that Visual C++ assigns to form controls can be challenging to remember, especially if you add a lot of controls to your application. So instead of generic names, I'll strive to assign a descriptive name to form elements that describes their function. For example, I might assign a name of btnExit to a button that is responsible for exiting an application If clicked. Or I might assign a name of txtInputName to a TextBox control intended to collect a user's name.

Image from book

Let's start customizing the form and all the controls that you have added to it. Begin by modifying Form1, changing the properties listed in Table 3.11.

Table 3.11: Property Changes for the Form
Property | Value
FormBorderStyle | FixedSingle
Icon | app.ico [1]
StartPosition | CenterScreen
Text | Speed Typing
[1]You can find I con. ico by default in the debug directory of any project you create.

Next, set the Name property of the ToolTip control to tipControl. Then change the Name property of the Timer control to tmrControl and set its Interval property to 1000.

Then modify the properties belonging to the two TextBox controls, as shown in Table 3.12.

Table 3.12: Property Changes for the TextBox Controls
Control | Property | Value
textBox1 | Name | txtDisplay
 | ReadOnly | True
 | ToolTip | Displays source text string
textBox2 | Name | txtEntry
 | ReadOnly | True
 | ToolTip | Type your text here

Next change the properties belonging to the three Label controls, as shown in Table 3.13.

Table 3.13: Property Changes for the Label Controls
Control | Property | Value
label1 | Name | lblInstructions
 | Text | Click Go to begin. You have 15 seconds to type the text displayed in the Source Text field exactly as shown.
label2 | Name | lblSourceText
 | Text | Source Text:
label3 | Name | lblEntryText
 | Text | Enter Text Here:

Modify the properties belonging to the three Button controls, as shown in Table 3.14.

Table 3.14: Property Changes for the Button Controls
Control | Property | Value
button1 | Name | btnGo
 | Text | Go
 | ToolTip | Display new text string
button2 | Name | btnDone
 | Enabled | False
 | Text | Done
 | ToolTip | Check typing
button3 | Name | btnExit
 | Text | Exit
 | ToolTip | Exit game

Then modify the Name property of your StatusStrip control to stsControl. Finally, change the Name property of the toolStripStatusLabel control within the tool strip to stsLabel. These are all the control property modifications that you must make for the Speed Typing game.

Step 4: Adding a Little Programming Logic

Now it is time to begin coding. To give the Speed Typing game life, you need to add code in five places, including the btnGo, btnDone, btnExit, and tmrControl controls. In addition, you need to add a few lines of code to define some variables.

Trap

It's a bit too early to start discussing the statements that make up the Visual C++ programming language as of yet. You might not be able to understand everything that you'll see, but at this stage, you only need to key in what you see and follow along. Starting with Chapter 5, "Storing and Retrieving Data in Memory," we will be covering the specifics of what you see in greater detail so that by the time you return to this chapter, you will fully understand what is going on.

For starters, select the Code option from the View menu. The Code Editor appears. You see many lines that Visual C++ has generated for your application automatically. Don't worry if you don't understand what the lines mean at this point—the code will become clearer as you learn more.

Trick

Although it might seem somewhat unintelligible at this point, much of the code that you see is the result of the settings you've chosen in Design view. Almost all the Design view settings must have some code equivalent. This code that Visual C++ automatically generates actually turns your Design view settings into the behavior that drives your application.

At present, you should be at the top of the form's code, at a line that reads as follows:

namespace TheSpeedTypingGame

Scroll down and locate the section that reads like this:

private:
  /// <summary>
  /// Required designer variable.
  /// </summary>

Right below this section, add the following lines (which have been highlighted in bold):

private:
  /// <summary>
  /// Required designer variable.
  /// </summary>
  Int16 intWrong;  // Tracks number of strikes
  Int16 intCount;  // Tracks number of tries
  Int16 intTimer;  // Tracks elapsed time

These three statements define the variables that the game uses to track the number of strikes made by the player, the number of tries the player has made, and the amount of time that has elapsed for each turn. But before the program can use these values, the values must be initialized. One place to do this is in the Form1_Load event. To place the appropriate statements, switch back to the Form Designer and double-click the form. Your cursor is positioned at code that looks similar to the following example:

private: System::Void Form1_Load(System::Object^ sender,
          System::EventArgs^  e) {
         }

To allow the application to keep track of the game information it needs, add the lines shown in bold in the next listing.

private: System::Void _Form1_Load(System::Object^ sender,
          System::EventArgs^ e)   {
         //Set beginning data values
         intWrong = 0;
         intCount = 0;
         intTimer = 0;
       }

Next, return to the Form Designer and double-click on the btnGo button. This switches you back to the Code Editor, where the following new code has been added:

private: System::Void btnGo_Click(System::Object^
          sender, System::EventArgs^ e)   {
          }

This code identifies the program statements that run when the user clicks on the btnGo button. At the moment, it is empty and does nothing. To add code to this portion of your application, enter the programming statements shown next between these two statements:

private: System::Void btnGo_Click(System::Object^ sender,
System::EventArgs^  e) {
        // Display game sentences according to level
        if( intCount == 0 )
          txtDisplay->Text = "Once upon a time there "
          "were three little pigs.";
        if( intCount == 1 )
          txtDisplay->Text = "In days gone by times "
          "were hard but the people were strong.";

        if( intCount == 2 )
          txtDisplay->Text = "Once in awhile something "
          "special happens even to the worst of people.";
        if( intCount == 3 )
          txtDisplay->Text = "When injustice rears its "
          "ugly head, it is the duty of all good "
          "citizens to object.";
        if( intCount == 4 )
          txtDisplay->Text = "It has been said that in "
          "the end there can only be one. Let that "
          "one be Mighty Molly!";
        btnDone->Enabled = true; // Activate Done button
        btnGo->Enabled = false;  // Disable Go button
        // Allow text to be entered
        txtEntry->ReadOnly = false;
        // Activate timer
        tmrControl->Enabled = true;
        intTimer = 0;
        txtEntry->Focus();
      }

The first five statements beginning with the Visual C++ keyword if test what level the game is currently running at (0-4) and display the correct text in the txtDisplay control. For example, if this is the player's first turn, then "Once upon a time there were three little pigs" is shown.

The next two statements enable the btnDone button and disable the btnGo button. Next, the txtEntry control's Readonly property is set equal to True to allow the player to begin typing text into it. Then the tmrControl is enabled and the value of intTimer is set equal to 0. This begins the 15-second countdown sequence. Finally, the Focus() method causes the cursor to be placed automatically in the txtEntry field each time it's encountered.

Trick

The Focus method determines in code which control receives focus. This effectively sets the current active control.

Return to the Form Designer window and double-click on the btnDone button. This switches you back to the Code Editor, where code for the btnDone control's click event has been added, as shown next.

private: System::Void btnDone_Click(System::Object^ sender,
System::EventArgs^  e) {
     }

Add the following statements between these two statements:

//Clear Out Status Bar Text
stsControl->Text = "";
// Deactivate timer so it doesn't keep going
tmrControl->Enabled = false;

The first statement, as you can see from the comments, clears out any text that might be displayed in the StatusStrip. The second statement disables the game's Timer control to prevent it from counting down and eventually declaring a strike at 15 seconds.

Next, add the following statements just beneath the previous statements:

// Make sure player entered something
if( String::IsNullOrEmpty( txtEntry->Text ) )
{
   // Show error
   MessageBox::Show(
   "Error: You must enter something!" );
   // Reset game
   txtDisplay->Text = "";
   btnDone->Enabled = false;
   btnGo->Enabled = true;
   txtEntry->ReadOnly = true;
   intTimer = 0;
   btnGo->Focus();
   return;
}

This block of code checks to ensure that the player has typed something into the txtEntry field. If the user has entered anything, the indented statements contained within the opening { and closing } braces execute, displaying an error message and resetting all the controls back to their initial settings. Note the use of the return statement just before the final brace. The return statement tells Visual C++ to stop processing any of the remaining statements in the btnDone control's click event. This is appropriate because it's useless to perform further processing if the player has not typed anything.

Next, add the following statement just beneath the previous statements:

if( String::Compare( txtEntry->Text, txtDisplay->Text )
  == 0  )
{
  // Handle correct answer
  MessageBox::Show( "Match! You typed the string in "
  " correctly!" );
  intCount += 1;
  intTimer = 0;
}
else
{
  // Handle incorrect answer
  intWrong += 1;
  MessageBox::Show( String::Concat( "Strike ",
    intWrong.ToString(), "! You made at least", "
    " one typo." ) );
  intTimer = 0;
}

These statements compare what the player has entered with the string to be copied. The two pieces of text must match exactly. The code starts by determining if the text string currently stored in the txtEntry control compares to the text string stored in the txtDisplay control. If a match exists, the MessageBox::Show method is used to inform the player, and the game adds 1 to the number of turns of levels the player has completed and resets the variable used by the Timer control (to track the number of seconds that a turn has lasted) back to 0. However, if the text stored in the two controls does not match, an error message is displayed, and the game adds 1 to the number of strikes made by the player before resetting the intTimer variable back to 0.

Now add the following statements just beneath the previous statements:

// Get set up for next level
txtEntry->Text = "";
txtDisplay->Text = "";
btnDone->Enabled = false;
btnGo->Enabled = true;
txtEntry->ReadOnly = true;
intTimer = 0;
btnGo->Focus();

These statements reset the form's controls to their starting settings and shift the focus back to the btnGo control. This allows the player to attempt to match the sentences again.

Add the following statements just beneath the previous statements:

// Handle three strikes
if( intWrong == 3 )
{
  // Inform player he's a beginner
  if( intCount < 2 )
  {
    MessageBox::Show( "Game Over! Your "
    "typing skill level is: Beginner. "
    "Please play again!" );
    intCount = 0;
      intWrong = 0;
    return;
  }
  // Inform player he's Intermediate
  if( intCount < 4 )
  {
    MessageBox::Show( "Game Over! Your "
    "typing skill level is: Intermediate. "
    "Please play again!" );
    intCount = 0;
    intWrong = 0;
    return;
  }
  // Inform player he's advanced
  if( intCount < 5 )
  {
    MessageBox::Show( "Game Over! Your "
    "typing skill level is: Advanced. "
    "Please play again!" );
    intCount = 0;
    intWrong = 0;
    return;
  }

This code appears a little more complicated, but it is really only performing tests and displaying messages as a result. Each time the player clicks on the btnDone button, the game tests whether the player has struck out or if all five levels have been completed. These statements toward the end determine whether the player won the game and, if so, display the correct reward message. If, on the other hand, the player earned three strikes, the game assigns a skill level rating according to his score.

Now it's time to add a really simple code statement to the btnExit control, as shown next:

private: System::Void btnExit_Click(System::Object^   sender,
System::EventArgs^  e) {
        this->Close();
      }

The last control that the game needs is the Timer control. Switch back to the Design view and then double-click on the tmrControl control. This returns you to the Code Editor, where the following new code has been added:

private: System::Void tmrControl_Tick(Systern::Object^
sender, System::EventArgs^  e) {
      }

Modify this section of your application by adding the following statements inside these statements:

// Update timer value
intTimer += 1;
Int16 intTimeRemain = 15 - intTimer;
stsLabel->Text = "Seconds remaining: ";
stsLabel->Text = String::Concat( stsLabel,
                  intTimeRemain.ToString() );
// Handle running out of time
if( intTimer == 15 )
{
  intWrong += 1;
  tmrControl->Enabled = false;
  stsLabel->Text = "";
  MessageBox::Show( String::Concat( "Strike ",
  intWrong.ToString(), " - Time is up! Please",
  " try again." ) );
  // Reset game

  txtEntry->Text = "";
  txtDisplay->Text = "";
  btnDone->Enabled = false;
  btnGo->Enabled = true;
  txtEntry->ReadOnly = true;
  intTimer = 0:
  btnGo->Focus();
// Handle three strikes
if( intWrong == 3 )
{
  // Inform player he's a beginner
  if( intCount < 2 )
  {
    MessageBox::Show( "Game Over! Your "
    "typing skill level is: Beginner. "
    "Please play again!" );
    intCount = 0;
    intWrong = 0;
    return;
  }
  // Inform player he's Intermediate
  if( intCount < 4 )
  {
    MessageBox::Show( "Game Over! Your "
    "typing skill level is: Intermediate. "
    "Please play again!" );
    intCount = 0;
    intWrong = 0;
    return;
  }
  // Inform player he's advanced
  if( intCount < 5 )
  {
    MessageBox::Show( "Game Over! Your "
    "typing skill level is: Advanced. "
    "Please play again!" );
    intCount = 0;
    intWrong = 0;

      return;
    }
  }
  // Player is an expert!
  if( intCount >= 5 )
  {
     intCount = 0;
     intWrong = 0;
    MessageBox::Show( "Game Complete. Your "
    "typing skill level is: Expert! '"
    "Please play again!"   );
  }
}

The first statement adds 1 to the variable used by the Timer control to track the number of seconds that the current play has lasted. The next helps keep a running count of how much time the player has left. After that, the sentence to become the status label is assigned its first value: Seconds remaining. With its value set, the next statement builds the text statement by adding different sentences. The result is shown in the Status Strip.

Each second that the game runs, the Timer control executes automatically. The statements following those related to the Status Strip statement check to see if 15 seconds have elapsed. If so, a strike is declared on the player by adding 1 to the variable used to track the number of failed attempts. The Timer control then disables itself, clears out any text displayed on the Status Strip, and uses the MessageBox::Show method to tell the player that time has expired.

The rest of the code that you added to the tmrControl control's click event determines whether the conditions have been met for game over. They are nearly identical to the ones you added to the btnDone control's click event.

Step 5: Testing the Execution of the Speed Typing Game

Now it's time to test the application. Press F5 to launch it. If errors occur, go back and double-check the code statements that you added to make sure you did not make typos.


SUMMARY

In this chapter, you learned how to add a professional touch to the GUIs you will create for Windows applications. Some of the techniques you learned included how to implement several standard Windows features, such as ToolTips, Status Strips, System Tray functionality, and adding customized icons to your application. You also learned how to control your application's starting location and border style. Finally, you gained an understanding of how to use useful information display dialog boxes in the form of the MessageBox::Show method.

Before moving on to the next chapter, take a moment to test your knowledge of what you learned by implementing the following challenges.


CHALLENGES

  1. Try adding new levels to the game, making sure that each one is more challenging than the one that precedes it.

  2. Improve the game's skill level rating by assigning an individual rating to each level the player successfully achieves.

  3. Modify the game so that it displays an icon in the System Tray whenever it is minimized. Provide the ability to redisplay the game when the player clicks on its System Tray icon.


Chapter 4: Working with Menus and Toolbars

OVERVIEW

In this chapter, you learn how to add menus and toolbars to your Visual C++ applications. Menus and toolbars are an excellent way to expand on the functionality of your application and pack a great number of features into an easily accessible interface. They also increase your users' productivity by making it easier for them to gain access to the features that your application provides.

This chapter covers several aspects of creating menus. First, you learn how to fill out a menu with options. Then you learn how to attach program code to the options that your menu provides. This chapter also addresses how to build submenus that branch from the main menus you create. In addition, you learn how to accelerate your users' workflow by adding productivity-enhancing shortcuts and access keys.

As you work through this chapter, you learn how to enable and disable menu items and how to make them appear and disappear. The coverage also includes how to create context menus for specific controls and how to provide easy access to your application's most commonly used commands using toolbars. Finally, you gain an opportunity to put these techniques into practice via the completion of this chapter's game project, the Lottery Assistant game.

In this chapter, you learn the following:

  • How to add a menu system to your application

  • How to add shortcuts and access keys to menu items

  • How to control when users can access menu items

  • How to create context menus for individual controls

  • How to add toolbars to your applications


PROJECT PREVIEW: THE LOTTERY ASSISTANT GAME

In this chapter, you learn how to create a Visual C++ game called the Lottery Assistant. This application is designed to aid users in creating a list of randomly generated lottery numbers. Players have control over several graphical options for the game, including the font size used to display game output and the game window's background color.

The range of numbers that a lottery game should display depends on the type of game being played. Some games, for example, might require the selection of numbers in the range of 1 to 36, whereas others might set the range as 1 to 50. Lottery games also vary in the number of lottery numbers (picks) required to play. Some games, for instance, require 5 numbers, whereas others might require 7 or even 10 numbers. The Lottery Assistant is designed to deal with these variations. It allows players to specify the following:

  • The range of numbers to select from

  • The number of lottery numbers required to play the lottery game

  • The number of sets of lottery numbers they want generated

To play the game, the player first provides this information in text fields. Then, to make the game run, the player clicks on the appropriate menu item. Figures 4.1 through 4.6 illustrate the overall flow of the Lottery Assistant game.

Image from book
Figure 4.1: The Lottery Assistant game begins by collecting player input.
Image from book
Figure 4.2: Players control the game using its menu system.
Image from book
Figure 4.3: Up to 10 sets of lottery numbers can be generated at a time.
Image from book
Figure 4.4: Players can configure the game's background color.
Image from book
Figure 4.5: Using the Font Size submenu, the user can specify the font size used to display lottery numbers.
Image from book
Figure 4.6: By clicking on the About menu item located on the Help menu, players can learn more about the game.

As a result of creating this game, you'll have learned how to create your own menu system, complete with menus, menu items, submenus, access keys, and shortcuts.


DESIGNING A MENU SYSTEM

A menu system is one of the most standard features of any Windows application. Menus provide a compact way to organize the commands that make your Visual C++ applications work.

Menus are convenient because they save users space. Often, they take up only a single line at the top of many applications. In fact, they really only occupy space when activated. When a user finishes accessing a menu, it closes and returns control of the program to the user. This helps to free up valuable desktop space for other tasks.

Figure 4.7 shows a typical Windows application menu system. As you can see, it consists of many different features.

Image from book
Figure 4.7: This menu illustrates the contents of the Visual C++ Express 2005 File menu.

Windows application menu systems generally consist of one or more of the following six menu features, each of which is visible in Figure 4.5. These six menu features include the following:

  • Menus. These are the first, or high-level, menu items that are immediately visible from the menu bar. Examples include File, Edit, and Help.

  • Menu items. These are additional menu items residing under menus, each of which represents a choice that users can make.

  • Submenus. These are collections of menu items accessed through a parent menu item. You can identify submenus by the black arrow on the right end of the menu item that provides access to them.

  • Shortcuts. These are keyboard characters, such as the F1 key, that can be used to access menu items.

  • Access keys. These are keyboard keys that, when used in conjunction with the Alt key, activate a menu or menu item.

  • Separators. These are horizontal lines used to organize menu items into logical groups.

Image from book
IN THE REAL WORLD

Most users have enough experience with Microsoft Windows that they expect certain minimal standards from the applications that they use. They have come to expect that all Windows applications work in certain similar ways. Any application that fails to meet these expectations runs the risk of disappointing its target audience, no matter how well designed it might be. One major expectation that most Windows users have is that Windows application menus will perform the same way across applications. For example, users have come to expect to see menu headings such as File, Edit, and Help. The File menu, for instance, is generally expected to be first in the menu's list, and Help is often listed last. Options for opening, closing, printing, exiting, and so on typically are located on the File menu. The Exit command is expected to be the last menu item on the File menu. You should avoid upsetting this traditional expectation unless your application has an overriding need to do so.

Image from book


ADDING MENUS, MENU ITEMS, AND SUBMENUS

The first step in adding a menu system to a Visual C++ application is to select the MenuStrip control from the Toolbox and add it to your form. Doing so creates an instance of the control to the Component Tray. After this control is a part of your form, you can begin defining menus, as demonstrated in Figure 4.8.

Image from book
Figure 4.8: You can use the MenuStrip control to add a menu system to a Visual C++ application.

The following steps illustrate the process of adding a menu system to your Visual C++ applications.

  1. Open your Visual C++ application and select the form to which you want to add a menu system.

  2. Add the MenuStrip control to your form.

  3. Click on the Type Here text that is displayed, and type the name of the first menu that you want to define, as demonstrated in Figure 4.9.

  4. To create an additional menu, click on the Type Here text shown just to the right of the first menu heading and type the name of the menu, as demonstrated in Figure 4.10.

  5. To add a menu item under a particular menu, click on the menu, click on the Type Here text that appears just underneath it, and type in the name of the menu item, as demonstrated in Figure 4.11.

  6. To create a submenu, select the menu item that will provide access to the submenu. Then click on the Type Here text located just to the right of the menu item and type the name of the first menu item in the submenu. Then, to complete the submenu, continue clicking on the Type Here text displayed under each new menu item in the submenu, adding as many menu items as required. (See Figure 4.12.)

  7. Repeat steps 4 through 6 as many times as necessary to assemble your application's menu system.

Image from book
Figure 4.9: The first menu heading in the application's menu system is defined by typing its name.
Image from book
Figure 4.10: Additional menus can be added to the application's menu system.
Image from book
Figure 4.11: Menu items can be added by typing in the boxes under a menu heading.
Image from book
Figure 4.12: Entering text automatically enables you to add submenu items to the menu system.

One way to make your menus look more professional is to be consistent in how you spell each element. Always be sure that the first letter in each menu or menu item is a capital letter. Also, add an ellipsis (…) to the end of any menu name that, when selected, provides access to another window.

Trick

After you've started defining your menu items, you're not stuck with their position. You can select a menu item and quickly rearrange it by using drag-and-drop to move it to a new location. You can also right-click on it and select Delete to remove it.
Trick

If you want, Visual C++ can help you start putting together a generic menu system that includes menus and menu items standard to most Windows applications. To use this feature, add the MenuStrip control to a form, right-click on the control, and select Insert Standard Items. In response, you end up with a standard menu system like the one shown in Figure 4.13.

Image from book
Figure 4.13: Visual C++ allows you to insert a standard menu system into a form.

Associating Code Statements with Menus and Menu Items

Just as you have done with other controls, you can give menu items code by double-clicking on them. When you do so, the IDE creates a new click event function for the item and positions the cursor so that you can begin entering your code statements.

For example, Figure 4.14 illustrates the standard menu added in the previous example. You can add code by double-clicking on any item. You can, for example, associate the following code with the Exit menu to close the application.

Image from book
Figure 4.14: Clicking any menu item allows you to easily add code to it.
private: System::Void exitToolStripMenuItem_Click(System::Object^
          sender, System::EventArgs^  e)
          {
            Close();
          }

Enhancing Windows Menus

As shown in the following list, you can do a variety of things to make your menu systems easier and more convenient for users:

  • Adding shortcut keys

  • Adding access keys

  • Adding and removing check marks

  • Organizing menu items using separator bars

Adding Shortcut Keys

Shortcut keys allow users to access menu items using only the keyboard. This can give your users a boost in productivity. You can use shortcuts to quickly initiate commonly used application commands. Examples of shortcut keys include all the function keys (F1 to F12) and keystroke combinations such as Ctrl+N and Ctrl+O.

Hint

Some shortcut keys have become so common that they are now a de facto standard for Windows application commands. Examples include Ctrl+S for saving and Ctrl+X for exiting an application. Make sure that you use these shortcuts when appropriate in your applications.

Adding a shortcut to a menu item is straightforward, as outlined here:

  1. Select the menu containing the menu item that you want to work with.

  2. Select the appropriate menu item.

  3. Click on the value field that is associated with the Shortcut property (in the Properties window) and select one of the shortcuts displayed in the drop-down list, as demonstrated in Figure 4.15.

Image from book
Figure 4.15: You can specify the shortcut you want to assign to a menu or menu item.

After you select the shortcut, it's immediately visible, as demonstrated in Figure 4.16.

Image from book
Figure 4.16: You can specify shortcut keys to activate menus and menu items.

Adding Access Keys

Access keys are another method for allowing users to activate specific menu items using their keyboard. To establish an access key, preface one of the characters in a menu's or menu item's name with a special character. You can identify access keys by their underscore character under the letter in the menu or menu item's name. For example, the letter F is generally used as the access key for the File menu.

To use an access key, all you have to do is press and hold the Alt key while simultaneously pressing the appropriate letter key. For example, to open the File menu in Visual C++ Express 2005, just press and hold Alt and F at the same time. While the File menu is displayed, you can release the Alt key and press the access key for any menu item located under the File menu to access it.

The following steps outline the process involved in adding access keys to your Visual C++ menu and menu items.

  1. Select the menu heading or menu item that you want to work with.

  2. Position the cursor in front of the letter in the menu or menu item name that you want to designate as the access key.

  3. Add the ampersand ( & ) character in front of the selected letter (for example &File or E&xit). The results are immediately visible, as demonstrated in Figure 4.17.

Image from book
Figure 4.17: This example shows the process of adding access keys to menus and menu items.

Adding and Removing Check Marks

Another feature that users might find convenient is the check mark. Check marks are useful when you need to identify the status of menu items that you can toggle on and off. The presence of a check mark indicates that the menu item has been selected or enabled. Similarly, the absence of a check mark indicates that the menu item has been deselected or disabled. For example, later in this chapter when you develop the Lottery Assistant game, you use check marks so that the user can distinguish which font and background options are selected.

You can set the initial check mark setting at design time using the following method:

  1. Select the menu item that you want to work with.

  2. Right-click to bring up the item's context menu. Click on the Checked option, as demonstrated in Figure 4.18.

Image from book
Figure 4.18: A check mark indicates when a menu item has been selected.
Trick

You can also set the check mark value by selecting the appropriate menu item and then setting the Checked property in the Properties window to true.

Any menu item that can be checked can also be unchecked. When you click a menu item, it is appropriate to toggle the checked status of the item. Therefore, you need to know how to change the checked status of your menu items at runtime, as demonstrated in the following example:

private: System::Void grayToolStripMenuItem_Click(System::Object^
          sender, System::EventArgs^  e)
          {
            grayToolStripMenuItem->Checked = true;
            yellowToolStripMenuItem->Checked = false;
            whiteToolStripMenuItem->Checked = false;
          }

Here, the statement marks the Gray menu item as checked whenever the user clicks on it and removes check marks from the Yellow and White menu items. Alternatively, if the user comes back later and clicks on the Yellow menu item, it's appropriate to remove the check mark from the Gray and White menu items and add it to the Yellow menu item, as demonstrated next:

private: System::Void yellowToolStripMenuItem_Click(System::Object^
          sender, System::EventArgs^  e)
          {
            grayToolStripMenuItem->Checked = false;
            yellowToolStripMenuItem->Checked = true;
            whiteToolStripMenuItem->Checked = false;
          }

Organizing Menu Items Using Separator Bars

Separator bars divide long lists of menu items and make them easier to read. They are also an excellent way of visually grouping related menu items. For example, in Microsoft Excel, menu items for opening and closing files, saving files, printing files, and closing the application are grouped separately.

Of course, the separator can group menu items only if you have added related items together in an easy-to-understand fashion. The following steps outline the process involved in adding a separator bar between your menu items:

  1. Begin creating your menu items.

  2. When you get to a point where you want to insert a separator bar, click the drop-down arrow next to Type Here.

  3. A list of options appears. Select the Separator option from the list. A bar is added to your menu, separating its contents, as shown in Figure 4.19.

Image from book
Figure 4.19: Using separator bars can visually group related menu items.

Enabling and Disabling Menus and Menu Items

Based on what your application is doing, you might need to prevent a user from being able to click on a given menu item. For example, later in this chapter, you work on developing the Lottery Assistant game. This game's menu system controls it, and it includes Get Numbers and Clear Numbers menu items on its File menu. The game enables and disables access to the Get Numbers menu item based on whether the user has entered all the data required to retrieve lottery numbers.

When a menu item is disabled, it appears to the user to be grayed out and doesn't respond when clicked. By default, menu items are enabled. However, you can disable menu items at design time using the following function:

  1. Select the menu or menu item that you want to work with.

  2. Using the Properties window, set the Enabled property for the menu or menu item to true to enable the menu or menu item (the default) or set it to false to disable it. As you can see in Figure 4.20, the Yellow menu item has been disabled.

Image from book
Figure 4.20: Menu items can be disabled at design time.

This functionality is not very useful, however, if you don't add program statements to your code that enable your menu items at the appropriate time. Doing so is a simple process, fortunately, as demonstrated next. In the following example, the previously disabled Yellow menu option is enabled when the user selects the White menu option.

private: System::Void whiteToolStripMenuItem_Click(System::Object^
          sender, System::EventArgs^  e)
          {
            yellowToolStripMenuItem->Enabled = true;
          }
Trap

If you disable a menu heading or a menu item that provides access to a submenu, all menu items and submenus underneath it become inaccessible. Figure 4.21 demonstrates this. Notice the arrow to the right of the Yellow menu option. This menu option has three submenu items, none of which is accessible as long as the Yellow menu option is disabled.

Image from book
Figure 4.21: Associated submenus are disabled when a menu item is disabled.

Hiding and Displaying Menus and Menu Items

Although disabling menu items is a frequent technique that applications use to hide options that are not relevant or appropriate to whatever your user is currently doing, sometimes this is not enough. In such cases, you can go a step further by completely hiding and later revealing menus and menu items. The following steps outline the process involved in hiding and displaying menus and menu items:

  1. Select the menu or menu item that you want to work with.

  2. Using the Properties window, set the Visible property for the menu or menu item to true to enable its display (the default) or set it to false to disable it. The option disappears at runtime. Figure 4.22 shows the result of adding an option named Custom to the Background submenu at design time, which simply disappears when its Visible property is set to false.

Image from book
Figure 4.22: Here the Custom submenu item has been made invisible on the Background submenu.
Trap

If you hide a menu or a menu item that provides access to a submenu, all menu items and submenus underneath it are hidden from view.

After you hide a menu or menu item, you need to add program statements to your code that make them visible later on. Doing so is straightforward, as shown in the following example:

private: System::Void loadToolStripMenuItem_Click(System::Object^
          sender, System::EventArgs^  e)
          {
            customToolStripMenuItem->Visible = true;
          }

As Figure 4.23 demonstrates, the Custom menu item is once again visible. In this example, the code that triggers this change was placed in the Load option, so that when the Load menu item is selected, the Visible setting for the Custom item is set to the value of true.

Image from book
Figure 4.23: You can also control user access to menu items by hiding and redisplaying them when appropriate.


CONTEXT MENUS

A second type of menu system that you might want to add to your Visual C++ applications is a context menu. Context menus are hidden from view, only appearing when the user right-clicks on the form or control with which the context menu is associated.

Hint

A context menu is a menu system that you can attach to a form or control to provide the form or control with additional options or functionality.

The following steps outline the process involved in setting up a context menu:

  1. Double-click on the ContextMenuStrip control located in the Toolbox to add it to the Component Tray.

  2. Add menu items to it by keying in text on top of the Type Here text, as demonstrated in Figure 4.24.

  3. Double-click on each of the menu items in the context list and add your program code, as demonstrated next. For example, you might add the following statement to the click event for the first context menu:

    private: System::Void executeCommandlToolStripMenuItem_Click(
System::Object^  sender. System::EventArgs^  e)
{
  MessageBox::Show( "Command 1 Has Executed" );
}

    Similarly, you might add the following code to the click event for the second context menu item:

    private: System::Void executeCommand2ToolStripMenuItem_Click(
System::Object^  sender, System::EventArgs^  e)
        {
          MessageBox::Show( "Command 2 Has Executed" );
        }

    Finally, you can assign the following code to the click event for the third context menu item, as shown here:

    private: System::Void executeCommand3ToolStripMenuItem_Click(
System::Object^  sender, System::EventArgs^  e)
        {
          MessageBox::Show( "Command 3 Has Executed" );
        }

  4. Select the control for which you created the context menu and set its ContextMenuStrip property equal to the name of the context menu that you just created.

Image from book
Figure 4.24: Here the menu items for a context menu are configured.

After you have finished configuring the form or control's ContextMenuStrip property, you can run your application and access the context menu by right-clicking on the form or control, as demonstrated in Figure 4.25.

Image from book
Figure 4.25: This button has been given an associated context menu.


ADDING CONVENIENCE WITH TOOLBARS

Toolbars are another popular feature in some Windows applications. They provide easy-to-recognize functionality by displaying an organized collection of buttons, each of which when clicked executes a particular application command. By default, when you add a toolbar to a window, Visual C++ automatically places it at the top of the window, just below the menu, if one is present. However, you can move the toolbar to the bottom, right, or left side of the window if you prefer by setting the Dock property.

Typically, programmers use toolbars to give users single-click access to an application's most commonly used commands. Toolbar buttons can display text, graphics, or both text and graphics.

The following steps outline the process involved in adding a toolbar to a Visual C++ application and identify various options that are available to you.

Trick

The first step in adding a toolbar to a Visual C++ application is to add the ToolBar control Located in the Toolbox to a form. However, by default, the ToolBar control is not located in the Toolbox window. But you can add it by right-clicking on the Toolbox window and selecting the Choose Items option. This opens the Choose Toolbox Items dialog box. Make sure that the .NET Framework Components tab is selected when the Choose Toolbox Items dialog box appears, and scroll down until you see ToolBar control. Select the ToolBar control and click on OK. The control becomes visible in the Toolbox window.

  1. Drag and drop the ToolBar control onto your form.

  2. Select the ToolBar control, locate the buttons property in the Properties window, and click on the (Collection) ellipsis button located in its property's value field. The ToolBarButton Collection Editor appears, as shown in Figure 4.26.

  3. Click on the Add button to add as many buttons as you want to the toolbar. Each time you click on the Add button, an entry for the button is displayed in the Members pane located on the left side of the editor, as demonstrated in Figure 4.27.

  4. To display a text string on the button, select the Text property and type a string as its value.

  5. To add a ToolTip to the button, select the ToolTipText property and type the text that you want to be displayed.

  6. Modify the Style property to specify the style that you want to apply to the button. The following options are available:

    • PushButton. Displays the three-dimensional button.

    • ToggleButton. Toggles the button's appearance between a depressed and normal state each time the user clicks on it.

    • Separator. Changes the button into a separator bar.

    • DropDownButton. Modifies the button to behave as a drop-down control that displays menu items.

  7. Click on OK to close the ToolBarButton Collection Editor.

Image from book
Figure 4.26: The ToolBarButton Collection Editor a allows you to add and remove buttons on a toolbar.
Image from book
Figure 4.27: Use the up and down arrows to configure the order in which buttons are displayed on the toolbar.
Trick

If you are adding text to your toolbar buttons, you might need to specify toolbar button width, depending on the amount of text you plan to display. To change the width or height of toolbar buttons, select the ToolBar control's ButtonSize property and specify a new size.

Adding Graphics to Your Toolbars

You're not limited to displaying text in your toolbar buttons; you can display pictures, too. Graphic images enhance your toolbars even further by providing a visual cue as to a given button's purpose. But to provide this functionality, you must take a few extra steps before you can actually associate a graphic with a button. For starters, you must add an ImageList control from the Toolbox to your application. Using this control, identify all the graphics images that you plan to add to your toolbars. After you've added them to the ImageList, you can configure each of your toolbar buttons to display one of the graphics images defined in the ImageList.

The following function identifies the steps that are involved in making all this work:

  1. Add an ImageList control to your form.

  2. In the Properties window, click on the (Collection) ellipsis button located in the Images property's value field. The Images Collection Editor appears, as shown in Figure 4.28.

  3. Click on the Add button and specify the name of an image to be added to the ImageList. Repeat this step as many times as necessary, and make sure you take note of the index number that is assigned to each image you add.

  4. Click on OK to close the Images Collection Editor.

Image from book
Figure 4.28: The Images Collection Editor lets you specify the images that you will add to your toolbar.

After you have finished adding images to the ImageList control, select the ImageList property for your ToolBar control and specify the name of the ImageList that you just created. Then open the ToolBarButton Collection Editor by clicking on the Button property's (Collection) ellipsis button. Modify the ImageIndex property for each button to associate the button with a given graphic image's index number within the ImageList control. For example, Figure 4.29 shows a toolbar under development with an image added to each of its three buttons.

Image from book
Figure 4.29: Here a graphic image is added to a ToolBar control button.

Associating Program Statements with Toolbar Buttons

Unfortunately, individual toolbar buttons do not have their own click event. There is just a single click event for the entire ToolBar control. Therefore, you must determine, in code, which button the user clicked on and then execute the appropriate program behavior. Fortunately, despite this complication, it is easy to make this happen.

The ToolBarButtonClickEventArgs object's Button property is automatically passed to the ButtonClick event handler at runtime. If you look back at Figure 4.27, you see that just to the left of each toolbar button is a number that uniquely identifies the button's indexed position within the toolbar. By querying the Button property and comparing it to the button index numbers, you can identify which button was clicked.

To see this in greater detail, let's create an example. For starters, access the toolbar's click event by double-clicking on it. The following code appears in the Code Editor:

private: System::Void toolBar1_ButtonClick(System::Object^ sender,
          System::Windows::Forms::ToolBarButtonClickEventArgs^ e)
          {
          }

In addition to defining the click event for the toolbar, this code automatically receives an argument that identifies the index number of the clicked button. You can access this number by your code as e->Button, as demonstrated in the following example:

private: System::Void toolBar1_ButtonClick(System::Object^  sender,
          System::Windows::Forms::ToolBarButtonClickEventArgs^ e)
          {
            // Test each button value to find which was clicked
            if( toolBar1->Buttons->IndexOf( e->Button ) == 0)
              MessageBox::Show( e->Button->Text );
            if( toolBar1->Buttons->IndexOf( e->Button ) == 1)
              MessageBox::Show( e->Button->Text );
            if( toolBar1->Buttons->IndexOf( e->Button ) == 2)
              MessageBox::Show( e->Button->Text );
          }

In this example, e->Button is an argument representing the index number of the button the user clicked. After the comment, the first two statements check to see if the first toolbar button was clicked. The two following statements check to see if the second toolbar button was clicked, and the last two statements check to see if the third toolbar button was clicked.

Figure 4.30 shows the output displayed when the previous example is executed and the user clicks on a button that is named Command 1.

Image from book
Figure 4.30: A dialog box is displayed as a result of clicking within the correct area.


BACK TO THE LOTTERY ASSISTANT GAME

Now that you have a basic overview of menu systems, it's time to put that knowledge to work creating this chapter's game project. You will create the Lottery Assistant game using the same five steps that you followed in previous chapters. By the time you have finished creating this game, you will have demonstrated your ability to modify your Visual C++ applications by adding fully functional menu systems to your forms.

Designing the Game

The Lottery Assistant game is played on a single window. Therefore, it has only a single form to which you add the nine controls listed in Table 4.1.

Table 4.1: Form Controls for the Lottery Assistant Game
Control Type | Control Name | Description
Label | lblFullSet | Identifies the Label control where the player specifies how many numbers constitute a full set
Label | lblNumPics | Identifies the Label control where the player specifies how many sets of lottery numbers the game should generate
Label | lblNumRange | Identifies the Label control where the player specifies the range of numbers from which the game should generate lottery numbers
Label | lblOutput | Identifies the Label control where the game displays the lottery numbers that it generates
TextBox | txtFullSet | Identifies the TextBox control where the player specifies how many numbers constitute a full set
TextBox | txtNumPics | Identifies the TextBox control where the player specifies how many sets of lottery numbers the game should generate
TextBox | txtNumRange | Identifies the TextBox control where the player specifies the range of numbers from which the game should generate lottery numbers
TextBox | txtOutput | Identifies the TextBox control where the game displays the lottery numbers that it generates
MenuStrip | mnuStrip I | Identifies the name of the MenuStrip control that is used to create the game's menu system

Step 1: Creating a New Visual C++ Project

The first step in developing the Lottery Assistant game is to start Visual C++ and open a new project, as detailed next:

  1. If you have not already done so, start up Visual C++ 2005 Express and then click on File, New Project. The New Project dialog box appears.

  2. Select Windows Application template.

  3. Type Lottery Assistant as the name of your new application in the Name field at the bottom of the New Project window.

  4. Click on OK to close the New Project dialog box.

In response, Visual C++ creates a new project for you and displays a blank form on which you can design the game's user interface.

Step 2: Creating the User Interface

Next, you must add the controls that make up the game's user interface. To begin, let's review the overall layout of the game user interface, as shown in Figure 4.31.

  1. Begin by adding a MenuStrip control to the form. By default, Visual C++ assigns the name MenuStrip1 to the control.

  2. Add four Label controls to the form and line them up as shown in Figure 4.31. By default, Visual C++ names them Label1 to Label4.

  3. Add three TextBox controls to the form and line them up horizontally with the first Label controls. By default, Visual C++ names these controls TextBox1 to TextBox3.

  4. Finally, add a fourth TextBox control to the form just under the Label4 control. Set the control's Multiline property to true and the Wordwrap property to false. Resize it so that it covers most of the bottom half of the form, as shown in Figure 4.31. By default, Visual C++ assigns this control the name TextBox4.

Image from book
Figure 4.31: The interface design for the Lottery Assistant game is complete.

The layout of the Visual C++ form is now complete. All controls should be visible on the form except for the MenuStrip1 control, which is displayed in a Component Tray just below the form.

Step 3: Customizing Form and Control Properties

Before you start customizing the properties associated with the controls that you've just added to the form, you need to modify a few properties that belong to the form. The properties that need to be changed, along with their new value assignments, are listed in Table 4.2.

Table 4.2: Property Value Assignments for the Lottery Assistant Game's Form
Property | Value
Name | ltaForm
BackColor | White
FormBorderStyle | Fixed3D
StartPosition | CenterScreen
Text | Lottery Assistant

Next, let's set the Name and Text properties for each of the four Label controls, as specified in Table 4.3.

Table 4.3: Property Changes for Each of the Label Controls
Control | Property | Value
Label1 | Name | lblFullSet
 | Text | How many numbers make up a full set?
Label2 | Name | lblNumPics
 | Text | How many sets of lottery numbers do you want?
Label3 | Name | lblNumRange
 | Text | What is the highest number that can be picked?
Label4 | Name | lblOutput
 | Text | What are your lottery numbers?

Now let's make modifications belonging to each of the TextBox controls, as listed in Table 4.4.

Table 4.4: Property Changes for Each of the TextBox Controls
Control | Property | Value
TextBox1 | Name | txtFullSet
TextBox2 | Name | txtNumPics
TextBox3 | Name | txtNumRange
TextBox4 | Name | txtOutput
 | Multiline | true
 | ReadOnly | true
 | ScrollBars | Vertical
 | TabStop | false
 | Wordwrap | false

Setting the ReadOnly properly to true for the fourth TextBox control prevents the player from attempting to enter text into it. Setting the ScrollBars property to Vertical adds a scrollbar to the text box so that the player can scroll up and down when more sets of lottery numbers are generated than can be displayed at one time. Setting the TabStop property to false takes the fourth TextBox control out of the tab index.

The last control in need of modification is the MenuStrip control. First, click on the control and change its name to mnuStrip. Next, configure the MenuStrip control to create a menu system composed of the menus outlined in Table 4.5.

Table 4.5: Menus for the Lottery Assistant Game
Text Property | Resulting Menu Name | Description
&File | FileToolStripMenuItem | Contains commands that control the game's execution
&Options | OptionsToolStripMenuItem | Contains commands that configure the game's display
&Help | HelpToolStripMenuItem | Provides access to additional information about the game

After you have created each of the menus listed in Table 4.5, it is time to configure each menu by adding menu items. Table 4.6 lists the menu items that you'll need to add to the FileToolStripMenuItem menu.

Table 4.6: Menu Items Residing Under the File Menu
Text Property | Resulting Menu Name | Description
&Get Numbers | GetNumbersToolStripMenuItem | Retrieves randomly generated lottery numbers
&Clear Numbers | ClearToolStripMenuItem | Clears out any text displayed in the game's TextBox controls
E&xit | ExitToolStripMenuItem1 | Terminates game execution

The Clear Numbers menu item is used to execute programming statements that remove text that might currently be stored in the form's TextBox controls. When the form is first displayed, no text is displayed in the TextBox controls. Therefore, it is appropriate to initially disable this Clear Number menu item at design time. Later, when the application is running and the player begins to key in text, you'll add programming logic to enable this menu item. So, to disable the Clear Numbers menu item, select it and then set its Enabled property (in the Properties window) to false.

Table 4.7 lists the menu items that you are to add to the OptionsToolStripMenuItem menu.

Table 4.7: Menu Items Residing Under the Options Menu
Text Property | Resulting Menu Name | Description
&Background | BackgroundToolStripMenuItem | Provides access to a submenu where you can change the game's background color
&Font Size | FontSizeToolStripMenuItem | Provides access to a submenu where the font size used to control the display of lottery numbers can be changed

Table 4.8 lists the menu item that you are to add to the HelpToolStripMenuItem menu.

Table 4.8: Menu Items Residing Under the Help Menu
Text Property | Resulting Menu Name | Description
&About | AboutTooLStripMenuItem | Executes code that displays information about the game in a pop-up window

At this point, you have defined all three of the game's menus, in addition to menu items that reside underneath them. However, you are not done yet. You need to set up both the Background and Font Size menu items to provide access to their own submenus. Table 4.9 outlines the contents of the Background submenu. Table 4.10 outlines the contents of the Font Size submenu.

Table 4.9: Menu Items Residing on the Background Submenu
Text Property | Resulting Menu Name | Description
&White | WhiteToolStripMenuItem | Sets the form's background color to white
&Yellow | YellowToolStripMenuItem | Sets the form's background color to yellow
&Gray | GrayToolStripMenuItem | Sets the form's background color to gray
Table 4.10: Menu Items Residing on the Font Size Submenu
Text Property | Resulting Menu Name | Description
8 | ToolStripMenuItem1 | Sets the font size displayed in the txtOutput control to 8
10 | ToolStripMenuItem2 | Sets the font size displayed in the txtOutput control to 10
12 | ToolStripMenuItem3 | Sets the font size displayed in the txtOutput control to 12

Before you call it quits with the Lottery Assistant game's menu system, let's add just a few more bells and whistles. For starters, add the shortcut key F1 to the Get Numbers menu item located under the File menu by selecting the menu item and setting the ShortcutKeys property to F1. Then add the shortcut key F2 to the Clear Numbers menu item, which is also located under the File menu. Then set the Checked property for the White submenu item under the Options menu to true, indicating that it is the default menu item. Do the same things for the Checked property belonging to the first menu item on the Font Size submenu.

That's all the property modifications that are required for the Lottery Assistant game's controls and menu system. Now it's time to add the program statements required to make the game work.

Step 4: Adding a Little Programming Logic

All of the Lottery Assistant game's program code is controlled by the game's menu system. Unlike the game projects that you worked on in previous chapters, no Button controls are available for the player to click on in this game. To keep things straightforward, let's begin by adding the programming statements for each menu item one by one, starting with the first menu item located on the File menu and finishing with the last menu item under the Help menu.

Adding Code to the Get Numbers Menu Item

The easiest way to associate programming statements with a menu item is to double-click on the menu item. When you do, Visual C++ automatically opens the Code Editor and creates a couple of lines of initial code for you. So, first double-click on the Get Numbers menu item located under the File menu. The following code is generated automatically and displayed in the Code Editor.

private: System::Void getNumbersToolStripMenuItem_Click(
          System::Object^  sender, System::EventArgs^  e)
         {

         }

Type in the source code for the Get Numbers menu item by starting with the following statements. These statements define variables and an array that the application uses to store and manipulate the data it needs to execute. For now, key in these statements exactly as shown. In Chapter 5, "Storing and Retrieving Data in Memory," you will learn all about variables and arrays.

Double dblInputTest = 0;     //Used to test input
const Int16 cMinInSet = 3,   //Set range
             cMaxInSet = 10,
             cMinNumPics = 1,      //Number of sets
             cMaxNumPics = 10,
             cMinNumRange = 1,     //Range of picks
             cMaxNumRange = 50:

Next add the following statements, which check to see if the player has supplied valid input into the first TextBox control and display an error message if this is not the case. Take note of the return statement, which immediately forces the function to exit when encountered. This prevents Visual C++ from processing any of the remaining statements associated with the Get Numbers menu item click event.

//Confirm that full set is a proper entry
if( !Double::TryParse( txtFullSet->Text,
    dblInputTest ) ||
    !(dblInputTest >= cMinInSet &&
    dblInputTest <= cMaxInSet) )
{
  MessageBox::Show( String::Concat( "You must enter"
  " a number between ", cMinInSet.ToString(),
  " and ", cMaxInSet.ToString(), " for the full set." ) );
  return;
}
Trick

The Double::TryParse method is one of the most robust means for checking to see if a text string contains a numeric value. Although you can use other means, most require special error handling techniques if they encounter data outside of a certain range. You can use Double::TryParse, however, to examine a string containing any combination of letters and numbers.

The next set of statements checks to ensure that the player entered valid data into the second TextBox control and displays an error message if this is not the case.

//Confirm that number of picks is a proper entry
if( !Double::TryParse( txtNumPics->Text, dblInputTest )
    || !(dblInputTest >= cMinNumPics &&
    dblInputTest <= cMaxNumPics) )
{
  MessageBox::Show( String::Concat( "You must enter"
  " a number between ", cMinNumPics.ToString(),
  " and ", cMaxNumPics.ToString(), " for the "
  "number of sets you want." ) );
  return;
}

The next set of statements ensures that the third TextBox control has the appropriate values. This includes confirming that the range of numbers is within minimum and maximum bounds and that the range of numbers to generate is greater than the number of picks.

//Confirm that range is a proper entry
if( !Double::TryParse( txtNumRange->Text, dblInputTest )
    || !(dblInputTest > cMinNumRange &&
    dblInputTest <= cMaxNumRange) )

{
  MessageBox::Show( String::Concat( "You must enter"
  " a number greater than ", cMinNumRange.ToString(),
  " and less than ", cMaxNumRange.ToString(), " for"
  " the range of numbers." ) );
  return;
}
Trap

Be certain that any text string you send to the Int32:: Parse method contains an integer value. If not, your program will crash without special error handling techniques.

//Confirm that range is greater than number within a set
if( Int16::Parse( txtNumRange->Text ) <
  Int16::Parse( txtFullSet->Text ) )
{
  MessageBox::Show( "You must enter a range "
  "of numbers that is greater than the number "
  "of picks in order to be able to generate "
  "one unique number for each pick." );
  return;
}

Now add the following statements, which create a series of randomly generated numbers by accessing the computer's current time:

//Create random numbers based on current time
DateTime moment = DateTime::Now;
Random^ randNumGen = gcnew Random( moment.Millisecond );

Next, add the following statements. These statements include for loops and a do loop, which you will learn more about in Chapter 7, "Processing Lots of Data with Loops."

Although somewhat complicated, you can follow the basic flow of this block of code by reading the comments. First, the code creates a list that holds a set of lottery number picks. This allows for the checking of duplicates. Then the code creates a for loop, which causes the entire process of creating lottery numbers and checking for duplicates to happen again and again until the program has created all the lottery numbers that the user desires.

//Create a list that will hold the picks
//  and allow checks for duplicates

Int16 iLotteryArray[cMaxInSet];
//Generate all random numbers
Int16 numPics = Int16::Parse(txtNumPics->Text);
for( Int16 iNumSetCntr = 0;
   iNumSetCntr < numPics;
   iNumSetCntr++ )
{
   //Clear the list of picks
   Int16 iCurPickCntr;
   for( iCurPickCntr = 0; iCurPickCntr < cMaxInSet;
      iCurPickCntr++ )
      iLotteryArray[iCurPickCntr] = 0;
   //Generate the list
   iCurPickCntr = 0;
   Boolean bPickDuplicate;
   do
   {
     bPickDuplicate = false;
     //Get a possible lottery value
     iLotteryArray[iCurPickCntr] = cMinNumRange +
     randNumGen->Next()
     % (Int16::Parse( txtNumRange->Text) -
     cMinNumRange );
     //Check to see if the pick is duplicated
     for( Int16 iDupCntr = 0; iDupCntr < iCurPickCntr;
        iDupCntr++ )
     {
       if( iLotteryArray[iDupCntr] ==
         iLotteryArray[iCurPickCntr] )
       {
         bPickDuplicate = true;
         break;
       }
     }
     //If the number is a duplicate, try again
     if( bPickDuplicate == true )
       continue;
     //The number is not a duplicate; output
     //  and move to next

     txtOutput->Text = String::Concat(
     txtOutput->Text, Convert::ToString(
     iLotteryArrayEiCurPickCntrl ), "t" );

     iCurPickCntr++;
   } while( iCurPickCntr <
           Int16::Parse( txtFullSet->Text) );
   txtOutput->Text = String::Concat(
   txtOutput->Text, "rrnrrn" );
}

Don't worry if this example is difficult to follow. The specifics of the programming logic are covered in upcoming chapters. The last program statements to add to the code that executes in response to the Get Numbers menu item's click event are shown next:

getNumbersToolStripMenuItem->Enabled = false;
clearNumberToolStripMenuItem->Enabled = true;

These last two statements disable the Get Numbers menu item and enable the Clear Numbers menu item.

Adding Code to the Clear Numbers Menu Item

Now, switch back to the Design view and double-click on the Clear Numbers menu item. Visual C++ generates the following code:

private: System::Void clearNumberToolStripMenuItem_Click(
          System::Object^  sender, System::EventArgs^  e)
      {
      }

Add these statements to the Clear Numbers menu click event. The first four statements clear out any text displayed in the four TextBox controls. The next statement places the cursor in the first TextBox control, and the last statement enables the Get Numbers menu item:

txtFullSet->Text = "";
txtNumPics->Text = "";
txtNumRange->Text = "";
txtOutput->Text = "";
txtFullSet->Focus();
getNumbersToolStripMenuItem->Enabled = true;
Adding Code to the Exit Menu Item

Now return to the Design view and double-click on the Exit menu item located under the File menu. The code to add to this function is straightforward. Simply add the programming statement this->C1ose(), which tells the application to shut down all windows and quit.

private: System::Void exitToolStripMenuItem_Click(System::Object^
          sender, System::EventArgs^ e)
      {
        this->Close();
      }
Adding Code to the White Menu Item

Now it's time to start adding the program statements required to make the menu items on the Background submenu work. Start by accessing the click event for the White menu item and modifying the code that is generated automatically, as shown here:

private: System::Void whiteToolStripMenuItem_C1ick(System::Object^
          sender, System::EventArgs^  e)
      {
        this->BackColor = Color::White;
        whiteToolStripMenuItem->Checked = true;
        yellowToolStripMenuItem->Checked = false;
        grayToolStripMenuItem->Checked = false;
      }

As you can see, you are adding four statements. The first statement changes the background color of the parent object (the form) to white. The next statement places a check mark to the right of the White menu item. The last two statements ensure that the Yellow and Gray menu items do not display a check mark.

Adding Code to the Yellow Menu Item

Next, access the click event for the Yellow submenu item and modify the code that is generated automatically, as shown here:

private: System::Void yellowToolStripMenuItem_Click(System::Object^
          sender, System::EventArgs"  e)
      {
        this->BackColor = Color::Yellow;
        whiteToolStripMenuItem->Checked = false;
        yellowToolStripMenuItem->Checked = true;
        grayToolStripMenuItem->Checked = false;
      }

As you can see, the only difference between this and the code that you added to the White menu item is that this code changes the background color to yellow and sets the check mark for the Yellow menu item.

Adding Code to the Cray Menu Item

Now access the click event for the Gray menu item and modify the code that is generated automatically, as shown here:

private: System::Void grayToolStripMenuItem_Click(System::Object^
          sender, System::EventArgs^  e)
      {
        this->BackColor = Color::Gray;
        whiteToolStripMenuItem->Checked = false;
        yellowToolStripMenuItem->Checked = false;
        grayToolStripMenuItem->Checked = true;
      }
Adding Code to the First Font Size Submenu Item

Now let's add the code that executes when the menu items on the Font Size submenu are clicked. For starters, access the click event for the first menu item in the Font Size submenu (the menu item that sets the font size to 8) and modify the code that is generated automatically, as shown here:

private: System::Void toolStripMenuItem2_Click(System::Object^
          sender, System::EventArgs^  e)
      {
        this->txtOutput->Font = gcnew Drawing::Font(L"Arial", 8.25F );
        toolStripMenuItem2->Checked = true;
        toolStripMenuItem3->Checked = false;
        toolStripMenuItem4->Checked = false;
      }

As you can see, the first statement that you added sets the Font property of the txtOutput control to Arial and specifies a font size of 8.25. The next three statements control the placement of the check mark.

Adding Code to the Second Font Size Submenu Item

Now access the click event for the second menu item in the Font Size submenu (the menu item that sets the font size to 10) and modify the code that is generated automatically, as shown here:

private: System::Void toolStripMenuItern3_Click(System::Object^
          sender, System::EventArgs^  e)
      {
        this->txtOutput->Font = gcnew Drawing::Font(L"Arial", 10.OF );
        toolStripMenuItem2->Checked = false;
        toolStripMenuItem3->Checked = true;
        toolStripMenuItem4->Checked = false;
      }
Adding Code to the Third Font Size Submenu Item

Finally, access the click event for the third menu item in the Font Size submenu (the menu item that sets the font size to 12) and modify the code that is generated automatically, as shown here:

private: System::Void toolStripMenuItem4_Click(System::Object^
          sender, System::EventArgs^ e)
      {
        this->txtOutput->Font = gcnew Drawing::Font(L"Arial", 12.OF );
        toolStripMenuItem2->Checked = false;
        toolStripMenuItem3->Checked = false;
        toolStripMenuItem4->Checked = true;
      }
Adding Code to the About Menu Item

Now let's add the program statements for the last remaining menu item by accessing the click event for the About menu item located under the Help menu. Modify the code that is generated automatically, as shown here:

private: System::Void aboutToolStripMenuItem_Click(System::Object^
          sender, System::EventArgs^ e)
      {
        MessageBox::Show( "This Visual C++ application was"
        "created by Aaron Miller" );
      }

As you can see, the MessageBox.Show method is executed whenever the player clicks on the About menu item, displaying information about the application and its author. (However, you can feel free to change the name.)

That's it. In the next four chapters, you will gain a better understanding of the programming statements that make up the Visual C++ programming language. If there is anything in this project that you had trouble understanding, bookmark it and then come back and look over the example again after you have gotten through Chapters 5 through 8.

Step 5: Testing the Execution of the Lottery Assistant Game

Okay. Now it's time to see if your application works. Press F5 and see how it runs. If you run into any errors, go back and check your typing and fix any typos that you might have made. When you think you have the game running smoothly, share it with friends and ask them to test it.


SUMMARY

In this chapter, you learned how to give your applications a few finishing touches with interface elements such as menus and toolbars. You learned how to create professional-looking menus with shortcuts, access keys, and separator bars, and how to create submenus. In addition, you learned how to breathe life into your menu system by adding code to the options. This chapter also covered how to enhance your menu system through the use of check marks, graying menu items, and hiding items when necessary. Finally, you learned how to create context menus, associate them with controls, and give your applications toolbars.

Before you move on to Chapter 5, take a few minutes to enhance the Lottery Assistant game by implementing the following challenges.


CHALLENGES

  1. Add a menu item under the Help menu that provides instructions for using the lottery game by means of the MessageBox.Show method.

  2. Add a toolbar to the Lottery Assistant game and define buttons for each of the menu items found under the File and Options menus.

  3. Going back to the material that you learned in Chapter 3, "Creating an Application Interface," create ToolTips for each TextBox and add a status strip to your application.


Chapter 5: Storing and Retrieving Data in Memory

OVERVIEW

One of the primary purposes of a computer is to process information. When you interact with an application, it must process the information that you supply to it and the actions you tell it to perform. To work with this information, the application must store it in various ways so that it can retrieve it later, change it, or make decisions based on it. In this chapter, you learn about this aspect from a programming point of view. You learn how to store and retrieve data in memory using variables, constants, and complex data types such as arrays and structures.

This chapter also covers a few other areas, such as how to create more professional, readable code with comments, and more details on how to work with the ProgressBar control. In addition, you get the chance to work on a new game project, a game called The Story of Mighty Molly.

In this chapter, you learn the following:

  • How to define constants, variables, structures, and arrays

  • How to properly specify data types

  • How to convert data from one type to another

  • How to specify variable scope


PROJECT PREVIEW: THE STORY OF MIGHTY MOLLY

In this chapter, you learn how to create a Visual C++ game called The Story of Mighty Molly. In this game, the player helps to tell the story by providing answers to questions. The questions are intended to collect specific information that is then used to fill in the story. This type of game is known as a madlib. Figures 5.1 through 5.5 provide a sneak preview of The Story of Mighty Molly and demonstrate the overall execution of the game.

By the time you have created this project, you'll have learned how to declare variables and how to specify their data type and scope. In addition, you will have learned how to work with conversion functions and String constants.

Image from book
Figure 5-1: The Story of Mighty Molly game begins by presenting the player with five questions and then allowing him to tell the story by clicking a button.
Image from book
Figure 5.2: An introduction tells the story of Mighty Molly.
Image from book
Figure 5.3: The game issues an error if all text is not filled in.
Image from book
Figure 5.4: A progress bar located on the status bar indicates when all required information has been collected.
Image from book
Figure 5.5: Data input collected from the player is then plugged into the story line and displayed for the player to enjoy.


ENHANCING YOUR CODE WITH COMMENTS

Comments are often considered to be one of the distinguishing marks of a professional programmer. Comments are ways of making notes about what your code is doing. As your projects become larger and more complicated, the number and complexity of the programming statements that you add to them will rise. As the amount of code in an application grows, it becomes more and more difficult to understand what is happening. You might understand program code that you write today, but without comments, the code might be indecipherable a year or two later. It can be especially difficult for another programmer to follow behind you and make modifications or enhancements to your code.

By embedding comments at key points in your applications, you can leave behind notes that explain why you did things the way you did. Because commenting helps you to clarify your thought process, it can be critical in helping to deal with program mistakes and in helping other programmers to build larger projects.

Hint

A comment is a text statement that is embedded within an application used to document the source code of a program for the programmer, but that is ignored by the application.

In Visual C++, comments start with two forward slashes, as demonstrated here:

//Define a generic counter for the application
Int16 intCounter;
Trick

You can create comments around any statement using the /* and */ characters. The slash and then asterisk denotes the beginning of a body of comment text, and the asterisk and then slash denotes the ending of that body. Here is an example:

/* Type anything you want in the comment block
    When you are finished, close the comment block like so: */

This style of commenting is a holdover from Visual C++'s roots in the C language. In general, C++ programmers usually prefer to use two forward slashes for each line of comments to make each comment line clear.

As you can see, the first statement in the previous example documents what the following statement does. When executed, Visual C++ ignores the first statement, executing only the second line of code. Visual C++ also allows you to add comments to the end of other statements, as demonstrated here:

MessageBox::Show( "ABC123" ); //Show key
Trick

Another good use of comments is to temporarily comment out statements when testing your application at development time. For example, in the course of testing your application, you might place a temporary message that confirms that a function within the program has been reached, as demonstrated here:

private: System::Void Form1_Load(System::Object^ sender,
          System::EventArgs^ e)
          {
            MessageBox::Show( "Form_Load Successful." );
          }

However, seeing the pop-up window displayed by the MessageBox::Show method appear every time you test the execution of your application might get tiresome after a while. To speed up your testing, you might choose to comment out the MessageBox::Show statement while you are working on some other area of your application.

private: System::Void Form1_Load(System::Object^ sender,
          System::EventArgs^ e)
          {
            //MessageBox::Show( "Form_Load Successful." );
          }

When you are finished making changes, all you have to do is remove the comment, and your application resumes displaying the pop-up dialog box whenever it is loaded.


STORING AND RETRIEVING DATA

Data manipulation is a fundamental part of the programs you write in Visual C++. Every program requires the ability to store data and then later to retrieve and process it. The projects from earlier chapters are excellent examples of this. Visual C++ provides many options for manipulating data so that your applications can perform the tasks your users need.

Hint

Data is information that your application collects, stores, recalls, and modifies during its execution.

Alternative Ways of Storing Data

Visual C++ is an extremely flexible programming language, and as such it offers a wide variety of ways to solve a particular problem or perform a certain task. This is especially true when it comes to working with data. Visual C++ provides a number of different options, each of which is best suited to different situations. The options that you decide to use will vary based on the challenge you are faced with. Often, the best method for storing data varies based on the manner in which the data is used.

  • Constants. These data types are best when you are dealing with immutable quantities. Because they cannot be changed, you can rely on them to be the same throughout your program. A good example of a constant data type is pi.

  • Variables. Whereas constants are perfect for storing unchanging and unchangeable data, variables, as their name implies, are best suited for storing data that is expected to change frequently.

  • Arrays. Sometimes you need to store and work with large collections of related information, such as a list of names or highest scores. These situations are perfect for an array because this data type allows you to work with both the list and the individual elements of it when you need to.

  • Structures. A structure is a user-defined data type that you design to suit your needs. It allows you to group related variables into a single variable. You could, for instance, create a customer variable that stored a person's name and customer number. Your application could then refer back to either one later, but use a single variable to do so.

    Trick

    One of the most powerful options for manipulating data is the class. This option is covered later in Chapter 9, "Getting Comfortable with Object-Oriented Programming."

Data Types

Visual C++ is capable of storing and working with many different data types. Table 5.1 lists each of the supported data types. Each data type, except the Object data type, is capable of storing a specific type of data. The limits on the range of possible values that a given data type can store vary based on the type.

Table 5.1: Visual C++ Supported Data Types
Data Type | Value Range
Boolean | true or false
Byte | 0 to 255
Char | 0 to 65,535
DateTime | January 1, 0001 to December 31, 9999
Decimal | 1.0×10-28 to approximately 7.9×1028 with 28 to 29 significant digits
Double | 5.0×10-324 to 1.7×10308 with a precision of 15–16 digits
Int16 | -32,768 to 32,767
Int32 | -2,147,483,648 to 2,147,483,647
Int64 | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
Object | A generic type that is the basis of all other types
Sbyte | -128 to 127
Single | 1.5×10-45 to 3.4×1038 with a precision of 7 digits
String | Up to two billion characters
UInt16 | 0 to 65,535
UInt32 | 0 to 4,294,967,295
UInt64 | 0 to 18,446,744,073,709,551,615
Trick

Although you can always use the largest data type possible to store information, your programs in fact benefit from using the smallest possible. When you specify the correct data type to meet the task that your application is performing, you enable your Visual C++ programs to run faster. This bonus comes from reducing the amount of memory used by the application and by eliminating the need to later convert data from one data type to another.

By specifying a data type, you tell Visual C++ the range of allowable values for your variable. You also indicate to Visual C++ what actions you want to perform on the variable. For example, by specifying one of the numeric data types, you tell Visual C++ that it can perform mathematic calculations. On the other hand, if you specify string data, you tell Visual C++ that you want to work with text.


WORKING WITH CONSTANTS

When deciding whether to use a constant, variable, array, or structure to store a piece of data, it is best to look first at how the data is to be used. Data that is known at design time and that will not change during the execution of the application is defined best as a constant. This allows Visual C++ to work more efficiently with the data and provides you, the programmer, with a measure of safety against accidentally changing it.

Declaring Your Own Constants

By assigning data to a constant instead of to a variable, you eliminate the possibility that you might alter the data mistakenly later on in your application. Unlike with variables, Visual C++ bars you from making a change to a constant value. If you try to change the data assigned to a constant, Visual C++ flags it as an error when you test the execution of your application.

Constants make your application code easier to read. They prevent the syndrome in code known as "magic numbers," which often seem like arbitrary, out-of-the-blue values. Constants, at a glance, explain what they are doing in the code.

To declare a constant within Visual C++, you must use the const keyword using the syntax outlined here:

const DataType ConstHame = Expression;

ConstName represents the name that you assign to the constant. DataType identifies the type of data to be assigned to the constant, and Expression represents the value that is being assigned. To demonstrate how constants work, take a look at the following example:

const Int16 cMaxPasswordChars = 8;
MessageBox::Show( String::Concat( "Maximum password characters: ",
                    cMaxPasswordChars.ToString() ) );

In this example, a constant named cMaxPasswordChars is declared with a data type of Int16 and is assigned a value of 8. The MessageBox:: Show method uses it as an argument specifying the pop-up maximum number of password characters, as shown in Figure 5.6.

Image from book
Figure 5.6: By assigning a string to a constant, you can use it throughout your application without worrying that the value will change.
Trick

As you might have noticed in the previous example, the letter c precedes the name of the constant. This is to help identify it as a constant. Prefacing constants with a c is a recommended naming convention. When used consistently, it helps make your constants stand out and your code easier to read.


WORKING WITH VARIABLES

Constants are ideal for storing data that you do not want to change during program execution. However, you will most often need to store data that will change as your application runs. Variables are perfect for storing your data in these situations.

A variable is essentially a container for information. The variable's name is how Visual C++ keeps track of which data belongs to what part of your application.

Hint

A variable stores data that might change during program execution.

Variables give your Visual C++ applications the ability to process all kinds of data. For example, in previous chapter game projects, you saw how applications used text boxes to collect player input. This input was then stored in variables and later processed.

There are two steps to working with variables:

  • Variable declaration. This involves the naming of a variable and the identification of the type of data that it will store.

  • Variable assignment. This is the process of assigning a value to a variable.

Declaring Variables

To declare a variable, you must think of a name and the type of data you want to store. The name represents a location in memory that your program will use automatically to hold whatever you want to store.

Hint

The name of a variable is also called its identifier. That word applies to anything you name, including functions or classes. If your compiler ever gives you a message about an identifier, it's likely talking about something you created.

Visual C++ allows you to save space by declaring multiple variables of the same data type on a single line, as demonstrated next. If, for instance, you want to declare a variable that holds the maximum amount of text that a user should be allowed to enter into a text box, you might use this:

Int16 intCounter;
Single sngHighestTemperature;
Double dblEscapeVelocity;

These variables are ready to be assigned values. If you want to save space, you can declare variables of the same type on the same line. To do so, you declare the type and separate the variables names by a comma.

Int16 intCurrentTime, intBestTime, intWorstTime;

Defining Variables

When you declare a variable, you tell Visual C++ that you plan to use it elsewhere. But until you give the variable a value, it is said to be undefined. Defining a variable is the process of giving a variable its value.

Defining a variable is important because, until you do so, it has a random value in memory. Each time you run your application, the value might be different. Not until you tell Visual C++ to give your variable a value can you safely know what its contents will be should you refer to it later.

The syntax for defining a variable is exactly like declaring one, except that you follow the variable name by an equal sign and place a value after it. This causes your variable to take on whatever value that comes after the equal sign when your application runs. For instance, this example defines a variable:

Int16 intCounter = 0;

This statement, which you might use in your own code to keep track of certain items, defines a variable with the name of intCounter and sets its value to 0.

Trick

It's often a good idea to initialize your variable as soon as you declare it.

Assigning Data to Variables

You can choose to declare a variable but not assign a value to it. This leaves you free to wait until the right moment in code to use the variable as you want. When it is time to use this variable, your application is free to assign a value to it. You can assign the contents of a value you type into the code or another variable.

Int16 intIntCurrentAge;
Int16 intOldestAge;
intOldestAge = 100;
intIntCurrentAge = intOldestAge;

If you don't assign a value to your variables when you first declare, the value they hold is some random value.

To save space, you can combine variable declaration and assignment into one statement, as demonstrated here:

Int16 intCurrentAge = 100;

You can even declare and assign values to multiple variables in the same statement, as demonstrated next:

Int16 intMinimumAge = 10, intMaximumAge = 120;

Defining Local Variables

Local variables can be referenced only within the block or function where they are defined. Therefore, they are not accessible to other parts of a Visual C++ application.

Hint

A block is a collection of statements that are processed as a unit. Blocks in Visual C++ begin with an opening curly brace ({) and end with a closing brace (}).

For example, the following statements demonstrate how to declare and assign data to a local variable name blnGameOver within a block:

if( intCounter > 10 )
{
  Boolean blnGameOver;
  blnGameOver = false;
}

Because the blnGameOver variable is defined within a block, it cannot be referenced from anywhere outside the block. Similarly, the following example demonstrates how to declare and assign data to a local variable named strMessage within a procedure:

private: System::Void button1_Click(System::Object^
sender, System::EventArgs^  e)
{
  String^ strName = gcnew String("");
  strName = "Smith";
  MessageBox::Show( strName );
}

Local variables exist only while the block or procedure that declares them is executing. When the block or procedure ends, Visual C++ destroys any local variables. This process frees up memory that the variable used. Thus, using local variables can help reduce the overall amount of memory used by your application when compared to static variables, which have a longer lifetime.

Defining Static Variables

A static variable is one that is declared at the block or function level using the static keyword. Static variables can be referenced only within the block or procedure where they are defined; therefore, other parts of a Visual C++ application cannot access them. However, unlike local variables, a static variable continues to exist after the block or procedure that contains it has finished executing. In fact, a static variable exists as long as your application runs. The following example demonstrates how to use a static variable:

private: System::Void button1_Click(System::Object^
sender, System::EventArgs^ e)

{
  static Int16 intCounter = 0;
  intCounter += 1;
}

One good use for static variables is to create a procedure that behaves differently based on the number of times it has been executed. You can accomplish this by declaring a static variable with a data type of Int16, incrementing its value by 1 each time the procedure executes, and adding programming logic for the procedure to behave differently when the value of the static variable reaches a certain number. You will see an example of this in this chapter's game program.

Defining Variable Scope

As discussed earlier, every variable has a scope that defines whether a given block of code can see and use it. Because blocks of code are more or less defined by a set of opening and closing braces in Visual C++, braces set the limits of any variable's scope. If a variable is declared within a set of braces, it is invisible outside those braces. This feature of the C++ language allows you to create and use variables right in the middle of your program without having to worry that operations will contaminate them later on.

This rule of visibility works only one way, though. Variables that are declared outside of a block of code can be "seen" and used by the code within an inner set of braces. This works to your advantage because you often need to have some code that is within braces use a variable that was declared well above (and hence outside of) where the changes need to take place.

Rules for Naming Variables

You need to be aware of a few rules that govern the naming of variables. Failure to follow these rules, listed next, results in an error.

  • Variable names must begin with either an alphabetic character or the underscore character.

  • Variable names cannot include spaces.

  • Variable names cannot be reserved words.

Variable names must be unique. Names are case sensitive, meaning that variables such as userName, UserName, USERNAME, and username are treated as separate variables. So, in general, no two variables can have the same name. The exception to this involves the variable's scope, or visibility to other parts of your program. (See the previous section in this chapter titled "Defining Variable Scope" for more information.) Despite the flexibility that you have in naming your variable, it is best if you are consistent and avoid similarly spelled variables. Doing otherwise can make it difficult to understand your code and find and fix problems later on.

Another useful guideline involves giving your variables names that reflect their purpose. Like a constant, a good variable tells you at a glance why it is in the code. Using textCounter might be preferable to textCntr for that reason. The more your variable names describe their function, the more logical and organized your code will appear.

Above all, you should strive to avoid ambiguity. If you have a program that deals with containers and counters, cntr is likely a bad idea for a variable's name. So, too, is temp if you're dealing both with temporary variables and temperatures.

Image from book
IN THE REAL WORLD

You have probably noticed that I have been assigning descriptive variable names when declaring variables that help to identify their purpose or contents. This makes program code easier to read and understand. You also might have noticed that I am preceding each variable name with a three-character prefix that identifies the type of data associated with the variable, making things easier to understand. I recommend that you follow a similar approach when naming your own variables. For your convenience, you might want to use the prefixes shown in the following list:

  • Boolean: bln

  • Boolean: f (for a flag that is turned on and off)

  • Byte: byt

  • Date: dtm

  • Double: dbl

  • Error: err

  • Integer: int

  • Long: lng

  • Object: obj

  • Single: sng

  • String: str

Image from book

Recognizing Variables as Objects

As you might recall from Chapter 1, "An Introduction to Visual C++ 2005 Express," Visual C++ is an object-oriented programming language. The object-oriented programming aspect is so deeply integrated into Visual C++ that even variables are treated like objects. Try the following example to see this concept in action:

  1. Start Visual C++ and create a new Visual C++ application.

  2. Double-click on the default form (form1) to open the Code Editor and access the form's Load event procedure.

  3. By default, Visual C++ generates the following code to set up the application's response to the Load event for you:

    private: System::Void Form1_Load(System::Object^ sender,
          System::EventArgs^ e)
{
}

  4. Declare a variable named intUserAge as an Int16 and assign it a value of 55, as shown here:

    private: System::Void Form1_Load(System::Object^ sender,
          System::EventArgs^  e)
{
  Int16 intUserAge = 55;
}

  5. Next, type the following partial statement exactly as shown here:

    MessageBox::Show( intUserAge

  6. Because Visual C++ treats variables as objects, IntelliSense kicks in and displays all the properties and methods available, as shown in Figure 5.7.

  7. Click on ToString and press Enter. The statement should look like the example shown here:

    MessageBox::Show( intUserAge.ToString() );
    Trick

    You can use the ToString method to return a string showing the value for the specified variable, whether it is a number or a date.
Image from book
Figure 5.7: Using IntelliSense to view methods and properties associated with a variable object.

Functions and Methods for Manipulating Strings

Because most people deal with information in the form of text more than in the form of numbers, the String data type is one of the most useful aspects of Visual C++. Technically, parts of this data type are a little too advanced to cover at this point. But as you can see from past chapter games and examples, the String data type is so useful that we had to start using it even before we understood it.

Hint

A string is a series of one or more characters, which might include alphabetic, numeric, and special characters, in addition to spaces. It is defined by enclosing the characters within a pair of double quotation marks ("").

Let's look at some basic aspects of the String data type first. A variable with a data type of String can store up to 2 billion characters. The actual limit depends on your system's available memory, although for most purposes, you will probably never need to approach that limit.

A String data type has such a range because it is declared in a way that gives it access to more memory resources than a normal variable. A String makes use of the gcnew keyword to gain access to this memory. At this point, it is too early to cover gcnew in detail, but it is discussed in depth in Chapter 8, "Enhancing Code Structure and Organization." For now, just know that it is a way of giving certain data types access to the memory they need.

Hint

gcnew is a new Visual C++ operator that gives variables access to memory resources that are managed by the .NET Framework, with support for garbage collection (a feature of .NET that takes care of freeing memory automatically). If you prefer to use the C++ standard new operator, you may use it instead of gcnew and take care of freeing memory yourself.

Declaring String Variables

Unlike other .NET languages such as Visual Basic, Visual C++ does not automatically manage strings. Programmers must go through a few extra steps to use them. The .NET Framework does simply use them, however, after you get the hang of how they work.

You declare a String data type using the following format:

String^ strVariableName = gcnew String( "" ):

There are three important elements to creating a string in Visual C++. First, note the special symbol before the variable, called p-hat (^). This symbol denotes that strVariableName is a handle, a special type of variable that can reference large sections of memory. As with gcnew, the details of handles are discussed in greater detail in Chapter 8.

Following gcnew, you see a repetition of the String data type. However, this data type has a special format. The parentheses and quotes are how the String data type is setting its starting value. You can place any text you like within the quotes. Empty quotes (two quotation marks side by side) indicate that the string has no initial value or is empty. You can, however, place text between the quotes, as in the next example:

String^ strWelcome = gcnew String( "Welcome!" );

This line of code creates a variable (technically a handle) called strWelcome of type String. This variable is then attached to memory resources created by gcnew. The memory resource created by gcnew contains the text value of Welcome.

If this is a bit fuzzy at this point, an example should help to clear things up.

  1. Start Visual C++ and create a new Visual C++ application.

  2. Double-click on the default form (form1) to open the Code Editor and access the form's Form1_Load event procedure.

  3. By default, Visual C++ generates the following code to set up the application's response to the Load event for you:

    private: System::Void Form1_Load(System::Object^
sender, System::EventArgs^  e)
{
}

  4. Add the following code, which declares a variable of String type named strWelcomeMessage and initializes it with Welcome to the application! The result is then displayed in a dialog box.

    private: System::Void Form1_Load(System::Object^
sender, System::EventArgs^  e)
{
  String^ strWelcomeMessage = gcnew String(
  "Welcome to the application!" );
  MessageBox::Show( strWelcomMessage );
}

  5. Run the application. You see text in quotes.

  6. To illustrate how strings can be assigned values, add the following text, shown in bold, to the Form1_Load function:

    private: System::Void Form1_Load(System::Object^  sender,
System::EventArgs^  e)
{
  String^ strWelcomeMessage = gcnew String(
  "Welcome to the application!" );
  MessageBox::Show( strWelcomeMessage  );
  strWelcomeMessage = "";
  MessageBox::Show( strWelcomeMessage );
  strWelcomeMessage = "Have a nice day!";
  MessageBox::Show( strWelcomeMessage );
}

  7. Run the program. You see the first welcome dialog box, followed by a blank dialog box. This is the result of the strWelcomeMessage = ""; line of code. When you select the OK button, you are taken to the last line, which presents another message.

Using Built-In String Methods

One of the great strengths of Visual C++ is the abundance of string manipulation methods that it provides. Visual C++ offers several ways to change the text that your application displays. In fact, the language provides so many different ways of manipulating strings that it is unlikely you will ever need to develop your own custom string-handling functions.

In previous chapters, you saw a number of examples of strings being used to convey information. Visual C++ provides a number of other string manipulation tools, including the properties and methods listed in Table 5.2.

Table 5.2: String Handling Properties and Methods
String Object Methods | Description
String::ToLower | Converts a string to all lowercase
String::ToUpper | Converts a string to all uppercase
String::Length | Retrieves the length of a string
String::SubString | Extracts a portion of a string
String::ConCat | Combines two strings
String::Chars | Searches for one string within another string
String::TrimStart | Removes leading blank spaces from the left side of a string
String::TimeEnd | Removes trailing blank spaces from the right side of a string

As a quick example of how to use these functions and methods, look at the following example:

private: System::Void Form1_Load(System::Object^  sender,
System::EventArgs^  e)
 {
        String^ strMsg =
        gcnew String("Once upon a time in a very far away land" );
        MessageBox::Show( "String is " + strMsg->Length +
        " characters long." );
        strMsg = String::Concat( strMsg, " there lived a giant." );
        MessageBox::Show( "String is now " + strMsg->Length
        + " characters long." );
}

In this example, the Length property displays the number of characters that make up the strMsg variable's value. The value increases after String::Concat is called because this method adds strings together. In this case, strMsg is being set to equal the addition of itself (the second strMsg) and a new text string.


WORKING WITH ARRAYS

Sometimes it's convenient to link similar data. One big advantage is that you gain the convenience of being able to use one variable name to refer to multiple items. Without arrays, if you needed 100 variables of a certain type, you would have to name each one of them separately.

But more importantly, you can perform all kinds of optimized searches and organizational tricks when you can rely on the fact that your data is contiguous—that is, predictably located in a linear sequence in memory.

Hint

An array is an indexed List of data. The first piece of data stored in an array is assigned an index position of 0. The next piece of data is assigned an index position of I, and so on. You can reference any data stored in the array based on its index position.

An array is a repeating sequence of a single data type with a fixed size. Each item of the array is known as an element. You declare the type of data that will make up each element and the name you want to call it. Then you specify how many elements you want in brackets after the array name. Upon declaration, each element is reserved in as many adjacent blocks of memory as you've requested.

Defining Arrays

The format for a basic array takes the size (number of elements) in brackets:

<data type>     <variable name>[<size>

Following is an example of an array:

Int16 intCodeArr[50];       //A list of 50 integers

When you declare an array, it is as if you've declared n number of variables of the same type, where n is the quantity you've specified in brackets. Because computers count beginning with zero, your list of elements begins at zero and runs to just one under the number you choose. So if you declare an array often elements, it's important to know that the list starts at zero and extends to nine.

Just as any variable is filled with garbage if you fail to initialize it, arrays, too, must be initialized. You have two options for doing so: You can either initialize an array when you first declare it, or you can initialize each element.

The former method is practical for relatively small arrays. Small essentially means as many elements as you have the patience to specify by hand. To initialize an array when you declare it, you assign it to a comma-delimited list of values surrounded by braces. Each value is specified as a literal:

Double dblUserAverage[5] = { 0.25, 0.17, 0.22, 0.98, 0.77 };

If you use this method, you can omit the number of elements in the array. Visual C++ automatically determines the size of the array when you compile the program. Here is an example:

Int16 intCodeCombo[] = { 7,2,3,4,5,6,9,7,1 };

As you can see, the manual initialization method can become cumbersome quickly. Alternatively, if you know that you want all the elements initialized to the same value, you can specify a single literal value within the braces regardless of the size of the array:

Double initialDistances[100] = { 0.0 };

Unfortunately, using braces works only when you're declaring the array. A common way of initializing an array, which you can use anywhere after your array is declared, is to use an iterator. An iterator is a fancy word for a counter, which you commonly use to keep track of values to control a loop. By using an iterator within the brackets of your array, you can traverse every element:

Int32 highScores[kNumHighScores];
for( int i; i < kNumHighScores; i++ )
    highScores[i] = 0;

This code example loops through an array of high scores and sets each element to zero. Because you have fine control over an iterator, you can move up or down the elements of the array in any way you want. This allows you to assign a different value to every fifth element, for example, if you need to. Or you can assign values based on a formula.

Trap

Take care that when you access the elements of an array, you stay within the bounds of the elements you've declared. If you try to access areas outside of this range, you might get nasty results. Your array is a location in memory. If you try to write values to or access areas that your program doesn't have permission to touch, you might cause insidious, hard-to-find bugs or even mysterious crashes in your program.


WORKING WITH STRUCTURES

Structures are yet another way of organizing the data within your code. They give you the ability to create new data types composed of existing ones, or even ones you create. Their main benefit is that they keep related data together, which helps not only in keeping your program clear, but in performing data manipulation.

The basic component of a structure uses the struct keyword, followed by the name of the new composite data type you created, and then braces. Within the braces, you specify the data types that you want the structure to be composed of. Although a structure uses braces like a function or control structure, because it is a data type, the braces must be followed by a semicolon.

Here is one example of a structure:

struct UserType
{
    Int16 IDCode;     //User code
    Boolean fActive; //Current status
};

The elements within this structure are known as the members of the structure. After you've created this structure, you're free to use it as you would a fundamental or custom enumerated type you've created. For instance, you can declare a single instance of the new type or an entire array of the following:

UserType admin;
UserType subscribers[1000];

This code creates a single player and an array of 1,000 subscribers.

Unlike fundamental data types such as Intl6 or Single, however, you must access the members of your struct type individually. To access the elements of a structure, you use the access specifier, which is a period between the structure variable's name and the member you want to access:

player.fAlive = true;
user.IDCode = 1000;

Structures can even be composed of other structures. This allows you to create even more complex data types. For instance:

struct CoordType
{
    Int16 x, y, z;
};

struct VehicleType
{
    struct CoordType coordinates;
    Int16 hullIntegrity;
    Single velocity;
};

In this example, the VehicleType structure uses a presumably widely used utility structure for storing coordinates in a game world. The coordinates can be initialized in this way:

VehicleType playerVehicle;
playerVehicle.coordinates.x = 0;
playerVehicle.coordinates.y = 0;
userVehicle.coordinates.z = 0;


RESERVED WORDS

The Visual C++ programming language is made up of a large number of keywords (also referred to as reserved words) that have specific meanings. An example of a reserved word is void, which is a data type. It signals to the compiler that you plan to use functions or data in a certain way. Because it is reserved (for the compiler), you can only use the keyword in your Visual C++ applications when you follow its syntax rules. In other words, you cannot use it as a variable name or as a name for any other programming construction (such as a constant, array, structure, or function name).

Hint

A reserved word is one that Visual C++ sets aside for the specific purpose of communicating instructions to the compiler. You cannot use a reserved word in your application for variable names.

Table 5.3 provides a listing of Visual C++ reserved words for your review.

Table 5.3: List of Visual C++ Reserved Words
break | case | catch | char
class | const | const_cast | continue
declaration | default | delete | deprecated
directive virtual | dllexport | dllimport do | double
dynamic_cast | else | enum | explicit
extern | false | float | for
friend | gcnew | goto | if
inline | int | long | mutable
namespace | new | noinline | noreturn
nothrow | novtable | operator | private
property | protected public | register | reinterpret_cast
return | selectany short | signed | sizeof
static | static_cast | struct | switch
template | this | thread | throw
true | try | typedef | typeid
typename | union | unsigned | using
using | void | volatile wchar_t | while


BACK TO THE STORY OF MIGHTY MOLLY

Now it is time to turn your attention back to the development of this chapter's game project, The Story of Mighty Molly. To create this game, you follow the same five development steps that you used to create previous chapter projects.

Designing the Game

The Story of Mighty Molly is played on a single window, although the () function and MessageBox::Show method are used to collect and display stored input and output. The game is therefore made up of one form and the 11 controls listed in Table 5.4.

Table 5.4: Form Controls for the Story of Mighty Molly
Control Type | Control Name | Description
Label | lblWelcomeMsg | Displays the game's welcome message
Label | lblCreature | Displays the creature question
Label | lblRoom | Displays the room question
Label | lblColor | Displays the color question
Label | lblWeapon | Displays the weapon question
Label | lblFood | Displays the food question
Button | btnintroText | Shows the intro
Button | btninstructions | Shows the instructions
Button | btnTellStory | Tells the story
TextBox | txbCreature | Gets the creature
TextBox | txbRoom | Gets the room
TextBox | txbColor | Gets the color
TextBox | txbWeapon | Gets the weapon
TextBox | txbFood | Gets the food
StatusStrip | stsControl | Holds the status strip controls
StatusLabel | tslMessage | Provides the encouragement messages
StatusLabel | tslProgress | Displays word progress
ProgressBar | tspProgressBar | Provides a graphical indication of the game's progress

Step 1: Creating a New Visual C++ Project

The first step in creating The Story of Mighty Molly is to start Visual C++ and open a new project.

  1. If you have not already done so, start up Visual C++ 2005 Express and then click on File, New Project. The New Project dialog box appears.

  2. Select Windows Application template.

  3. Type The Story of Mighty Molly as the name of your new application in the Name field located at the bottom of the New Project window.

  4. Click on OK to close the New Project dialog box.

Visual C++ creates a new project for you, including an empty form, which you'll use to create the game's user interface.

Step 2: Creating the User Interface

Now it's time to add the necessary controls that make up the game's user interface. The overall design of the game's interface is shown in Figure 5.8.

  1. Start by resizing the form so that you have space to add several controls, including text boxes.

  2. Add six Label controls to the form. By default, Visual C++ assigns the names label1 through label6 to these controls. Position the first label roughly near the top of the form, and the other five vertically on the left side.

  3. Add five TextBox controls to the form and line them up vertically along the right side, as shown in Figure 5.8. By default, Visual C++ names these controls textBox1 through textBox5.

  4. Add three Button controls to the form and line them as shown in Figure 5.8. By default, Visual C++ names these controls button1 through button3.

  5. Add a StatusStrip control to the form. By default, Visual C++ assigns this control the name statusStrip1.

  6. Add two ToolStripStatusLabel controls to the Status Strip. By default, Visual C++ assigns these controls the names of toolStripStatusLabel1 and toolStripStatusLabel2.

  7. Add a ProgressBar control to the form.

  8. Add a ToolTip control to the form.

  9. Set the tab ordering so that focus starts with the first TextBox control and moves through each to the last. Doing so ensures a smoother experience when playing the game.

Image from book
Figure 5.8: Completing the interface design for The Story of Mighty Molly.

The overall layout for the application's form is now complete.

Step 3: Customizing Form and Control Properties

It is time to customize the form and its controls. By this point in the book, you should be comfortable with the steps involved in modifying form and control properties. Instead of walking you through each step that is involved in modifying every control, I am going to provide you with tables for each control that identify the property changes that need to be made and leave it up to you to make the changes.

The property modifications that need to be made to form1 are listed in Table 5.5.

Table 5.5: Property Changes for Form1
Property | Value
Name | frmGame
FormBorderStyle | Fixed3D
MaximizeBox | False
MinimizeBox | False
StartPosition | CenterScreen
Text | The Story of Mighty Molly

The property changes for each of the form's six Label controls are listed in Table 5.6.

Table 5.6: Property Changes for the Label Controls
Control | Property | Value
Label1 | Name | lblWelcomeMsg
 | Font.Bold | True
 | Text | Welcome to The Story of Mighty Molly.
label2 | Name | lblCreature
 | Text | What creature scares you the most?
label3 | Name | lblRoom
 | Text | What's the worst room in a castle?
label4 | Name | lblColor
 | Text | What's your favorite color?
label5 | Name | lblWeapon
 | Text | What kind of weapon can you find lying on the ground?
label6 | Name | lblFood
 | Text | What is your favorite food?

The property changes for each of the three Button controls are listed in Table 5.7.

Table 5.7: Property Changes for the Button Controls
Control | Property | Value
button1 | Name | btnlntroText
 | Font.Bold | True
 | Size | 90,23
 | Text | Introduction
 | ToolTip | Click here to learn about Mighty Molly.
button2 | Name | btnInstructions
 | Font.Bold | True
 | Size | 90,23
 | Text | Introduction
 | ToolTip | Click here to learn how to play.
button3 | Name | btnTellStory
 | Font.Bold | True
 | Size | 100,23
 | Text | Tell the Story!
 | ToolTip | Click here once all the text boxes are filled to tell the story.

The property changes for the StatusStrip control are listed in Table 5.8.

Table 5.8: Property Changes for the StatusStrip Control
Control | Property | Value
StatusStrip1 | Name | stsControl
 | Size | 452,22

The property changes for each of the five TextBox controls are listed in Table 5.9.

Table 5.9: Property Changes for the TextBox Controls
Control | Property | Value
textBox1 | Name | txbCreature
 | Size | 150,20
textBox2 | Name | txbRoom
 | Size | 150,20
textBox3 | Name | txbColor
 | Size | 150,20
textBox4 | Name | txbWeapon
 | Size | 150,20
textBox5 | Name | txbFood
 | Size | 150,20

The property changes for the ToolStripStatusLabel control are listed in Table 5.10.

Table 5.10: Property Changes for the ToolStripStatusLabel Control
Control | Property | Value
toolStripStatusLabel1 | Name | tslMessage
 | BorderSides | All
 | BorderStyle | Sunken
 | Spring | True
 | Text | Get Ready!
toolStripStatusLabel2 | Name | tsl Progress
 | BorderSides | Left, Top,Bottom
 | BorderStyle | Sunken
 | Text | Progress:

The property changes for the ProgressBar control are listed in Table 5.11.

Table 5.11: Property Changes for the ProgressBar Control
Control | Property | Value
tootStripProgressBar1 | Name | tspProgressBar
 | Step | 20

The property changes for the ToolTip control are listed in Table 5.12.

Table 5.12: Property Changes for the ToolTip Control
Control | Property | Value
toolTip1 | Name | tltGameTips

Step 4: Adding a Little Programming Logic

Now that the game's user interface has been created and you have modified the appropriate form and control properties, it is time to begin coding. Start by clicking on the button labeled Introduction. You are taken to the btnIntroText_Click function. This function displays text in a dialog box that introduces the player to the world of Mighty Molly. The strDialogText variable is initialized with the large string that contains the introduction. Notice that the string is all one string, even though it is broken up on many lines. In Visual C++, strings that are next to each other or on a separate line without a semicolon are considered one string.

private: System::Void btnIntroText_Click(System::Object^ sender,
          System::EventArgs^  e)
       {
          //Store intro in dialog string
          String^ strDialogText = gcnew String(

          "Mighty Molly was the bravest of all the Mollys."
          "She was fearless in battle and relentless in "
          "everything else. No one who ever met her was "

          "left untouched, for the mighty one had a "
          "certain mystical way about her that almost "
          "magically seemed to rub off on those "
          "around her. n"
          "Certainly, there never was before and may "
          "never be again anyone as mighty as "
          "Mighty Molly. For those of you who "
          "have not heard the tales of the mighty one, "
          "you are in luck, because today you get the "
          "chance to participate in the telling of the "
          "mighty one's last great adventure!" );
          //Show into
          MessageBox::Show( strDialogText, "Introduction" );

       }

Click on the button that reads Instructions, which produces the btnInstructions_Click function. It performs the same steps as the Introduction button, except that the text is smaller. Again, strDialogText is being used in this function. However, because of the limits of scope, it is considered by Visual C++ to be a separate variable even though it shares the same name.

private: System::Void btnInstructions_Click(Systern: :Object^ sender,
          System::EventArgs^  e)
       {
        //Store intro in dialog string
       String^ strDialogText = gcnew String(
       "To play the game and participate in the "
       "telling of 'The Story of Mighty Molly,' "
       "you must enter text in the five boxes"
       "and then click on the 'Tell the Story!' "
       "button." );
       //Show instructions
       MessageBox::Show( strDialogText, "Instructions" );
      }

Click on the Tell the Story button. This generates the btnTellStory_Click function, as shown later. This function appears to be quite involved, until you realize that it only looks that way because it has so much text. The btnTellStory_Click function first tests to see if all text was entered. It does so by setting a Boolean variable, fAllTextEntered to true, optimistically assuming that all text has been entered by the time the user clicks on the button. Then the function examines the text contents of each TextBox control. The String method IsNullOrEmpty is called for each one. If the text string being examined is found to be empty, fAllTextEnterad is set to false. This then triggers an error message and the exiting of this function via the return keyword. If all text has been entered, the strDialogText String variable is used again. However, because it is in a new function, it is not the same as the other strDialogText variables used in the introduction and instruction functions.

After strDialogText has been initialized with the first part of the story, string after string is appended to it. The method that performs this is the String::Cat function, which allows several strings to be added to a string. Finally, a MessageBox::Show method displays the huge string that was assembled:

private: System::Void btnTellStory_Click(System::Object^ sender,
          System::EventArgs^  e)
       {
        Boolean fAllTextEntered = true;
        //Test to see if all text was entered
        //If any text string is empty, the flag
        //  fAllTextEntered will be set to false
        if( String::IsNullOrEmpty( txbCreature->Text ) )
          fAllTextEntered = false;
        if( String::IsNullOrEmpty( txbRoom->Text ) )
          fAllTextEntered = false;
        if( String::IsNullOrEmpty(  txbColor->Text ) )
          fAllTextEntered = false;
        if( String::IsNullOrEmpty(  txbWeapon->Text ) )
          fAllTextEntered = false;
        if( String::IsNull0rEmpty( txbFood->Text ) )
          fAHTextEntered = false;
        //If no text was entered, issue an error
        if( fAllTextEntered == false )
        {
          MessageBox::Show( "You must enter all text"
          " to continue the game!", "Error!",
          MessageBoxButtons::OK, MessageBoxIcon::Stop );
          return; // Exit this function
        }
        //Assemble the strings that tell the story

String^ strDialogText = gcnew String(
       "A long time ago in a land far away, there "
       "was a castle where the great Prince William lived. "
       "Prince William was a kindly boy who cared more for "
       "his people than he did for himself. One day a storm "
       "from out of nowhere swept upon the land where "
       "Prince William lived. A mysterious " );
//Append the next group of text
strDialogText = String::Concat( strDialogText,
       txbColor->Text,
       " mist soon followed the storm. Out of this mist "
       "appeared an evil ", txbCreature->Text, ".nnThe
//Append the next group of text
strDialogText = String::Concat( strDialogText,
       txbCreature->Text, "'s heart was dark and cold. The ",
       txbCreature->Text, " killed William's father, the "
       "good King Stefford. So William became the new king. "
       "Summoning up all his bravery, King William rode out "
       "ahead of his armies to do battle with the fearsome ",
       txbCreature->Text, ". However, King William's army was "
       "quickly crushed and King William was captured and "
       "locked away in the castle's " );
//Append the next group of text
strDialogText = String::Concat( strDialogText,
txbRoom->Text, ".nn"
       "A call went out from far and wide for a great hero "
       "to rescue King William. But no one dared answer "
       "the call except for Mighty Molly, mightiest of all "
       "the Mollys. Within a fortnight the mighty one "
       "arrived in the land where King William once ruled. "
       "Upon hearing of the mighty one's arrival, the",
       txbCreature->Text, " quickly rushed out to meet her."
"nnMighty Molly and the dreaded ",
       txbCreature->Text );
//Append the next group of text
strDialogText = String::Concat( strDialogText,
       " fought for 4 days and 4 nights. As they did battle "
"a cloud of ", txbColor->Text, " dust gathered around "

          "them, making them invisible to all who tried to "
          "watch. Finally, at the end of the 4th day, the ",
          txbCreature->Text, " fell dead at the mighty one's feet."
          "With her strength all but gone, Mighty Molly had "
          "slain the " );
   //Append the next group of text
   strDialogText = String::Concat( strDialogText,
   txbCreature->Text, " with her final "
          "blow, using a large ", txbWeapon->Text, " that she had "
          "fallen on during the fight.nn"
          "When the fight was finally over and the ",
   txbColor->Text, " mist finally cleared, " );
   //Append the next group of text
   strDialogText = String::Concat( strDialogText,
          "a great roar arose from the people who had gathered "
          "around to watch. Happily, the people followed the "
          "mighty one to King William's castle where she "
          "freed him. In gratitude, good King William declared "
          "a holiday and ordered his cooks to prepare a great "
          "feast of meat, wine and ", txbFood->Text, ". At the "
          "feast, King William offered to give his kingdom over "
          "to Mighty Molly and he knelt at her knees and "
          "offered up his crown. But Mighty Molly turned down "
          "his offer, for she knew that King William was the "
          "true king and that as mighty as she was, she needed "
          "to be mightier still to rule as wisely as King "
          "William.nnThe End." );
   MessageBox::Show( strDialogText,
   "The Story of Mighty Molly" );
}

The final step involves triggering the ProgressBar control's updates and seeing the unique messages that appear in the Status Strip. Click on each text box in turn and add the following code:

private: System::Void txbCreature_TextChanged(System::Object^
          sender, System::EventArgs^ e)
       {
        static Boolean fProgressBarUpdated = false;

        //Set the progress bar message
        tslMessage->Text = "Be Brave!";
        //Only update the progress bar once
        if( fProgressBarUpdated == false )
        {
          tspProgressBar->PerformStep();
          fProgressBarUpdated = true;
        }
     }
private: System::Void txbRoom_TextChanged(System::Object^ sender,
          System::EventArgs^  e)
       {
        static Boolean fProgressBarUpdated = false;
        //Set the progress bar message
        tslMessage->Text = "Any Room Will Do!";
        //Only update the progress bar once
        if( fProgressBarUpdated == false )
        {
          tspProgressBar->PerformStep();
          fProgressBarUpdated = true;
        }
     }
private: System::Void txbColor_TextChanged(System::Object^ sender,
          System::EventArgs^  e)
       {
        static Boolean fProgressBarUpdated = false;
        //Set the progress bar message
        tslMessage->Text = "Any Color Will Do!";
        //Only update the progress bar once
        if( fProgressBarUpdated == false )
        {
          tspProgressBar->PerformStep();
          fProgressBarUpdated = true;
        }
     }
private: System::Void txbWeapon_TextChanged(System::Object^
          sender, System::EventArgs^  e)
       {

        static Boolean fProgressBarUpdated = false;
        //Set the progress bar message
        tslMessage->Text = "Pick Something Strong!";
        //Only update the progress bar once
        if( fProgressBarUpdated == false )
        {
          tspProgressBar->PerformStep();
          fProgressBarUpdated = true;
        }
     }
private: System::Void txbFood_TextChanged(System::Object^
          sender, System::EventArgs^  e)
       {
        static Boolean fProgressBarUpdated = false;
        //Set the progress bar message
        tslMessage->Text = "Pick Something Tasty!";
        //Only update the progress bar once
        if( fProgressBarUpdated == false )
        {
          tspProgressBar->PerformStep();
          fProgressBarUpdated = true;
        }
     }

These five functions, which are nearly identical, are responsible for updating the Progress Bar and Status Strip messages. The identical fProgressBarUpdated variable in each demonstrates the concept of scope, because although these variables share the same name, they are in fact regarded by Visual C++ as entirely separate. The difference here is that each is prefaced by the static keyword. This directs Visual C++ to maintain both contents each time the function is executed. The function is, in fact, executed each keystroke as the user is typing in the TextBox control. The first time that the text box receives a keystroke, fProgressBarUpdated is defined with a value of false. After the Status Strip Label is updated with the appropriate message, fProgressBarUpdated is tested to see if it is false. The first time this happens, the code block beneath the test fProgressBarUpdated == false executes. This code block causes the Progress Bar to update itself, advancing one step. The fProgressBarUpdated variable is then set to true. Because no other logic alters it, the fProgressBarUpdated variable will forever be true. The effect of this action is that the Progress Bar is updated once and only once, when it receives its first keystroke.

Step 5: Testing the Execution of The Story of Mighty Molly

Okay. That's it. The Story of Mighty Molly should be ready to run. Press F5 and put the game through its paces. If you have errors, double-check your typing. When you think you have things working the way you want, try testing the game again, this time feeding data that the game doesn't expect to receive and seeing how it handles it.


SUMMARY

In this chapter, you learned how to store and retrieve data using a number of different programming constructs, including constants, variables, arrays, and structures. You learned how to specify the data type, to convert data from one data type to another, and to control variable scope. You also learned how to add comments to your Visual C++ applications and to work with the ProgressBar control. Before you move on to Chapter 6, "Applying Conditional Logic," look at the following challenges and see if you can improve The Story of Mighty Molly.


CHALLENGES

  1. Modify the story by giving players the ability to change background colors, font types, and font sizes.

  2. Create a unique-looking icon for the game, display the icon on the application's title bar, and put an icon in the System Tray when the game is running.

  3. Modify the game so that the player can specify additional story inputs, including the name of the story's main character.


Chapter 6: Applying Conditional Logic

OVERVIEW

For your application to be truly effective, it must be able to make decisions. It must be able to distinguish between two different situations and execute different code based on criteria you choose. For example, when examining user input, you can use conditional logic to alter the flow of your program, causing it to execute only those sections of code that are relevant. This allows you to create applications that respond dynamically and give the user an interactive experience. In this chapter, you learn how to apply conditional logic using variations of the if and switch statements. You also gain a better understanding of this logic through development of this chapter's game project, the Guess a Number game.

In this chapter, you learn the following:

  • How to test two logical conditions

  • How to provide for alternative courses of action

  • How to embed conditional statements to create more complicated conditional logic tests

  • How to rest multiple conditions against a single value


PROJECT PREVIEW: THE GUESS A NUMBER GAME

This chapter's project is a Visual C++ application called the Guess a Number game. By developing this game, you have several opportunities to apply your knowledge of conditional logic. Figures 6.1 through 6.4 provide a sneak preview of the Guess a Number game and give an overview of the game's overall execution.

Image from book
Figure 6.1: The game begins by allowing the player to specify configuration options, including the range of numbers to pick from and the amount of information the game displays.
Image from book
Figure 6.2: When gameplay starts, the player's access to the configuration options is disabled and the player is prompted to take the first guess.
Image from book
Figure 6.3: The game gives players clues to help them home in on the answer. It also displays a running count of the number of guesses the player makes.
Image from book
Figure 6.4: At the end of each game, the player gets a chance to modify the game's configuration options and reset the score.

After you have created and run this game, you'll have a sound foundation of how to drive your applications using sophisticated conditional logic tests. You will, as a result, be ready to begin building fairly complex programs. You will also have a better basis from which to understand the remaining programs in the coming chapters.


APPLYING CONDITIONAL LOGIC

Conditional logic is easy to use and understand. We employ it in our daily lives to make basic decisions. For example, when shopping, we might decide to buy an item or not based on its sale price. Likewise, based on what time we awake in the morning, we might decide to rise or sleep a little longer. There is really no difference between this type of logic and the conditional logic that you'll learn to apply in your Visual C++ applications.

Underlying any conditional logic test is an evaluation that resolves to either true or false. Based on the results of this test, different actions might be taken. To help facilitate the development of conditional logic, Visual C++ gives you two different statements, each of which is suited to different situations. These statements are as follows:

  • if. This statement provides the ability to test a condition and, based on the result, execute one or more program statements.

  • switch. This statement allows you to perform several tests against a single value and to execute one or more statements if the value matches another value.


THE IF STATEMENT

You might have seen that in previous chapters, several of the games used the if statement. This was done because conditional tests are vital to creating functional applications. In fact, it is nearly impossible to develop a program of much complexity without the aid of conditional logic. For example, in the Click Race game that you created in Chapter 2, "Navigating the Visual C++ 2005 Express Edition Environment," you set up an if statement to change the functionality of the game. The code, shown next, disabled the game's two buttons after its timer reached 30 seconds.

if( intTimerCounter == 30 )
{
  //If the timer reaches 30, disable it
  button1->Enabled = false;
  button2->Enabled = false;
}

In the Speed Typing game, featured in Chapter 3, "Creating an Application Interface," you used several if statements to control program flow. For example, you used five if statements to determine which text statements the game should display, as shown here:

 //Display game sentences according to level
if( intcount == 0 )
  txtDisplay->Text = "Once upon a time there "
  "were three little pigs.";
if( intCount == 1 )
  txtDisplay->Text = "In days gone by times "
  "were hard but the people were strong.";
if( intcount == 2 )
  txtDisplay->Text = "Once in awhile something "
  "special happens even to the worst of people.";

To better understand how if statements work, look at the following example:

if it is below 70 degrees outside
  then I'll dress warmly
else
  I'll wear shorts

This English-like or pseudo-code outline demonstrates how a person might apply conditional logic in everyday life. The first line sets up the conditional test, which is whether it is below 70 degrees outside. The condition, expressed as it is, can only evaluate to true or false. If the tested condition turns out to be true, the actions specified by the second statement are executed. Otherwise, an alternative course of action is taken.

Hint

Pseudo-code is a rough, English-like outline or sketch of one or more program statements. By writing what you are trying to do in pseudo-code and then translating that pseudo-code into actual program statements, you can simplify application development. The pseudo-code, in effect, becomes an initial-Level draft version of your application.
Trick

Writing pseudo-code can speed the development of your applications by allowing you to create appropriate comments and guide the logical flow within a function.

Now that you have seen several examples of the if statement, let's look at some of the different ways you can use it.

if Statement Syntax

The if statement allows you to test two or more conditions. Based on the results, you can then alter your program's logical flow. The if statement has many optional variants, as demonstrated by the following syntax:

if( condition is true )

  perform statement;
else if( condition is true )
  perform statement;
else
  perform statement;

Within this structure are even more variations of how the if statement can be used. These are explored in the sections that follow.

The Single-Line if Statement

The simplest form of the if statement involves a single test and the execution of a single command. The command executes only if the test condition proves true, as demonstrated here:

Int32 intCounter = 0;
if(intCounter == 0 )
  MessageBox::Show("We have a match.");

In this example, the condition being tested determines whether the value assigned to intCounter is equal to 0. If the value assigned to intCounter is equal to 0, the conditional test evaluates to true. This causes the MessageBox.Show method to execute and display a message. However, if the test proves false, the line containing the MessageBox.Show method is skipped, and the application continues on, processing any remaining programming statements.

The main advantage of the single-line if statement is that it allows you to set up one simple, clean test and to execute a single statement only if the test proves true. This allows you to keep your code clear and logically easy to understand.

Multiline if Statements

In most cases, you need to execute more than a single statement in response to a conditional test. When this is the case, you need to use the if statement in the format demonstrated here:

if( condition is true )
{
  perform statement
  perform statement
  ...
}

By bracketing multiple statements, you can cause multiple lines of code to be executed in response to a given condition being true. For example:

Int32 intCounter = 0;
if( intCounter == 0 )
{
  intCounter += 1
  MessageBox::Show("The value of intCounter has been updated." )
}

In this example, there are too many commands to be executed by the if statement. The solution is to place braces around the lines to be executed, creating a block of code. When you use the code this way, you can place any number of statements between the opening { symbol statement and the closing } symbol. Each is executed only if the condition in parentheses evaluates to true.

The if…else Statement

The two previous examples demonstrate how to execute one or more commands when a tested condition evaluates as true. However, if the condition proves false, the statement or statements are skipped. But what if you want to execute one or more alternate commands if the statement proves false? One option is to write a second if statement. For example, suppose that you create a small Visual C++ application, as depicted in Figure 6.5.

Image from book
Figure 6.5: Validating the player age before allowing the game to be played.

In this example, the application consists of a form with a Label, a TextBox, and a Button control. The application requires the player to type an age and click on the button labeled Submit Age before continuing. The following statements show the program code that has been added to the Button control's click event:

private: System::Void btnAge_Click(System::Object^ sender,
System::EventArgs^  e)
{
  Double dblAge = 0;
  Double::TryParse( txtAge->Text, dblAge );
  if( dblAge < 18 )
    MessageBox::Show( "Thanks for playing!" );
  if( dblAge >= 18 )
    MessageBox::Show( "Sorry, you're too old!" );
}

As you can see, the example uses two different if statements within the btnAge function. The first if statement checks to see if the player is less than 18 years old. The second if statement checks to see if the player is 18 or older. If the player is younger than 18, a message is displayed thanking the player for playing. Otherwise, the player is told that he does not meet the age criteria for the game.

Although two if statements certainly get the job done, this example can be made even simpler. Because there are only two logical conditions, one the alternative of the other, a better way to accomplish the same result is to use an if...else statement, as demonstrated here:

private: System::Void btnAge_Click(System::Object^ sender,
System::EventArgs^  e)
{
  Double dblAge = 0;
  Double::TryParse( txtAge->Text, dblAge );
  if( dblAge < 18 )
    MessageBox::Show( "Thanks for playing!" );
  else
    MessageBox::Show( "Sorry, you're too old!" );
}

As you can see, the if...else version of this example is slightly smaller and requires one less conditional test, making the programming logic simpler and easier to follow.

The if…else if Statement

If your application calls for it, you can add the else if keyword one or more times to expand the if statement. Each instance of the else if keyword allows you to test for another alternative condition. To better understand how the if...else if statement works, see the following example, shown in Figure 6.6.

Image from book
Figure 6.6: Using an if...else if statement to process the contents of a ComboBox control.

In this example, a new Visual C++ application has been created, consisting of a form with a Label, a Button, and a ComboBox control.

Trick

The ComboBox control provides a drop-down list from which the user can select a single option. After adding a ComboBox control to a form at design time, you can populate it with choices by locating its Items property in the Properties window and clicking on the (Collection) entry in the Value column. This opens the String Collection Editor, as shown in Figure 6.7. All you have to do now is enter the choices that you want to display in the ComboBox control, making sure to type each option on its own line.

Image from book
Figure 6.7: Using the String Collection Editor at design time to populate the contents of a ComboBox control.

To make a selection, the user must select one of the choices displayed in the ComboBox control and then click on the form's Button control. When this occurs, the code that is assigned to this control's click event, shown in the next example, executes:

private: System::Void btnSubmit_Click(System::Object^
sender, System::EventArgs^  e)
{
  if( cboAge->Text->Contains( "1 – 12" ) )
    MessageBox::Show( "There is a skateboard park just"
    " down the street." );
  else if( cboAge->Text->Contains( "13 – 18" ) )
    MessageBox::Show( "There is a 99 cent movie theater"
    "2 blocks over." );
  else if( cboAge->Text->Contains( "19 – 21" ) )
    MessageBox::Show( "A new dance club has opened"
    "downtown on 3rd Street." );
  else
    MessageBox::Show( "Oh, you must be ready for a"
    "nap!" );
}

As you can see, by adding multiple else if keywords, you are able to setup a logical test that can screen for multiple conditions.


NESTING CONDITIONAL LOGIC

Sometimes your application's logic is too complicated to be represented using the different variations of the if statements. If this is the case, you can greatly extend the power of the if statements by nesting them within one another. Nesting enables you to develop logic that tests for one condition and then further tests other conditions based on the result of the previous test.

Hint

Nesting is the process of embedding one statement within another statement of the same type, such as when you embed if statements to develop more complicated conditional logic.

You've already seen examples of nested if statements in previous chapter game projects. For example, the following code comes from the btnDone_Click event belonging to the Speed Typing game that you built in Chapter 3.

//Handle three strikes
if( intWrong == 3 )
{
  //Inform player that he's a beginner
  if( intCount < 2 )
  {
    MessageBox::Show( "Game Over! Your "
    "typing skill level is: Beginner. "
    "Please play again!" );
    intCount = 0;
    intWrong = 0;
    return;
  }
  //Inform player that he's intermediate
  if( intCount < 4 )
  {
    MessageBox::Show( "Game Over! Your "
    "typing skill level is: Intermediate. "
    "Please play again!" );
    intCount = 0;
    intWrong = 0;
    return;
  }
  //Inform player that he's advanced
  if( intCount < 5 )
  {
    MessageBox::Show( "Game Over! Your "

    "typing skill level is: Advanced. "
    "Please play again!" );
    intCount = 0;
    intWrong = 0;
    return;
  }
}

In the Speed Typing game, the game ends if the player receives three strikes. The number of strikes is stored in the intWrong variable. The game also tracks the number of typing tests passed by incrementing the value assigned to the IntCount variable.

In this example, the value of intWrong is tested first to see if it is equal to 3. If this is the case, a series of three nested if statements is executed. Each further refines the logical condition that the game needs to test for by checking the value assigned to the intCount variable. This creates a more sophisticated test whereby messages are displayed to the player and variables are reset based on both the intWrong and intCount variables matching certain conditions.

Trap

Try to avoid using more than one level of nested if statements. Having several layers of nested if statements within any given if statement can make for code that is difficult to follow logically.


THE SWITCH STATEMENT

You sometimes need to compare one value or expression to a whole series of possible values. One way to accomplish this is to create one if statement for each comparison. However, if you have more than four or five in a row, a switch statement is a better option.

The syntax for the switch statement is shown here:

switch( value )
  case constant value :
    statements
    ...
    break;

  case constant value :
    statements
    ...
    break;

  default :
    statements
    ...
    break;
}

The switch statement allows you to set up a block of code that compares a variable or value with several constant values. It begins with the Visual C++ keyword switch, followed by opening and closing parentheses containing the variable you want to use as a basis for comparison. Following the switch statement is the body of code containing the comparison, in braces. Between these braces, you can insert one or more case statements, each of which defines a constant value to be compared against. You can also include an optional default statement as a sort of catchall. The default statement executes if all the previous case statements fail to result in a match. To better understand how the switch statement works, look at the following pseudo-code example:

switch Temperature
  case if it is 32 degrees stay in bed
  case if it is 70 degrees play the lottery
  default Just read the newspaper

In this example, one value, the temperature, is compared to a number of different values. If any one value, as defined by a case statement, is equal to the value of the temperature, the programming statements associated with that value are executed.

Functionally, the switch and the if...else statements have similar capabilities. However, when performing many successive tests, the switch statement is easier to read. The following code listing illustrates the previous pseudo-code example:

switch( intTemperature )
{
  case 32 :
    MessageBox::Show( "It's too cold, stay in bed!" );
  break;
  case 70 :
    MessageBox::Show( "Let's play the lottery!" );
  break;
  default :
    MessageBox::Show( "Time to read the newspaper!");
}


COMPARISON OPERATORS

Many of the conditional logic tests featured in the chapter games and examples so far have involved comparing two values or expressions to see if they are equal. Although this is certainly a useful type of test, you often need to test the relationship between values and expressions in different ways. For example, you might want to know if one value is less than, greater than, or equal to another value. To accomplish these types of comparisons, you can use any of the comparison operators listed in Table 6.1.

Table 6.1: Visual C++ Comparison Operators
Operator | Description
== | Equal
!= | Not equal
< | Less than
> | Greater than
<= | Less than or equal to
>= | Greater than or equal to

To gain a better sense of how to use these operators, study the following example:

Int32 intSecretNumber = 6;
Int32 intPlayerGuess = 10;

if( intPlayerGuess < intSecretNumber )
     MessageBox::Show("Your guess is too low.");
if( intPlayerGuess == intSecretNumber )
     MessageBox::Show("Your guess is correct.");
if( intPlayerGuess > intSecretNumber )
     MessageBox::Show("Your guess is too high.");

In this example, three if statements have been established to test two values against one another. The first if statement uses the less than operator (<) to see if intPlayerGuess (which is 10) is less than intSecretNumber (which is 6). The second if statement checks to see if the player's guess is equal to intSecretNumber. Finally, the third if statement uses the greater than operator (>) to determine whether the number supplied by the user is greater than intSecretNumber. In this example, the message informing the player that his guess is too high activates because 10 is greater than 6.


BACK TO THE GUESS A NUMBER GAME

Let's get started on the development of this chapter's game project, the Guess a Number game. To create this game, you follow the same five development steps that you've used to create previous chapter projects.

Designing the Game

The Guess a Number game is played on a single window. This game collects the player's input by adding radio buttons and a check box to the user interface. In addition, instead of displaying output using MessageBox::Show, the game displays information messages for the player to read in a TextBox control located on the user interface.

The advantage of collecting player input and displaying game output on the user interface is that it makes the game run more smoothly. The player doesn't have to constantly stop and respond to pop-up windows as the game runs. To create the user interface, you have to learn how to work with several new types of controls, including the GroupBox, RadioButton, and CheckBox controls.

The Guess a Number game is made up of one form and the 17 controls listed in Table 6.2.

Table 6.2: Form Controls for the Guess a Number Game
Control Type | Control Name | Description
GroupBox1 | grpRange | Contains radio buttons, a check box, and a button, which control the game's configuration settings
GroupBox2 | grpScore | Displays the number of games won by the player and contains a button that resets the score
RadioButton 1 | rbnControl10 | Sets the range of game numbers to 1 through 10
RadioButton2 | rbnControl100 | Sets the range of game numbers to 1 through 100
RadioButton3 | rbnControl1000 | Sets the range of game numbers to 1 through 1000
CheckBox1 | chkVerbose | Determines the level of messaging displayed by the game
Label1 | lblGamesWon | Identifies the TextBox control where the total number of games won is displayed
Label2 | lblInstructions | Identifies the TextBox control where the player enters guesses
Label3 | lblFeedback | Identifies the TextBox control where game output is displayed
Button1 | btnDefaults | Resets default RadioButton and CheckBox control settings
Button2 | btnReset | Resets the number of games won back to 0 to start a new game session
Button3 | btnCheckGuess | Processes the player's guess to see if the player guessed low, high, or won the game
Button4 | btnNewGame | Starts a new game
TextBox1 | txtGamesWon | Displays the number of games that the player has won
TextBox2 | txtInput | Collects and displays player guesses
TextBox3 | txtOutput | Displays output messages generated during gameplay
StatusStrip1 | stsControl | Displays information messages during gameplay

Step 1: Creating a New Visual C++ Project

The first step in creating the Guess a Number game is to open Visual C++ and create a new project, as outlined here:

  1. If you have not already done so, start up Visual C++ 2005 Express, click on File, and select New Project. The New Project dialog box appears.

  2. Select Windows Application template.

  3. Type Guess a Number as the name of your new application in the Name field located at the bottom of the New Project window.

  4. Click on OK to close the New Project dialog box.

Visual C++ now creates a new project for you and displays a new form upon which you can design the game's user interface.

Step 2: Creating the User Interface

The first step in laying out the user interface is adding controls to the form and moving and resizing them to the appropriate locations. The following function outlines the overall steps involved in creating the game's user interface. As you go through each step, make sure that you reference Figure 6.9 so that you know where to place each control.

  1. Start by adding two GroupBox controls to the form. Position and resize them, as shown in Figure 6.8.

    Hint

    A GroupBox control is a container that organizes other controls. The GroupBox control displays a caption, set using its Text property, and displays a visible border.

  2. Add three RadioButton controls to the form and move them into the first GroupBox control.

    Hint

    A RadioButton control allows you to collect True/False or On/Off information. RadioButton controls are used together in groups to give users the ability to pick between mutually exclusive choices.

  3. Add a CheckBox control to the form and move it to the right of the last RadioButton control.

    Hint

    A CheckBox control lets you collect True/False or On/Off information. Unlike RadioButton controls, you can use CheckBox controls individually. When selected, the CheckBox control displays an x.

  4. Add a Button control to the first GroupBox control and resize it.

  5. Add a Label, a TextBox, and a Button control to the second GroupBox and resize and position them.

  6. Add two additional Label controls and position them toward the middle of the form.

  7. Add a TextBox control to the right of the first Label control and increase its width by approximately 30 percent.

  8. Add another TextBox control underneath the second Label control and resize it until it spans the length of the form.

  9. Add two more Button controls to the bottom area of the second GroupBox.

  10. Finally, add a StatusStrip control to the bottom of the form and select a StatusLabel from its drop-down list.

Image from book
Figure 6.8: Completing the interface design for the Guess a Number game.

The overall layout of your new application's form is now complete.

Step 3: Customizing Form and Control Properties

It is time for you to customize various properties belonging to the form and the controls that you have placed on it. Begin by changing the form properties listed in Table 6.3.

Table 6.3: Property Changes for Form1
Property | Value
Name | frmMain
Cursor | Hand
FormBorderStyle | Fixed3D
StartPosition | CenterScreen
Text | Guess a Number

Next, make the changes shown in Table 6.4 to the GroupBox controls.

Table 6.4: Property Changes for the GroupBox Controls
Control | Property | Value
GroupBox1 | Name | grpRange
 | Text | Select Range
GroupBox2 | Name | grpScore
 | Text | Score

Make the changes shown in Table 6.5 to the RadioButton controls.

Table 6.5: Property Changes for the RadioButton Controls
Control | Property | Value
RadioButton1 | Name | rbnControl10
 | Text | Range: 1 to 10
RadioButton2 | Name | rbnControl100
 | Checked | True
 | Text | Range: 1 to 100
RadioButton3 | Name | rbnControl1000
 | Text | Range: 1 to 1000

Make the changes shown in Table 6.6 to the Button controls.

Table 6.6: Property Changes for the Button Controls
Control | Property | Value
Button1 | Name | btnDefaults
 | Text | Reset Defaults
Button2 | Name | btnReset
 | Text | Reset Score
Button3 | Name | btnCheckGuess
 | Enabled | False
 | Text | Check Guess
Button4 | Name | btnNewGame
 | Text | NewGame

Make the changes shown in Table 6.7 to the CheckBox control.

Table 6.7: Property Changes for the CheckBox Control
Property | Value
Name | chkVerbose
Checked | True
CheckState | Checked
Text | Verbose Messaging

Make the changes shown in Table 6.8 to the Label controls.

Table 6.8: Property Changes for the Label Controls
Control | Property | Value
Label1 | Name | lblGamesWon
 | Font.Bold | True
 | Text | No. of Games Won:
Label2 | Name | lblInstructions
 | Font.Bold | True
 | Font.Size | 10
 | Text | Enter Your Guess:
Label3 | Name | lblFeedback
 | Font.Bold | True
 | Text | Feedback and Results

Make the changes shown in Table 6.9 to the TextBox controls.

Table 6.9: Property Changes for the TextBox Controls
Control | Property | Value
TextBox1 | Name | txtGamesWon
 | ReadOnly | True
 | TabStop | False
TextBox2 | Name | txtInput
 | Enabled | False
TextBox3 | Name | txtOutput
 | ReadOnly | True
 | TabStop | False

Make the changes shown in Table 6.10 to the StatusStrip control.

Table 6.10: Property Changes for the StatusStrip Control
Object | Property | Value
StatusStrip1 | Name | stsControl
 | SizingGrip | False
toolstripStatus1 | Name | stsLabel
 | Text | Game Ready!

That's it. At this point, you have configured all the form and control properties that need to be set at design time.

Step 4: Adding a Little Programming Logic

Begin by double-clicking on the form. This activates the Code Editor. Locate the block of code shown in the next program listing and add the statements shown in bold:

private:
    /// <summary>
    /// Required designer variable
    /// </summary>
    Int16 intRandomNumber;
    Int16 intTextGamesWon;

The intRandomNumber variable is used throughout the application to store the game's randomly generated secret number. The intTextGamesWon variable keeps track of the number of games won. Next, modify the form's Load event function, as shown next:

System::Void frmMain_Load(System::Object^ sender,
System::EventArgs^  e)
{
        //Clear game variables and text
        intRandomNumber = 0;
        intTextGamesWon = 0;
        txtGamesWon->Text = intTextGamesWon.ToString();
        //Set focus on new game button
        btnNewGame->Focus();
}

The first two statements set the value of intRandomNumber and intTextGamesWon to 0. This ensures that the game won't access some random value in memory when these values are first used. The next statement initializes the display of the txtGamesWon text box, setting it to the value of intTextGamesWon. The last statement places focus on the btnNewGame control.

Next, we need to add logic to the btnDefaults control to reset the game's default settings, as controlled by the RadioButton and CheckBox controls located in the first GroupBox control. Do so by modifying the click event function for the btnDefaults control, as shown next:

private: System::Void btnDefaults_Click(System::Object^
sender, System::EventArgs^  e)
{
        //Reset all game defaults
        rbnControl100->Checked = true;
        chkVerbose->Checked = true;
        //Set focus on text input
        txtInput->Focus();
}

The first statement selects the RadioButton that represents the range of 1 to 100. The second statement selects (by placing an x inside) the chkVerbose CheckBox control, and the third statement sets the focus to the txtInput control (to save the player the trouble of having to put it there before typing the next guess).

Next, let's add logic to the btnReset control so that the player can reset the value that tracks the number of games won to 0 at any time. Also, take note that the value is first assigned to the variable and then converted so that the txtGameWon->Text text property can display it:

private: System::Void btnReset_Click(System::Object^
sender, System::EventArgs^ e)
{
        //Reset the game score
        intTextGamesWon = 0;
        txtGamesWon->Text = intTextGamesWon.ToString();
}

Next, add the following statements to the TextChanged event for the txtInput control:

private: System::Void txtInput_TextChanged(System::Object^
sender, System::EventArgs^  e)
{
        //Toggle appropriate buttons when
        //  text is being entered for the
        //  guess
        btnCheckGuess->Enabled = true;
        btnNewGame->Enabled = false;
}

The TextChanged event is triggered automatically whenever the user keys something into the TextBox control that is associated with the event. It is used in the Guess a Number game to control when the btnCheckGuess button is enabled and when the btnNewGame button is disabled.

Now we need to add logic to the application that randomly generates the game's secret number. To do so, I have decided to create a new function named GenerateRandomNumber() and place the logic to generate the random number in it. You can't automatically generate this function by double-clicking on an object in the Form Designer. Instead, you need to key it in entirely by hand, as shown next. You'll learn more about how to work with functions in Chapter 8, "Enhancing Code Structure and Organization," including how to create your own custom functions. For now, just key in the function, as shown here:

private: Void GenerateRandomNumber( Void )
{

         //Get a random number based on the
         //  current time
         DateTime moment = DateTime::Now;
         Random^ randNumGen =
                  gcnew Random( moment.Millisecond );
         Int32 intUpperLimit = 0;
         //Check to see which radio button is
         //  checked to determine upper
         //  limit of random number
         if( rbnControl10->Checked == true )
           intUpperLimit = 10;
         if( rbnControl100->Checked == true )
           intUpperLimit = 100;
         if( rbnControl1000->Checked == true )
           intUpperLimit = 1000;
         //Get the number based on the upper range
         intRandomNumber = randNumGen->Next( intUpperLimit );
}

When called by the btnNewGame control's click event function, the GenerateRandomNumber function first gets the computer's current time. Then it instantiates a new Random object called randNumGen and checks to see which RadioButton control is currently selected so that it knows which range to use when generating the game's secret number. After that, the function executes the randNumGen object's Next() method so that it can generate the random number. The Next() method is passed the value stored in the intUpperLimit variable so that it can specify the maximum range from which the random number should be selected (between 0 and the value of intRandomNumber).

Trick

The Random object's Next() method generates a random number. If called without passing it parameters, the Next() method generates a positive whole number. If passed a single integer value, the Next() method generates a random number between zero and the value of the integer argument. If passed two integer values, the Next() method generates a random number within the specified range.

Now let's add the code required for the click event belonging to the btnCheckGuess control, as shown here:

private: System::Void btnCheckGuess_Click(System::Object^
sender. System::EventArgs^  e)
{

//Check the player's guesses

//Declare variable to store current guess
Double dblPlayerGuess = 0;
//Declare variable to continuously keep
//  track of player guesses
static Int32 intNoOfGuesses = 0;

//First, check to see if text has been entered
if( txtInput->Text->Length > 0 )
{
  //Try to convert the number and store it in
  //  the dblPlayerGuess variable; if the player
  //  accidentally enters text or a fraction,
  //  the Double::TryParse method fails gracefully
  if( Double::TryParse( txtInput->Text, dblPlayerGuess ) )
  {
    //Enable button
    btnCheckGuess->Enabled = true;
    //Check whether player guess equals number
    if( dblPlayerGuess == intRandomNumber )
    {

      txtInput->Text = "";
      intNoOfGuesses += 1;
      //Check whether verbose messaging is on
      if( chkVerbose->Checked == true )
      {
        //Create the message string
        txtOutput->Text =
        String::Concat( "Congratulations! "
        "You've won the Guess A Number Game! "
        "Number of guesses made = ",
        intNoOfGuesses.ToString() );
      }
      else
        txtOutput->Text =
        "Congratulations!";

            //Reset number of guesses
            intNoOfGuesses = 0;
            //Disable text input
            txtInput->Enabled = false;
            //Update number of games won
            intTextGamesWon += 1;
            txtGamesWon->Text =
              intTextGamesWon.ToString();
            //Enable the New Game button
            btnNewGame->Enabled = true;
            //Disable the check guess button
            btnCheckGuess->Enabled = false;
            //Enable all of the radio buttons
            rbnControl10->Enabled = true;
            rbnControl100->Enabled = true;
            rbnControl1000->Enabled = true;
            //Enable the two reset buttons
            btnDefaults->Enabled = true;
            btnReset->Enabled = true;
            stsLabel->Text = "Get Ready!"; }
          }
          //Is player guess less than number?
          if( dblPlayerGuess < intRandomNumber )
          {
            //Clear text
            txtInput->Text = "";
            //Increase guess count
            intNoOfGuesses += 1;
            //Check if verbose messaging is on
            if( chkVerbose->Checked == true )
            {
              //Create the message string
              txtOutput->Text =
              String::Concat( "The number that "
              "you entered was too low. "
              "Please enter a higher number "
              "and try again. "
              "Number of guesses made = ",

             intNoOfGuesses.ToString() );
           }
           else
             txtOutput->Text =
             "Too low.";
         }
         //Is player guess is greater than number
         if( dblPlayerGuess > intRandomNumber )
         {
           //Clear text
           txtInput->Text = "";
           //Increase guess count
           intNoOfGuesses += 1;
           //Check whether verbose messaging is on
           if( chkVerbose->Checked == true )
           {
             //Create the message string
             txtOutput->Text =
             String::Concat( "The number that "
             "you entered was too high. "
             "Please enter a lower number "
             "and try again. "
             "Number of guesses made = ",
             intNoOfGuesses.ToString() );
           }
           else
             txtOutput->Text =
             "Too high.";
         }
       }
       else
       {
        if( chkVerbose->Checked == true )
        {
          //Create the message string
          txtOutput->Text =
          String::Concat( "Sorry, you "
          "entered a non-numeric guess. "

          "Please enter a number and "
          "try again. " );
        }
        else
          txtOutput->Text =
          "Numeric input required.";
       }
     }
     else
     {
      if( chkVerbose->Checked == true )
      {
        //Create the message string
        txtOutput->Text =
        String::Concat( "Sorry, but ",
        "a number is required to. ",
        "play. Please enter a ",
        "number and try again." );
      }
      else
        txtOutput->Text =
        "No input provided.";
     }
     txtInput->Focus();
}

As you can see, this function is rather long and contains the bulk of the application's programming logic. It begins by declaring two variables. The first variable is dblPlayerGuess and is used to store and process the input provided by the player. A new value will be assigned to this variable each time the player clicks on the Button control labeled Check Guess. Therefore, it is declared as a local variable. However, the second variable, which is named intNoOfGuesses, is defined as a static variable, making its lifetime last for as long as the game runs. This allows it to maintain a count of the number of guesses that the player makes during each game.

Next, an if...else block is set up that determines which statements in the function execute based on whether the player entered input. If no input was provided, an error message is displayed in the txtOutput control. Otherwise, a second nested if...else block executes and checks whether the input that the player supplied is numeric. If the input is not numeric, an error message is displayed in the txtOutput control. If the input is numeric, one of three nested if blocks executes. The first if block checks whether the player won the game by guessing the secret number. The second if block checks whether the player's guess was too low, and the third if block checks whether the player's guess was too high.

If the player's guess was too high or too low, an error message is displayed in the txtOutput control. The message that is displayed depends on whether the chkVerbose control is checked. If the player guesses correctly, she wins the game, and a congratulatory message is displayed in the txtOutput control. In addition, the following actions are taken to prepare the game for another play:

  • The value of intNoOfGuesses is reset to 0.

  • The value indicating the number of games won is incremented, converted, and stored in the txtGamesWon control's text property.

  • The Check Guess button is disabled, and the New Game button is enabled.

  • The game's RadioButton controls are enabled, allowing the player to make changes to them if desired.

  • The game's Reset Default button is also enabled.

  • The message displayed in the game's StatusStrip control is updated.

Last but not least, it is time to add some code to the btnNewgame control's click event function, as shown here:

private: System::Void btnNewGame_Click(System::Object^
sender, System::EventArgs^  e) {
        //Set conditions for new game

        //Generate a new random number
        this->GenerateRandomNumber();
        txtOutput->Text
        txtInput->Text = "";
        //Set starting game buttons
        btnNewGame->Enabled = false;
        btnCheckGuess->Enabled = true;
        //Enable text input
        txtInput->Enabled = true;
        //Turn off radio buttons
        rbnControl10->Enabled = false;
        rbnControl100->Enabled = false;

        rbnControl1000->Enabled = false;
        //Disable the two reset buttons
        btnDefaults->Enabled = true;
        btnReset->Enabled = true;
        //Set status strip text
        stsLabel->Text = "Enter your guess.";
        txtInput->Focus();
}

When clicked, the code for the button causes the GenerateRandomNumber function to be called. Note that it uses the format this->GenerateRandomNumber(). The keyword this was used so that the form could refer to (and hence access) one of its own elements. Next, the function clears any text display in the txtInput and txtOutput controls. Following this, the btnNewGame control is disabled, and the btnCheckGuess control is enabled. Then the txtInput control is enabled to allow the player to enter a guess, and the game's RadioButton control and btnReset control are disabled, preventing the player from making configuration changes while a new game is being played. Finally, an instructional message is displayed on the game's StatusStrip control, and the cursor is placed in the txtInput control.

Step 5: Testing the Execution of the Guess a Number Game

That's it. The Guess a Number game is ready to run. Press F5 to see how it works. If you have errors, double-check your typing. Otherwise, pass it on to your friends and ask them to play and to report any problems back to you if they run into anything faulty.


SUMMARY

In this chapter, you gained knowledge on how to apply conditional logic to your Visual C++ applications using variations of the if and the switch statements. This included learning how to set up conditional tests to test for one or more possible outcomes and developing alternative execution flows if the conditional tests proved false. In addition, you learned how to work with the GroupBox, RadioButton, CheckBox, and ComboBox controls.

Before you jump into Chapter 7, "Processing Lots of Data with Loops," and learn how to apply advanced looping logic to your programs, take a few extra moments to review the following challenges and see if you can improve the Guess a Number game.


CHALLENGES

  1. Modify the Guess a Number game by providing better clues as the player's guesses begin to get closer to the secret number. For example, you might add text that tells the player when he is getting "warm," "warmer," and "hot."

  2. Add logic to the game to display the average number of guesses that it takes the player to guess the secret number, and display this information in the grpScore control (GroupBox).

  3. Modify the Guess a Number game so that the game ends if the player has not guessed the secret number after a certain number of tries, and display the number of games lost in the grpScore control (GroupBox). Also, display the secret number in the txtOutput control (TextBox) when the player loses a game.


Chapter 7: Processing Lots of Data with Loops

OVERVIEW

As you might have noted in previous chapter projects, sometimes creating loops within your applications allows you to repeatedly perform certain steps. Loops are an essential part of computer programming. They often allow you to compact what would otherwise be a large and messy number of duplicate programming statements into a few clean lines of code. Loops are a great option for processing the contents of arrays and controls, such as the ComboBox, which store collections of data. In this chapter, you learn how to use a number of Visual C++ statements to create different kinds of loops. In addition, you get the chance to apply what you learn through the development of the chapter's game project, the Dice Poker game.

In this chapter, you learn the following:

  • How to create do...while loops

  • How to create for and for each loops

  • How to create while loops

  • How to use variations of the break keyword to break out of loops

  • How to guard against endless loops


PROJECT PREVIEW: THE DICE POKER GAME

In this chapter's project, you apply your knowledge of loops to developing the Dice Poker game. In addition, you get experience working with and controlling graphics by learning how to use the ImageList and PictureBox controls.

Figures 7.1 through 7.6 show examples from the Dice Poker game, demonstrating its functionality and overall execution flow.

Image from book
Figure 7.1: The Dice Poker game begins by giving the player $20 in an account.
Image from book
Figure 7.2: Players can elect to hold onto specific dice before rolling the dice a second time.
Image from book
Figure 7.3: Two dollars are deducted from the player's account for each losing hand.
Image from book
Figure 7.4: Winning hands are rewarded with additional credits to the player's account.
Image from book
Figure 7.5: Winning hands include 3, 4, and 5 of a kind, full house, and high and low straights.
Image from book
Figure 7.6: The game automatically ends if the player's account runs out of money.

By the time you have completed this game, you'll have a good understanding of how to work with loops. You'll also have a greater sense of using graphics controls in your applications.


ITERATIVE PROCESSING

Loops let you repeat a certain section of code until a given condition is met. They save programmers time when creating code. Loops, for instance, can process hundreds or even thousands of elements of data using only a few programming statements. Loops are especially useful for processing the contents of arrays and collections, such as the collection associated with the ComboBox control. Loops can also drive any form of iterative logic, such as running a few lines of code that prompt a user for information. In such a case, you can use a loop to direct that the code continue to run until the appropriate information is provided.

Hint

A loop is a group of programming statements that are executed repeatedly.

Visual C++ gives you several options when it comes to establishing a loop:

  • for. Creates a loop that iterates a specific number of times

  • while. Creates a loop that iterates as long as a condition remains true

  • do...while. Creates a loop that is guaranteed to iterate at least once and will continue to do so as long as a condition remains true

Each type of loop is discussed in greater detail in the sections that follow.

while Loops

You can set up while loops to iterate until or while a specific condition is true. These types of loops are well suited when you know you want to loop repeatedly as long as some condition is true. For example, you might set up a do...while or while loop to allow a user to enter as much input as desired, terminating the loop's execution only when the user enters a trigger word such as Quit or Exit.

while

The while loop acts as a combination if statement and loop. It is designed to test a condition and then execute provided the condition proves to be true. It has the following syntax:

while( condition )
  statement;

Condition is expressed in the form of an expression, as demonstrated here:

Windows::Forms::DialogResult dlResult;
Int32 intCounter = 0;
const Int32 cintMaxValue = 5;
while( intCounter < cintMaxValue )
{
  dlResult = MessageBox::Show("Do you wish to increase the counter?",
              "Increase Counter", MessageBoxButtons::YesNo,
              MessageBoxIcon::Question,
              MessageBoxDefaultButton::Button1 );
  if( dlResult == Windows::Forms::DialogResult::Yes )
    intCounter++;
}

In this example, a loop is established that continues running the code within it while its expression evaluates to true. First, the variables dlResult, intCounter, and cintMaxValue are declared, and intCounter and cintMaxValue are initialized. Then program flow transfers to the loop. The loop tests the condition intCounter < cintMaxValue. If this expression proves to be true, the code within the loop executes. If it proves to be false, the entire body of the loop (enclosed in braces) is skipped.

Within the loop, a dialog box appears asking the user whether he wants to update intCounter. The dialog box has only two buttons, giving the user a Yes or No response. After the user responds to the dialog box, the result is stored in dlResult. Below this, the if statement tests the results of the user's response to the dialog box. If the result of the query is No, intCounter is not updated. If the user response to the dialog box is Yes, intCounter is updated by one. Program control continues past the if statement to the closing braces, where it jumps back to the while statement. The condition is then tested again.

The user must respond Yes five times to the dialog box query to get the loop to exit. Responding Yes causes intCounter to be incremented from 0 to 5, whereupon the logical test intCounter < cintMaxValue evaluates to false (because 5 < 5 is logically false). Program control then skips the entire body of the loop and continues executing whatever code lies beneath it.

In this example, the dialog box displays an indeterminate number of times as long as the user continues to click No. The example illustrates how flexible the whi1e loop is. This loop allows your application to execute code as long as is necessary until some condition is reached.

do…while

A do...white loop is a variant of the while loop, except that it is reversed. You can think of it as a while loop turned upside down. Like the while loop, it iterates as long as a specified condition remains true. However, since there is no test at the top of the loop, the code within the loop is guaranteed to execute at least once. The syntax is shown here:

do
{
  statements
  .
  .
  .
} while( condition );

As with if statements, condition represents an expression that is tested upon each iteration of the loop. The loop continues executing as long as the condition is true. Here is an example:

Int32 intCounter = 0;
do

{
  intCounter += 1;
} while( intCounter < 10 );

In this example, the variable named intCounter is declared and then used to control the iteration of the loop. When an application first encounters this code, the intCounter is incremented by one. The while statement then checks to see if intCounter is less than 10. If it is, program flow jumps back to the top of the loop, starting with the do keyword. The result in this example is that the value of IntCounter is increased by 1 at the end of each iteration, causing the loop to iterate 10 times.

A loop will continue executing so long as its controlling statement proves true. After the condition being tested by the while statement proves false, the loop ends automatically. In the previous example, this occurred when intCounter reached a value of 10. The while statement would have evaluated 10 < 10 logically as false.causing program flow to continue executing past the loop.

for Loops

The for loop is an excellent choice when you know in advance how many times you want a loop to execute. The for loop iterates a specific number of times as determined by a counter, which can increase or decrease based on the logic you are implementing.

The syntax for the for statement is shown here:

for( initial expression; condition; loop expression )
   statement;

The for statement executes a given statement until condition becomes false.statement can be a single line of code or a block enclosed in braces. The most typical use of a for statement involves setting a counter to a value, testing for a condition, and then altering the counter at the end of each iteration. Consider the following example:

private: System::Void Form1_Load(System::Object^   sender, \
System::EventArgs^  e)
{
  Int32 intArray[100];
  for( Int32 intCntr = 0; intCntr < 100; intCntr += 1 )
     intArray[intCntr] = intCntr;
}

In this example, an array intArray is first declared with 100 elements. A for loop is established to iterate through it. The variable controlling the loop, intCntr, is first initialized to 0.

Next, the condition of the loop, intCntr < 100, is tested. The loop then executes the statement beneath it, intArray[intCntr] = intCntr. Finally, the loop expression, intCntr += 1, activates. The result is that all 100 elements of the loop are filled with values ranging from 0 to 99. When intCnter is finally incremented to 100, the conditional expression fails and the loop ends, transferring program control to the statements following the loop.


ENDLESS LOOPS

One important aspect of looping to be aware of is an endless loop. Endless loops occur when you apply faulty logic in the creation of a loop that results in the loop running forever (or until you forcefully terminate your application).

Hint

An endless loop is a loop that has no means for terminating, causing the loop to run forever and draining computer resources.
Trick

If, white testing the execution of your Visual C++ application during development, you think you might have an endless Loop, you can stop the program from running by opening the Debug menu and clicking on the Stop Debugging menu item.

If you are running a compiled Visual C++ application from the Windows desktop and you think it might be caught in an endless loop, you can forcefully terminate its execution by pressing the Ctrl+Alt+Delete keys simultaneously. This opens the Task Manager window, from which you can select your application and click on the End Task button.

The following example demonstrates how easy it is to accidentally set up an endless loop:

Int32 intCounter = 0;
while( intCounter < 5 )
{
  intCounter = intCounter - 1;
  MessageBox::Show( intCounter->ToString() );
}

In this example, a while loop is established to iterate as long as the value of intCounter is less than 5. However, instead of incrementing the value of intCounter by 1 upon each iteration of the loop, the programmer here accidentally decremented the value of intCounter by 1. As a result, the value of intCount will continuously decline, never reaching 5. As a result, the loop will never terminate on its own. Always double-check the way that you have set up your loops, and test your applications thoroughly so that if you accidentally introduce a situation where an endless loop can occur, you'll catch it.


CONTROLLING EXECUTION WITHIN LOOPS

You might find it necessary to exit a loop early. Or you might find it useful to skip a particular sequence of statements within the loop. Visual C++ provides two easy-to-use commands for doing so that work with all types of loops.

Using break

You can use the break statement to break out of any loop. The syntax for this is shown in two example loops here:

while( condition )
{
  if( expression )
    break;
}

for( condition )
{
  if( expression )
    break;
}

As you can see, these examples are quite similar. In the first, a while loop begins based on some condition. An if then evaluates some other expression, which, if true, executes the break command. When encountered, this command causes the loop to terminate immediately and transfer control to the code following the loop. The same sequence applies to the for loop example. This loop continues as long as the condition within its parentheses is true. When the break expression is encountered, control transfers to the closing brace and then to any statements, which follow:

private: System::Void Form1_Load(System::Object^   sender,\
System::EventArgs^  e)
{
  Windows::Forms::DialogResult dlResult;
  Int32 intCounter = 0;
  const Int32 cintMaxValue = 1000;
  while( intCounter < cintMaxValue )
  {

    intCounter++;
    dlResult = MessageBox::Show("Do you wish to stop incrementing"
              "the counter?", "Increase Counter",
              MessageBoxButtons::YesNo,
              MessageBoxIcon::Question,
              MessageBoxDefaultButton::Button1 );
    if( dlResult == Windows::Forms::DialogResult::Yes )
      break;
  }
}

In this example, when the application's form first loads, a counter is incremented from 0 to 1000. The variables are declared, and the loop checks whether intCounter is less than cintMaxValue. The user is then presented with a dialog box asking if he wants to stop increasing the counter. If the response is no, the loop continues. However, if the expression dlResult == Windows::Forms::DialogResult::Yes evaluates to true, the break command is called. This causes the loop to terminate immediately and the rest of the application to run.

Using continue

An alternative to the break statement, the continue statement allows you to stay within a loop but skip any statements below it. Paired with logical tests, you can use this to control precisely how a loop iterates. As with break, you can use continue in any type of loop. Here is the syntax using two different types of loops as examples:

do
{
  if( expression )
    continue;
} while( condition );

for( condition )
{
  if( expression )
    continue;
}

The following example demonstrates how to use the continue statement to skip sections of a loop:

private: System::Void Form1_Load(System::0bject^   sender, \
System::EventArgs^  e)
{
  Windows::Forms::DialogResult dlResult;
  Int32 intCounter = 0;
  const Int32 cintMaxValue = 1000;
  while( intCounter < cintMaxValue )
  {
    intCounter++;
    if( intCounter < 100 )
      continue;
    dlResult = MessageBox::Show("Do you wish to stop incrementing"
              "the counter?", "Increase Counter",
              MessageBoxButtons::YesNo,
              MessageBoxIcon::Question,
              MessageBoxDefaultButton::Button 1 );
    if( dlResult == Windows::Forms::DialogResult::Yes )
      break;
  }
}

As in previous examples, this example iterates as long as intCounter is less than 1000. The difference here is the if statement test, which contains a test to determine whether the value of intCounter is less than 100. If this evaluates to true, the continue statement is executed. This effectively causes all statements within the loop to be skipped. Control of the program then returns to the top of the loop. The result is that for the first 100 iterations, none of the code is called that presents a dialog box and exits the loop if the user chooses.


BACK TO THE DICE POKER GAME

It is time to turn your attention back to the development of this chapter's game project, the Dice Poker game. You will create this game by following the five basic development steps that you've used to create all the previous chapter projects.

Designing the Game

The Dice Poker game is played on a single window and is made up of one form and the 20 controls listed in Table 7.1.

Table 7.1: Form Controls for the Dice Poker Game
Control Type | Control Name | Description
Label | lblWelcome | Displays the game's welcome message
PictureBox | pbxDie1 | Displays the image for the first die
PictureBox | pbxDie2 | Displays the image for the second die
PictureBox | pbxDie3 | Displays the image for the third die
PictureBox | pbxDie4 | Displays the image for the fourth die
PictureBox | pbxDie5 | Displays the image for the fifth die
CheckBox | chkDie1 | Determines whether the first die should be held at the end of the first roll
CheckBox | chkDie2 | Determines whether the second die should be held at the end of the first roll
CheckBox | chkDie3 | Determines whether the third die should be held at the end of the first roll
CheckBox | chkDie4 | Determines whether the fourth die should be held at the end of the first roll
CheckBox | chkDie5 | Determines whether the fifth die should be held at the end of the first roll
CheckBox | chkKeepAll | Determines whether the CheckBox controls representing all five dice should be checked
Button | btnRollDice | Controls the logic that rolls the dice for the game
Button | btnbreak | Controls the termination of the game
GroupBox | grpScoring | Provides a container for storing the Label control that displays the game's scoring rules
GroupBox | grpOutput | Provides a container for storing the TextBox control that displays the output messages
Label | lbllegend | Displays the game's scoring rules
TextBox | txtoutput | Displays status messages during the game's execution
Imagelist | imlDiceList | Stores a list of bitmap images representing each of the six sides of a die
Timer | tmrRoll | Controls the logic that spins each of the game's five dice

Step 1: Creating a New Visual C++ Project

The first step in creating the Dice Poker game is to open Visual C++ and create a new project, as outlined here:

  1. If you have not already done so, start Visual C++ 2005 Express and then click on File and select New Project. The New Project dialog box appears.

  2. Select the Windows Application template.

  3. Type Dice Poker as the name of your new application in the Name field at the bottom of the New Project window.

  4. Click on OK to close the New Project dialog box.

Visual C++ creates a new project for you and displays a new form upon which you can design the game's user interface.

Step 2: Creating the User Interface

The first step in laying out the user interface is to add controls to the form and move and resize them to the appropriate locations. As you go through each step, make sure that you reference Figure 7.7 so that you know where to place each control and what size to make it.

Image from book
Figure 7.7: Completing the interface design for the Dice Poker game.

  1. Begin by resizing form1 until its size is 660, 480.

  2. Next, add a Label control near the top of the form. You'll use this control to display the game's welcome message.

  3. Add five PictureBox controls to the form. Space them evenly just under the Label control.

    Hint

    A PictureBox control allows you to display a graphical image on a Visual C++ form. A PictureBox control can display graphics files stored in any of the following formats: .gif, jpg, .jpeg, .bmp, .wmf, and .png.

  4. Add six Checkbox controls to the form. Place each of the first five controls under one of the five PictureBox controls. Place the sixth CheckBox control in the middle of the form about .5 inches below the third Checkbox control.

  5. Add two Button controls, one on each side of the sixth CheckBox control.

  6. Next, add two GroupBox controls under the two Button controls. Enlarge and resize each GroupBox control until it takes up most of the space at the bottom of the form.

  7. The first GroupBox control displays a text string showing the player how winning hands are scored. Therefore, you need to add three Label controls inside the first GroupBox control.

  8. The second GroupBox control displays informational messages that identify winning and losing hands and tell the player how many dollars are in the account. To display this text, you need to add a TextBox control inside the second GroupBox control and resize it until it almost fills the GroupBox control. To resize the control vertically, you must set the Multiline property to true.

  9. To control the rolls of each die, you need to add a Timer control to your application. After you've added this control, it is displayed in the Component Tray.

  10. Finally, you need to add an ImageList control to your application. After you've added it, it is displayed in the Component Tray.

    Hint

    An ImageList control stores images, which other controls, such as the PictureBox control, can then display.

At this point, the overall layout of the Dice Poker game's user interface is now complete, and you can begin modifying form and control properties.

Step 3: Customizing Form and Control Properties

Let's begin by making the required changes to properties belonging to the Form object, as listed in Table 7.2.

Table 7.2: Property Changes for Form1
Property | Value
Name | frmMain
Cursor | Hand
FormBorderStyle | Fixed3D
MaximizeBox | false
StartPosition | CenterScreen
Size | 660, 480
Text | Dice Poker

Make the property changes shown in Table 7.3 to the Label controls.

Table 7.3: Property Changes for Label Controls
Control | Property | Value
Label1 | Name | lblWelcome
 | ForeColor | Desktop
 | Text | Welcome to Visual C++ Dice Poker
 | Font.Bold | true
 | Font.Size | 12
Label2 | Name | lblLegend1
 | Text | 5 of a kind = $4 Full House = $2
Label3 | Name | lblLegend2
 | Text | 4 of a kind = $3 High Straight = $3
Label4 | Name | lblLegend3
 | Text | 3 of a kind = $1 Low Straight = $3

Make the property changes shown in Table 7.4 to the PictureBox controls.

Table 7.4: Property Changes for PictureBox Controls
Control | Property | Value
PictureBox1 | Name | pbxDiel
 | BorderStyle | Fixed3D
 | Size | 75,75
 | Size Mode | StretchImage
PictureBox2 | Name | pbxDie2
 | BorderStyle | Fixed3D
 | Size | 75,75
 | Size Mode | StretchImage
PictureBox3 | Name | pbxDie3
 | BorderStyle | Fixed3D
 | Size | 75,75
 | Size Mode | StretchImage
PictureBox4 | Name | pbxDie4
 | BorderStyle | Fixed3D
 | Size | 75,75
 | Size Mode | StretchImage
PictureBox5 | Name | pbxDie5
 | BorderStyle | Fixed3D
 | Size | 75, 75
 | Size Mode | StretchImage

Make the property changes shown in Table 7.5 to the CheckBox controls.

Table 7.5: Property Changes for CheckBox Controls
Control | Property | Value
CheckBox1 | Name | chkDiel
 | Text | Keep
 | Visible | False
CheckBox2 | Name | chkDie2
 | Text | Keep
 | Visible | False
CheckBox3 | Name | chkDie3
 | Text | Keep
 | Visible | False
CheckBox4 | Name | chkDie4
 | Text | Keep
 | Visible | False
CheckBox5 | Name | chkDie5
 | Text | Keep
 | Visible | False
CheckBox6 | Name | chkKeepAll
 | Text | Keep All
 | Visible | False

Make the property changes shown in Table 7.6 to the Button controls.

Table 7.6: Property Changes for Button Controls
Control | Property | Value
Button1 | Name | btnRollDice
 | Font.Bold | true
 | Text | Roll Dice
Button 2 | Name | btnbreak
 | Text | Quit
 | Font.Bold | true

Make the property changes shown in Table 7.7 to the GroupBox controls.

Table 7.7: Property Changes for GroupBox Controls
Control | Property | Value
GroupBox1 | Name | grpScoring
 | Text | Scoring:
GroupBox2 | Name | grpOutput
 | Text | Game Status:

Make the property changes shown in Table 7.8 to the TextBox control.

Table 7.8: Property Changes for TextBox Control
Property | Value
Name | txtOutput
Multiline | true
ReadOnly | true

Change the Name property for the Timer control to tmrRoll, and change the Name property of the ImageList control toimlDliceList. At this point, all that remains is to load the images representing each side of a die into the ImageList control's Images property (Collection), as outlined in Table 7.9. You can find copies of each of the bitmap image files along with the source code for this chapter's game project at this book's companion Web site, located at http://www.courseptr.com. The dice images were created using Adobe Photoshop and saved as 24-bit color images.

Table 7.9: Bitmap Images to Add to the ImageList Control's Images Collection
Property | File | Index No.
Name | 1.bmp | 0
Name | 2.bmp | 1
Name | 3.bmp | 2
Name | 4.bmp | 3
Name | 5.bmp | 4
Name | 6.bmp | 5
Trick

Afteryou have Loaded the application's bitmap images into the ImageList control, you can programmatically reference those images, as demonstrated next.

PbxDiel.Image = imlDiceList.Images(3)

In this example, the fourth bitmap image stored in the ImageList control named imlDiceList is loaded into a PictureBox control named pbxDie1 using the PictureBox control's Image property.
Trick

You don't have to worry about packaging and distributing the six bitmap images of the game's dice. When you add the .bmp files to the Images property of the ImageList control, Visual C++ automatically saves copies of the bitmap files inside your application's binary file.

Step 4: Adding a Little Programming Logic

The first task to perform in putting together the program code for the Dice Poker game is to define class (or module)-level constants and variables, as shown in bold in the following code:

private:
    /// <summary>
    /// Required designer variable
    /// </summary>
    //Game timer counter
    Int32 intTimerCntr;

    //Handle for random number generator
    Random^ randNumGen;

    //Used to control display of checkbox controls
    Boolean blnExcludeList;

    //Number of dollars in player's account
    Int32 intTotalDollars;
    Int32 intNoOfRolls; //Tracks the number of die rolls
    Int32 intDice1; //Number 1 die
    Int32 intDice2; //Number 2 die
    Int32 intDice3; //Number 3 die
    Int32 intDice4; //Number 4 die
    Int32 intDice5; //Number 5 die

Next, access the Load event procedure for the form and add the statements shown here:

private: System::Void frmMain_Load(System::Object^  sender, \
System::EventArgs^  e)
{
         //Seed random number generator with current time
         DateTime moment = DateTime::Now;
         randNumGen = gcnew Random( moment.Millisecond );

         // Set starting game variables
         pbxDie1->Image = imlDiceList->Images[0];
         pbxDie2->Image = imlDiceList->Images[0];
         pbxDie3->Image = imlDiceList->Images[0];
         pbxDie4->Image = imlDiceList->Images[0];
         pbxDie5->Image = imlDiceList->Images[0];
         blnExcludeList = false;
         intTimerCntr = 0;

         //Set starting money
         intTotalDollars = 20;

         //Set beginning text
         txtOutput->Text = \
         String: :Concat(   "Welcome! Are you ready "
         "to play Dice Poker?\r\r\nYou have ",
         intTotalDollars.ToString(),
         " dollars in your account." );
}

The first two statements prime the game to generate random numbers, first getting the time, and then using that value to drive the Random method. The next five statements load an image of the die into the five PictureBox controls. Next, the variable controlling whether dice are excluded from being rerolled is set, followed by a clearing of the variable that track the timer. The player's starting money is also initialized. Finally, a welcome message is displayed in the txtOutput TextBox control. This message is created by joining strings using the String::Concat method, which allows numbers to be inserted into a text string.

Next, modify the click event procedure for the form's first Button control, as shown here:

private: System::Void btnRollDice_Click(System::Object^ \
sender, System::EventArgs^  e)
{
       //See if the die have been rolled twice
       if( intNoOfRolls == 2 )
       {
         //Change button display text
         btnRollDice->Text = "Roll Dice";
         //Reset to 0 to get game ready for new hand
         IntNoOfRolls = 0;
       }

       //If the first roll has been made, toggle the display of the
       //CheckBox control and keep track of the number of rolls
       if( btnRollDice->Text == "Roll Dice" )
       {
         blnExcludeList = false;
         intNoOfRolls += 1;
       }

       else
       {
         blnExcludeList = true;
         intNoOfRolls += 1;
       }
       //Start the Timer control
       tmrRoll->Enabled = true;
}

These statements use a variable named intNoOfRolls to keep track of whether the player is about to make the first or second roll. If the value of intNoOfRolls is equal to 2, the text string Roll Dice is displayed on the first Button control, and the value of intNoOfRolls is reset to 0. The following if...else statement checks to see whether a Boolean type variable named blnExcludeList should be set to true or false based on the text displayed on the first Button control and increments the value of intNoOfRolls by 1. The btnExcludeList variable is used later in the application to determine whether to display the CheckBox controls that allow the player to hold on to dice before making the second roll. The last statement begins the dice rolling process by enabling the Timer control (tmrRoll).

Next, create the following subroutine procedure, as shown next. Visual C++ doesn't create this procedure for you. You have to create it from scratch:

private: Void RollTheDice( Int32 intDiceNo )
{
      //Stores randomly generated number representing the role of a die
      Int32 intRoll;

      //These variables are used to track which die the player chooses
      //to hold onto over his first roll
      Boolean blnSkipCase1 = false,
               blnSkipCase2 = false,
               blnSkipCase3 = false,
               blnSkipCase4 = false,
               blnSkipCase5 = false;

      //Flag die the player wants to hold
      if( blnExcludeList = true )
      {
        if( chkDie1->Checked == true )
           blnSkipCase1 = true;

        if( chkDie2->Checked == true )
          blnSkipCase2 = true;
        if( chkDie3->Checked == true )
          blnSkipCase3 = true;
        if( chkDie4->Checked == true )
          blnSkipCase4 = true;
        if( chkDie5->Checked == true )
          blnSkipCase5 = true;
      }

      //Simulate a six-sided die
      intRoll = randNumGen->Next( 6 ) + 1;

      //For each die number, display the correct graphic
      switch( intDiceNo  )
      {
      case 1 : //Update image for the first die as it spins
        //Player elected not to hold
        if( blnSkipCase1 == false )
        {
          pbxDie1->Image = imlDiceList->Images[intRoll   -  1];
          intDice1 = intRoll;
        }
        break;

      case 2 : //Update image for the second die as it spins
        //Player elected not to hold
        if( blnSkipCase2 == false )
        {
          pbxDie2->Image = imlDiceList->Images[intRoll - 1];
          intDice2 = intRoll;
        }
        break;

      case 3 : //Update image for the third die as it spins
        //Player elected not to hold
        if( blnSkipCase3 == false )
        {

          pbxDie3->Image = imlDiceList->Images[intRoll - 1];
          intDice3 = intRoll;
        }
        break;

      case 4 : //Update image for the fourth die as it spins
        //Player elected not to hold
        if( blnSkipCase4 == false )
        {
          pbxDie4->Image = imlDiceList->Images[intRoll - 1];
          intDice4 = intRoll;
        }
        break;

      case 5 : //Update image for the fifth die as it spins
        //Player elected not to hold
        if( blnSkipCase5 == false )
        {
          pbxDie5->Image = imlDiceList->Images[intRoll - 1];
          intDice5 = intRoll;
        }
        break;
    }
}

Note that when this function is called, it is passed a variable identifying which die (1 through 6) is being rolled. It stores this in a variable of its own named intDiceNo. The function begins by defining local variables needed for the function's execution.

An if statement that contains five embedded if statements is then executed. All of these statements execute only if the value assigned to blnExcludeList is equal to true, indicating that the player has already taken the first roll. Each of the nested if statements checks to see if the player has elected to hold on to any of the dice from the first roll (by selecting the CheckBox control for the associated die).

Next, the randNumGen object's Next method is executed. This causes a new random number with a value between 1 and 6 to be created. This number is then assigned to a variable named intRoll. A switch statement associates the randomly generated number to the die passed to the function (represented by the variable named intDiceNo). For example, if the randomly generated number is 2, the program statements associated with case 2 : are executed.

Or if the number is 3, the statements associated with case 3 : are executed. After each case statement, an if statement determines whether the die in question should be held. If it should, the appropriate image is assigned to the correct PictureBox control using intRoll. Note that because intRoll reflects the die value, which is 1 through 6, and the image list runs from 0 through 5, 1 must be subtracted from the array index.

Next, access the Tick event procedure for the Timer1 control and modify it as shown here:

private: System::Void tmrRoll_Tick(System::Object^  sender, \
System::EventArgs^  e)
{
       //Set amount of time to show dice rolling
       const Int32 cintRollPeriod = 5;

       //Roll each die
       for( Int32 intDiceCntr = 1; intDiceCntr <= 5;
            intDiceCntr++ )
       RollTheDice( intDiceCntr  );

       intTimerCntr += 1;  //Increment counter by one

       //Disable timer and display CheckBox controls at the
       //  end of each roll
       if( intTimerCntr > cintRollPeriod )
       {
         intTimerCntr = 0;  //Reset timer counter
         //Disable timer control
         tmrRoll->Enabled = false;
         if( intNoOfRolls == 1 )
         {
           //Prepare game for second roll
           btnRollDice->Text = "Roll Again";
           //Enable CheckBox controls
           chkDie1->Visible = true;
           chkDie2->Visible = true;
           chkDie3->Visible = true;
           chkDie4->Visible = true;
           chkDie5->Visible = true;
           chkKeepAll->Visible = true;

         }
         if( intNoOfRolls == 2 )
         {
           //Prepare game for a new hand
           btnRollDice-XText = "Roll Dice";
           chkDie1->Checked = false;
           //Disable CheckBox controls
           chkDie2->Checked = false;
           chkOie3->Checked = false;
           chkDie4->Checked = false;
           chkDle5->Checked = false;
           chkKeepAll->Checked = false;
           chkDie1->Visible = false;
           //Hide CheckBox controls
           chkDie2->Visible = false;
           chkDie3->Visible = false;
           chkDie4->Visible = false;
           chkDie5->Visible = false;
           chkKeepAll->Visible = false;

           //Keeps track of score
           Total TheScore();

           //Display the player's account status
           UpdateAccountStatus();

           //See if player has gone broke
           if( intTotalDollars <= 0 )
             //End the game
             EndOfGame();
         }
     }
}

This function begins by declaring a variable that will control the amount of time that the dice roll when the timer is activated. Because this is a fixed value that will not change, the variable is declared constant. Next, a loop iterates once for each die, calling the RollTheDice function and passing it intDiceCntr. Then the variable intTimerCntr is incremented by 1. This ultimately governs how long the Timer control is enabled.

An if block is executed to determine whether it's time to disable the Timer control. In addition, two embedded if blocks execute, based on whether the player has made his first roll. This enables or disables the display of the CheckBox controls.

Next, the function calls on the TotalTheScore and UpdateAccountStatus functions before checking the number of dollars in the player's account. If intTotalDollars is less than or equal to 0, the function EndOfGame is called.

The next function that you'll work on is the TotalTheScore function. This is another function that you must create from scratch, as shown here:

private: Void TotalTheScore( Void )
{
       //Declare array to be used to keep count of number
       //  in each hand
       const Int32 intMaxNoDie = 7;
       Int32 intDieArray[intMaxNoDie];

       //Declare variable used to control loop execution
       Int32 intCounter = 1;

       //Clear the dice array
       for( intCounter = 0: intCounter < intMaxNoDie;
            intCounter++ )
       intDieArray[intCounter] = 0;

       //Iterate six times and keep count of the total number of
       //1s, 2s, 3s, 4s, 5s, and 6s that has been rolled
       for(  intCounter = 1; intCounter <- 6; intCounter++ )
       {
         if( intDicel == intCounter )
           intDieArray[intCounter] += 1;
         if( intDice2 == intCounter )
           intDieArray[intCounter] += 1;
         if( intDice3 == intCounter )
           intDieArray[intCounter] += 1;
         if( intDice4 == intCounter )
           intDieArray[intCounter] += 1;
         if( intDice5 == intCounter )
           intDieArray[intCounter] += 1;
       }

       //Iterate six times looking for winning hands
       for( intCounter = 1; intCounter <= 6; intCounter++ )
       {
         //See if the player has 5 of a kind
         if( intDieArray[intCounter] =- 5 )
         {
           //Update player's account
           intTotalDollars += 4;
           txtOutput->Text = "\r\r\nWinner: 5 of a kind!"
           " You win 4 dollars!";
           return;
         }

         //See if the player has 4 of a kind
         if( intDieArray[intCounter] == 4 )
         {
           //Update player's account
           IntTotalDollars += 3;
           txtOutput->Text = "\r\r\nWinner: 4 of a kind!"
           " You win 3 dollars.";
           return;
         }

         //See if the player has 3 of a kind or a full house
         if( intDieArray[intCounter] == 3 )
         {
           //Player has 3 of a kind
           for( Int32 intCounter2 = 1; intCounter2 <= 6;
                intCounter2++ )
           {
             //See if player has a full house
             if( intDleArray[intCounter2] — 2 )
             {
               //Update player's account
               intTotalDollars += 2;
               txtOutput->Text = "\r\r\nWinner:"
               " Full house! You win 2 dollars.";
               return;
             }

            }
            intTotalDollars += 1;  //Update player's account
            txtOutput->Text = "\r\r\nWinner: 3 of a "
            "kind! You win 1 dollar.";
            return;
          }
        }

        //Iterate through die 2 - 6 looking for a high straight
        for( intCounter = 2; intCounter <= 6; intCounter++ )
        {
          if( intDieArray[intCounter] != 1 )
            break; //No need to keep looking any further
          else
          {
            if( intCounter == 6 )
            {
              //Update player's account
              intTotalDollars += 3;
              txtOutput->Text = "\r\r\nWinner: "
              "High Straight! You win 3 dollars.";
              return;
            }
          }
        }

        //Iterate through die 1 - 5 looking for a low straight
        for( intCounter = 1; intCounter <= 5; intCounter++ )
        {
          if( intDieArray[intCounter] != 1 )
            break; //No need to keep looking any further
          else
          {
            if( intCounter == 5 )
            {
              //Update player's account
              intTotalDollars += 3;
              txtOutput->Text = "\r\r\nWinner: Low"
              " Straight! You win 3 dollars.";

              return;
            }
          }
        }

        //Update player's account
        intTotalDollars -= 2;
        txtOutput->Text = "\r\r\nSorry, You lost this "
        "hand! You lose 2 dollars.";
}

This function begins by defining an array that will store the total number of 1s, 2s, 3s, 4s, 5s, and 6s in the player's hand. Then a local variable named intCounter is set up for use as a counter in the for statement that follows. All elements in the array are then set to 0 using a for loop to ensure that they are not filled with some random value. The for loop is then again used to tally up how many of each die the player has.

Next, another for loop executes a series of embedded if statements. The first if code block checks to see if the player's hand is 5 of a kind by examining the value stored in each element of the intDieArray. The second if code block looks for 4 of a kind, and the third if block first looks for 3 of a kind. If the player does have 3 of a kind, a second for loop is executed to see if the player has a full house.

Trick

If you look closely at the code in the TotalTheScore function, you see that even though the intDieArray has six elements, the function does not store data in the first element of the array. I did this to simplify things by pairing up the index position I in the array with the die value of 1, the index position of 2 in the array with the die value of 2, and so on. Then, when I set up the function's for loops, I made sure that I specified the correct starting and ending index numbers so that the loops never processed the array's first index value (for example, intDieArray[0]).

If the player does not have 3, 4, or 5 of a kind, the function checks to see if the player has a high straight (for example, 2-6) using another for loop to iterate through each of the values stored in the intDieArray. If the player does not have a high straight, another for loop is set up to look for a low straight. If the player doesn't have a winning hand, $2 is subtracted from his account.

The next function that you'll work on is EndOfGame. Again, you'll need to create this function from scratch, as shown here:

private: Void EndOfGame( Void )
{
      //Variable used to hold player response
      Windows::Forms::DialogResult drPlayAgain;

      //Clear out any status messages
      txtOutput->Text = "";

      //Prompt player to try again
      drPlayAgain = MessageBox::Show( "Sorry, you are "
      "broke. The game is over. Would you like to "
      "play again?", "Dice Poker",
      MessageBoxButtons::YesNo, MessageBoxIcon::Question,
      MessageBoxDefaultButton::Button1  );

        //if( player clicks on Yes set up a new game
      if( drPlayAgain == Windows::Forms::DialogResult::Yes  )
      {
        //Reset the bank account
        intTotalDollars = 20;
        pbxDie1->Image = imlDiceList->Images[0];
        pbxDie2->Image = imlDiceList->Images[1];
        pbxDie3->Image = imlDiceList->Images[2];
        pbxDie4->Image = imlDiceList->Images[3];
        pbxDie5->Image = imlDiceList->Images[4];
        //Set beginning text
        txtOutput->Text = \
        String::Concat( "Welcome! Are you ready "
        "to play Dice Poker?\r\r\nYou have ",
        intTotalDollars.ToString(),
        " dollars in your account." );
      }
      else //player wants to quit
        this->Close();
}

This function begins by declaring a variable, drPlayAgain, to hold the player's response when he's asked to playa new game. The player is prompted to play again using the MessageBox::Show method. If the player clicks Yes, his bank account is reset to $20, and die images are loaded into each of the PictureBox controls. If the player clicks No, the application is closed.

The next function that you'll work on is the UpdateAccountStatus function, which you have to create from scratch, as shown here:

private: Void UpdateAccountStatus( Void  )
{
       txtOutput->Text = \
       String::Concat( txtOutput->Text,
       "\r\r\nYou have ",
       intTotalDollars.ToString(),
       " dollars in your account." );
}

This function is called from the Timer1_Tick function to append a string of text, showing the player's account balance, to the text displayed in the txtOutput TextBox control. It does this using the String::Concat method, which allows numbers to be inserted into strings.

Next, access the click event function for the game's Exit button, and modify it as shown here:

private: System::Void btnExit_Click(System::Object^ sender,\
System::EventArgs^  e)
{
       this->Close();
}

Finally, access the CheckedChange event function for the chkKeepAll CheckBox control, and modify it as shown here:

private: System::Void chkKeepAll_CheckedChanged(System::Object^\
sender, System::EventArgs^  e)
{
       //if( the player selects the CheckBox
       // labeled KeepAll, select the other
       // CheckBox controls
       if( chkKeepAll->Checked = true )
       {
         btnRollDice->Text = "Stick";
         chkDie1->Checked = true;
         chkDie2->Checked = true;
         chkDie3->Checked = true;
         chkDie4->Checked = true;

         chkDie5->Checked = true;
       }
       else
       {
         //if( the player clears the CheckBox
         //  labeled KeepAll. clear the other
         //  CheckBox controls
         btnRollDice->Text = "Roll Again";
         chkDie1->Checked = false;
         chkDie2->Checked = false;
         chkDie3->Checked = false;
         chkDie4->Checked = false;
         chkDie5->Checked = false;
       }
}

This function enables the player to hold onto all of the dice from the first roll, which makes sense when the player gets a high or low straight or 5 of a kind on the first roll. The function also changes the text display on the first Button control to either Stick or Roll Again, based on whether the player selected the chkKeepAll button.

Step 5: Testing the Execution of the Dice Poker Game

The Dice Poker game is now ready to run. Press F5 to make sure that everything works as it is supposed to. If you run into any problems, go back and double-check your typing. Once the game is working, try it out a bit and see how much virtual money you can make.


SUMMARY

In this chapter, you learned how to work with variations of the do and for loops. You also learned how to set up a whi1e loop. You learned how to use loops to collect and process user input and to process the contents of arrays and controls, such as the ComboBox control. In addition, you learned about endless loops and how to use the break keyword to break out of loops and the continue keyword to skip statements within a loop. As a final effort, you created the Dice Poker game.

Before you move on to Chapter 8, "Enhancing Code Structure and Organization," and start learning how to work with functions, take a few extra minutes to improve the Dice Poker game by completing the following challenges.


CHALLENGES

  1. Add a menu system to the Dice Poker game, including the following menu items under the File menu: Roll Dice, Roll Again, Stick, and Quit. Also add a Help menu, and give the player access to pop-up windows that display the rules of the game and information about the game and its developer.

  2. Modify the Dice Poker game so that it tracks and displays information about the number of games that have been played, won, and lost.

  3. Enhance the Dice Poker game so that it looks for 2 of a kind but doesn't add or subtract money from the player's account for this tying hand.

  4. Enhance the Dice Poker game so that it looks to see if the player's hand has two pairs and awards the player $1 for this winning hand.


Chapter 8: Enhancing Code Structure and Organization

OVERVIEW

Throughout this book you have, knowingly or not, been using functions in every application that you have developed. The basic Windows form code automatically generates functions every time you build a WinForms application. Your applications have relied on functions to organize and store program code. In this chapter, you learn about how functions work and how to create your own. You learn how to use functions to reduce the complexity of the programs you write and enhance their readability. In the process, this chapter covers how functions work with data and the different ways you can use them to send data to them and get results. In addition, you get an opportunity to use this information in the course of creating this chapter's game project, the Hangman game.

In this chapter, you learn the following:

  • How to organize the programming logic that makes up your applications into functions so that they're easier to develop and maintain

  • How to create custom functions

  • How to pass and return data to and from functions

  • How to streamline your applications by placing reusable code within functions

  • How to develop functions that can process optional data


PROJECT PREVIEW: THE HANGMAN GAME

In this chapter's project, you will use the knowledge you gain of functions to develop the Hangman game. Figures 8.1 to 8.7 show examples from the Hangman game, demonstrating its functionality and overall execution flow.

Image from book
Figure 8.1: When the game is started, it displays a graphic showing an empty hangman's gallows and a series of underscore characters representing the secret word.
Image from book
Figure 8.2: As the game progresses, each correct guess is displayed at the top of the window, and a visual record of every letter guessed is displayed at the bottom of the window.
Image from book
Figure 8.3: The game prevents the player from making the same letter guess more than once.
Image from book
Figure 8.4: The game permits the player to enter only one letter at a time.
Image from book
Figure 8.5: The game prevents the player from entering numeric input.
Image from book
Figure 8.6: The game congratulates the player when he correctly guesses the secret word.
Image from book
Figure 8.7: If the player fails to guess the secret word within six guesses, he loses the game, and the picture of the hangman's gallows is updated to show a full hangman image.

By the time you have finished developing this application, you will have gained a good understanding of how to create custom functions and how to use them to improve the overall organization and maintenance of your Visual C++ applications.


CREATING FUNCTIONS

The previous chapter's project, the Dice Poker game, required you to create three custom functions: RollTheDice, Total TheScore, and EndOfGame. The purpose of these functions was to cut down on the overall detail of the project, make the code more readable, and allow you to execute certain blocks of code continuously without duplicating large blocks of code or using unnaturally large loops. The result was that the overall development of the game was simplified. As your applications continue to grow in both size and complexity, you will come to rely on functions for the detail reduction, flexibility, and improvements to readability that they provide.

Hint

A function is a collection of program statements that is called and executed as a unit. When associated with objects, functions are called methods.

At their core, functions make an application easier to develop by allowing you to break it down into smaller pieces. These smaller pieces are then, in code, fitted together to perform all your application's tasks. When you create a function, you gain the ability to logically group related statements and to focus on writing your application one function at a time.

Because you can call and execute a function over and over again as needed, functions also enable you to reduce the overall amount of code that you must write. This, in turn, makes your application easier to create and easier to maintain over time. If your application's major functionality is isolated into functions, for example, it is easier to change its features without impacting the rest of the code.

When you find yourself adding code to perform a major operation within the application, particularly one that is executed often, you usually have a good candidate for a function. For example, if you have several locations where you need to perform the same steps to validate user input, enclosing the code in a function allows you to invoke its functionality simply by using the function's name.

The syntax for a function is as follows:

[Return Type] Function Name([Arguments]);

To use a function, you must know three things:

  • Its name

  • What, if any, data you must give it (placed in parentheses after its name)

  • What, if any, data the function returns as a result of its operations

Image from book
IN THE REAL WORLD

Professional programmers often try to limit each function they write to performing one single, major operation or task that the application requires. This makes application code more modular and streamlined. It also helps to isolate errors.

When it comes to fixing bugs, functions can be likened to fire doors on a ship or within a building. They isolate problems within a given section of the code. You can locate bugs within a function more easily when program flow executes to specific, reliable points. Functions are those points. If, for example, a programmer adds 100 new lines of code to an application he is working on and suddenly discovers that the program no longer behaves properly, he might have a hard time figuring out where the problem lies. However, if this code is contained within four or five functions, the programmer stands a better chance of locating the bug more quickly because he can comment out functions one by one to determine where the error lies.

Image from book

In same cases, the latter two points might be optional, because a function cannot accept or return data.

Don't worry yet about understanding the specific elements of a function. I'll cover them in the next sections. First, try to concentrate on the big picture of what a function is.

Calling a Function

When you use a function's name in your code, you are said to be calling that function, or making a function call. Doing so causes Visual C++ to execute the code related to the name, which you define somewhere within your program or in another file. For example, if you wanted to use a function called ValidateInput, which ensures that a user has made the proper input, you would write its name on a line by itself, followed by the data to send to the function, followed by a semicolon:

ValidateInput();

In the previous chapter's game, Dice Poker, when you wrote RollTheDice, Total TheScore, and EndOfGame within your code, you were calling functions that you defined later. The first enclosed code was responsible for generating a random number to simulate die rolls and updating the game's die graphics. The second function, TotalTheScore, contained several lines of logic to determine what the die rolls mean in terms of winnings. The final function, EndOfGame, determined whether the player wanted to quit the game or start a new game. If he did, the function reset the application so that a new game could begin. The next sections explore how this process works.

Returning Data from a Function

One of the easiest aspects to understand about functions is their return type. Functions are often employed to perform tasks and return results. You then can assign these results to a variable, use them to drive a logical test, or use them as a conditional expression to control a loop.

The following code, for instance, illustrates two instances of converting a numeric value to a string so that it can be displayed by the MessageBox::Show method:

Double dblValue = 10;
Int32 intValue = 100;
//Convert the double value and assign it to
//  a textbox property
txtPassword->Text = dblValue.ToString();
//Display the results of the conversion and
//  assignment
MessageBox::Show( txtPassword->Text );
//Skip the assignment and just show the
//  conversion directly
MessageBox::Show( intValue.ToString() );

Both dblValue and intValue have methods (functions) that automatically convert their value to another data type. In this case, after both variables are declared and initialized, the first, dblValue, initializes the Text property of a text box, txtPassword, that was previously declared elsewhere in the program. Specifically, the value of 10 is returned as a string by dblValue's ToString method. This string is then copied to txtPassword->Text. Next, txtPassword->Text serves as an argument in the MessageBox::Show method, resulting in 10 being displayed in a dialog box.

The display of the value of intValue skips a step, however. Because intValue.ToString returns a string, the data it returns is supplied directly as an argument to MessageBox::Show, which needs at least one string for the application to display a message.

Hint

An argument is a variable or constant value, such as a number, that is passed to a function. When used within a function, an argument is referred to as a parameter.

The advantage of the first technique is that the contents returned by the method ToString are saved in another variable (txtPassword->Text) and can be used elsewhere. The advantage of the technique used by intValue is that no variable is required. This can be useful if you temporarily need to return a result from a function but don't care about saving that result.

Handling Events

Behind the scenes, Visual C++ invisibly performs numerous steps to make your application functional. The steps include displaying the controls on your application's form and making certain that it functions properly with the Windows operating system. Handling events is yet another aspect that Visual C++ manages seamlessly. In response to user input or other triggers, your application can generate events, which in turn link to program code that you have defined.

Hint

An event is an occurrence within your application, such as a button click, that can trigger the execution of an associated function if such a function has been defined. If no function has been defined, the event is handled by the code that Visual C++ generates, handled by the operating system, or ignored.

To give your WinForms applications the most basic functionality, you must place code within a function and then associate that code with an event or data relating to the form. If you don't, there is no link between your application code and the functionality of the form. You can see an example of this by creating a project, dragging a button to it, and then running it. When you click on the button, nothing happens because your application does not capture the button click event.

As noted earlier, you have been working with functions in all the chapter projects that you have completed so far in this book. For example, in many of the chapter game projects, you added code to perform tasks that executed when the application was first loaded. To do this, you double-clicked on the game project's form when viewing it in Design view. This caused Visual C++ to automatically generate a Load event function for you, which was then displayed in the Code Editor. A good example of this can be taken from the Dice Poker game's form Load event function, which is shown here:

private: System::Void Form1_Load(System::Object^\
sender, System::EventArgs^  e)
{
  //Seed random number generator with current time
  DateTime moment = DateTime::Now;
  randNumGen = gcnew Random( moment.Millisecond );

  // Set starting game variables
  pbxDie1->Image = imlDiceList->Images[0];
  pbxDie2->Image = imlDiceList->Images[0];
  pbxDie3->Image = imlDiceList->Images[0];

  pbxDie4->Image = imlDiceList->Images[0];
  pbxDie5->Image = imlDiceList->Images[0];
  blnExcludeList = false;
  intTimerCntr = 0;

  //Set starting money
  intTotalDollars = 20;

  //Set beginning text
  txtOutput->Text = \
  String::Concat( "Welcome! Are you ready "
  "to play Dice Poker?\r\r\nYou have ",
  intTotalDollars.ToString(),
  " dollars in your account." );
}

If you go back and look at the rest of the code in the Dice Poker game, you'll see that it is organized inside various functions. Most of these are events, which are generated as a result of your double-clicking on form controls in Design view.

Defining Custom Functions

Now that you have a better understanding of what functions are and what they can do, let's look at creating one. To create a function, you first must give it a unique name. The rules for naming functions are basically similar to variables: They must begin with a letter, and they can contain letters and numbers.

Trick

You should strive to give your function a name that reflects the task it performs. This makes your code read more like English, which will be easier to follow as you begin to add more functions.

After you have a name for the function, you must decide if you want it to return data. You also must determine if the function should accept data. The usage of the function differs based on these choices, but fortunately, the format for defining it is the same.

The format for defining a function is as follows. Each element that makes up the function is shown in brackets for better clarity:

[public | protected | private]: [Return Type] FunctionName ([params])
{

  function body
  .
  .
  .
}

The first component of the function definition, which specifies whether it is public, protected, or private, relates to Object-Oriented Programming. As such, it is discussed more thoroughly in Chapter 9, "Getting Comfortable with Object-Oriented Programming." For now, you should know that the first component determines whether other modules can see and use the function.

The next element of the function, the return type, specifies the type of data that the function returns. You are free to use most of the data types, such as Int16, Int32, Double, or Void. Some data types, such as the String type, have special considerations, so you should avoid using them until you have a better understanding of handles (discussed briefly later in this chapter). Also, note that by declaring the return type of your function to be Void, you indicate to Visual C++ that your function will return no data.

The next element of the function definition is the function name. This is followed by the parameter list (shown in the previous example as params). You can indicate that your function will accept no data or one or more pieces of data. If your function accepts no data, you must specify Void in the parentheses following its name. If you want to accept data, you must place the variable type and name that will be used inside the function. You can specify multiple variable names and types by separating each with a comma.

To understand this better, let's look at some examples:

private: System::Void Form1_Load(System::Object^\
sender, System::EventArgs^  e)
{
  InitiateGame();
  SetStartingMoney( intStartingMoney );
  SetStartingMoney( 200 );
  blnSuccess = CheckSignIn();
}

In this sample listing, a call is made to several functions when the application's Load function is called. First, a Load function calls a function that neither accepts nor returns data, called InitiateGame. Next, SetStartingMoney is called and passes as an argument a variable, defined elsewhere, called intStartingMoney. Just to illustrate parameter passing, this function is called again, using a constant value of 200 rather than a variable.

Finally, a function called CheckSignIn is called, which accepts no data but returns a Boolean value. This return value is assigned to the blnSuccess variable. Note that if you specify a function as having a return type other than Void, you must use the keyword return to return a value that matches the data type. Failing to do so generates an error.

Here is a basic example of how you can define these functions:

private:Void InitiateGame( Void )
{
  blnGameInitialized = true;
  btnStart->Enabled = true;
}

private:Void SetStartingMoney( Int32 intMoney )
{
  intGameMoney = intMoney;
}

private:Boolean CheckSignIn( Void )
{
  return false;
}

In this example, the first function, InitateGame, indicates that it does not accept data because both its return type and list of arguments are Void. Instead, it sets a Boolean value, blnGameInitialized (defined elsewhere), and enables one of the application's buttons. The second function, SetStartingMony, assigns the intGameMoney variable (defined elsewhere in the program) to the parameter called intMoney. This enables it to accept any Int32 value, which can be a variable or a number. The last example, CheckSignIn, returns false, a Boolean value.

Image from book
IN THE REAL WORLD

Although this example would not be very functional, it illustrates a process called stubbing, which is a popular technique that programmers use to get an application up and running quickly. Stubbing functions involves defining all the functions that an application will use but giving the interior of those functions the minimal code they need to work. It allows an application to be put together in a skeletal fashion, with code being quickly added after the overall structure is defined.

Image from book


PASSING ARGUMENTS

Arguments provide a means for passing data to functions so that it can be processed or control the function's internal logic. After the arguments are passed to a function, they are mapped to parameters that are defined as part of the function's declaration, as demonstrated here:

private:Void ShowAge( Int32 intAge )
{
  MessageBox::Show( intAge.ToString() );
}
Trick

You can set up your functions to process as many arguments as you choose to pass to them, as long as you separate each corresponding argument definition with a comma.

In this example, a function named ShowAge is defined. The function defines a single variable, a parameter named intAge with a data type of Int32. The variable, or function parameter, is then used in the MessageBox::Show method to a value of intAge.

Hint

A parameter is a declaration within a function that defines variables to be used to store copies of values passed to them as arguments.

Outside of the function, you can use any Int32 as an argument when calling the function. For example, you could invoke the function using any of these means:

Int32 intCurrentAge = 20;
ShowAge(intCurrentAge);
ShowAge( 120 );

When a function accepts data in the form of a parameter, you are said to be passing by value. This means you are free to make changes to the variable within the function without those changes being reflected outside the function. For example, if you pass intCurrentAge in the previous example as a parameter, you cannot change it within the function.

You can pass as many arguments as required to a function, as long as you separate each argument with a comma when calling the function, as demonstrated here:

DisplayVitals( intAge, intWeight, intHeightInInches );

To better understand this, let's create a short program example:

  1. Start by launching Visual C++ and creating a new project.

  2. Add four labels and three text boxes to the form. Label the first TextBox control txtAge, the second txtWeight, and the last txtHeight.

  3. Add a button to the form. Change its text to Submit.

  4. Name and arrange all elements, as illustrated in Figure 8.8.

Image from book
Figure 8.8: Entering data into the Vitals application.

Next, double-click on the button and add the following code:

private: System::Void button1_Click(System::Object^  sender,\ System::EventArgs^  e)
{
  Boolean blnInputValid = false;
  //Declare variables to hold vitals
  Double dblAge,
          dblWeight,
          dblHeight;
  //Confirm proper input
  blnInputValid = Double::TryParse( txtAge->Text, dblAge );
  if( blnInputValid == false )
    return;
  blnInputValid = Double::TryParse( txtWeight->Text, dblWeight );
  if( blnInputValid == false )
    return;
  blnInputValid = Double::TryParse( txtHeight->Text, dblHeight );
  //If input valid, show vitals
  if( blnInputValid == true )
    ShowVitals( dblAge, dblWeight, dblHeight );
}

Below this function, add the following code:

private: Void ShowVitals( Double dblVital Age, \
          Double dblVitalWeight,  \
          Double dblVitalHeightInInches )
{
  MessageBox::Show( String::Concat( "Your age is ",
  dblVitalAge.ToString(), ". Your weight is ",
  dblVitalWeight.ToString(), ". Your height is ",
  dblVitalHeightInInches.ToString(), " inches." ) );
}

Press F5 to run your program. After you enter the required information, select the Submit button to see the information displayed. The program works by first validating user input in the button1_Click function. If the user input proves acceptable, the function then calls ShowVitals, passing it three arguments. Within the ShowVitals function, the three arguments are received as parameters. The parameters are concatenated using the String::Concat method and then displayed using the MessageBox::Show method. Figure 8.9 illustrates the results.

Image from book
Figure 8.9: A function within the Vitals application shows the information passed to it.


PASSING DEFAULT ARGUMENTS

Visual C++ also provides you with the ability to set up functions that can process default arguments. There are a few rules you need to be aware of when setting up a function to accept default arguments. First of all, you must assign a constant value to all default arguments. In other words, you cannot use a variable or other type of value. Finally, any argument that follows a default argument must be another default argument.

The following example demonstrates how to set up a function with a default argument:

private:Void ShowAge( Int32 intAge = 32 )
{
  MessageBox::Show( intAge.ToString() );
}

You can call the function in the previous example without passing it an argument, as shown here:

ShowAge();

Alternatively, you can call the function and pass it an argument, like this:

ShowAge( 100 )

Default arguments are useful because they allow you to ensure that a function's parameters are initialized. They can be useful in speeding application development by allowing you to use abbreviated function calls for the most common cases and detailed versions when you need to specify arguments outside of the norm.


LEVERAGING THE BUILT-IN FUNCTIONS AND .NET CLASSES

Although the ability to create your own functions is a powerful programming tool, allowing you to perform all sorts of tasks, it is not always necessary for you to develop all the programming logic required to perform a given task. Instead, you can take advantage of Visual C++'s built-in collection of functions in addition to properties and methods provided by .NET classes. By leveraging the functionality provided by these functions and classes, you can save a lot of development time.

You've already learned how to work with a number of built-in Visual C++ functions. One good example has been the use of the MessageBox::Show method, which provides a means for displaying information in its own window.

You could, of course, create your own custom MessageBox::Show method by creating a form and adding various labels and buttons to it, followed by the programming logic required to tie everything together. However, unless the MessageBox::Show function fails to provide you with a particular piece of functionality, there is really no reason to duplicate the code that Visual C++ provides.

Date-Related Classes

The .NET Framework provides numerous classes that assist you in working with the date and time. For example, the DateTime class's Now() method can retrieve the current system date and time, as demonstrated here:

MessageBox::Show( DateTime::Now.ToString() );
Hint

The DateTime class represents a moment in time. Its Now property retrieves the current date and time from the computer.

When executed, this statement produces the pop-up window shown in Figure 8.10.

Image from book
Figure 8.10: Using the DateTime.Now() function to display the current date and time.

You can also use the Convert object's ToDateTime method to convert a string value to a Date data type, as demonstrated here:

DateTime dteDate;
String^ strDate = gcnew String( "12/01/05" );
dteDate = Convert::ToDateTime( strDate );
MessageBox::Show( dteDate.ToString() );
Hint

The Convert class allows you to convert or change a data type from one type to another. Its ToDateTime method allows you to convert numerous data types to the Date data type.

The following example demonstrates how to use the TimeSpan object's Subtract method to determine the number of days that have elapsed from the specified date to the current date. In the case of this example, the specified date is November 11, 1964:

DateTime dteCurrentDate = DateTime::Now;
DateTime dteBirthDate;
TimeSpan dteDateDiff;
dteBirthDate = Convert::ToDateTime( "03/16/1965" );
dteDateDiff = dteCurrentDate.Subtract( dteBirthDate );
MessageBox::Show(
 String::Concat( "I was born ",
 dteDateDiff.Days, " days ago." ) );
Hint

The TimeSpan object represents an interval of time.

The first three statements in this example declare objects that store the current date, a hypothetical birth date, and an object to hold the difference between the two. The dteCurrentDate object is initialized with the current date, which is retrieved from DateTime::Now. The dteBirthDate object uses the Convert::ToDateTime method to convert the birth date. The difference is then assigned to dteDateDiff by calling dteCurrentDate.Subtract( dteBirthDate). The result is shown using MessageBox::Show.

String Manipulation Functions

Strings are a commonly used data type in Visual C++ applications. Applications need to work with string values in various ways, including the following:

  • Searching for one string within another

  • Parsing string contents to extract part of a string

  • Formatting the contents of a string

The .NET Framework provides Visual C++ with abundant methods for manipulating strings. For example, using the ToString method, you can convert a value to a String data type, as demonstrated here:

Double dblValue = 123.5;
strVal = dblValue.ToString();

In this example, the Double object's ToString method converts the number 123.5 to a string, which is then assigned to a variable named strVal. The following list provides a sampling of different types of methods and properties provided by the String object:

  • Trim. A method that removes leading and trailing blank spaces from a value

  • ToUpper. A method that retrieves an all-uppercase version of a string

  • ToLower. A method that retrieves an all-lowercase version of a string

  • Length. A property that returns the number of characters that make up a string

  • Substring. A method that returns a value indicating the starting location of one string within another

  • Contains. A method that determines whether one string is contained within another

  • Concat. A method that creates a new string from multiple strings

The following example demonstrates how to use each of these String manipulation functions:

String^ strSentence = gcnew String( "The quick brown fox" );
strSentence = String::Concat( strSentence, " jumped over the",
" lazy dog!" );

In this example, a new string is declared that contains the phrase The quick brown fox. The string is then appended using the String::Concat method. The first parameter is the string itself, strSentence. This ensures that the current contents are not erased. Next, two sentences are added together along with strSentence. The result is a completely new sentence, which is assigned to strSentence.


BACK TO THE HANGMAN GAME

Now it is time to return your attention to this chapter's game project, the Hangman game. The Hangman game is based on a children's game in which the player attempts to guess a secret word. If the player guesses the word before making six incorrect guesses, the player wins. Otherwise, he loses.

You will create the Hangman game by following the same five basic development steps that you followed when completing previous chapter projects.

Designing the Game

The Hangman game will be played within a single window. Therefore, it will be made up of one form and the 25 controls listed in Table 8.1.

Table 8.1: Form Controls for the Hangman Game
Control Type | Control Name | Description
Panel1 | pnlLetters | Groups TextBox controls that will display letters of a guessed word
TextBox1 | txtLetter1 | Displays the first letter in the game's secret word
TextBox2 | txtLetter2 | Displays the second letter in the game's secret word
TextBox3 | txtLetter3 | Displays the third letter in the game's secret word
TextBox4 | txtLetter4 | Displays the fourth letter in the game's secret word
TextBox5 | txtLetter5 | Displays the fifth letter in the game's secret word
TextBox6 | txtLetter6 | Displays the sixth letter in the game's secret word
TextBox7 | txtLetter7 | Displays the seventh letter in the game's secret word
TextBox8 | txtLetter8 | Displays the eighth letter in the game's secret word
TextBox9 | txtLetter9 | Displays the ninth letter in the game's secret word
TextBox10 | txtLetter10 | Displays the tenth letter In the game's secret word
TextBox11 | txtMisses | Displays the number of misses that the player has made
TextBox12 | txtGuesses | Displays the letters that the player has already guessed (both right and wrong)
TextBox13 | txtGamesWon | Displays the number of games that the player has won
TextBox14 | txtGamesLost | Displays the number of games that the player has lost
GroupBox1 | grpStats | Contains Label and TextBox controls that display game statistics
Label1 | lblInput | Identifies the TextBox control where the player enters a letter guess
Label2 | lblNoMissed | Identifies the TextBox control that displays the number of misses that the player has made
Label3 | lblGuessed | Identifies the TextBox control that displays the letters that the player has already guessed (both right and wrong)
Label4 | lblGamesWon | Identifies the TextBox control that displays the number of games that the player has won
Label5 | lblGamesLost | Identifies the TextBox control that displays the number of games that the player has lost
Button1 | btnSubmit | Executes code that checks to see if the player has guessed a letter in the secret word
PictureBox1 | pbcHangmanBmp | Displays a graphic that shows how many letter guesses the player has missed
ImageList1 | imlHangmanBmps | Stores an indexed collection of the Hangman images that are displayed in the PictureBox control

Step 1: Creating a New Visual C++ Project

The first step in creating the Hangman game is to open Visual C++ and create a new project, as outlined here:

  1. If you have not already done so, start Visual C++ 2005 Express and then click on File, New Project. The New Project dialog box will appear.

  2. Select Windows Application template.

  3. Type Hangman as the name of your new application in the Name field located at the bottom of the New Project window.

  4. Click on OK to close the New Project dialog box.

Visual C++ then creates a new project for you and displays a new form upon which you will design the game's user interface.

Step 2: Creating the User Interface

Now let's begin work on laying out the game's user interface by adding controls to the form and moving and resizing them in the appropriate locations. Refer to Figure 8.11 as you go through each step so that you know how to resize and place the controls.

  1. Begin by clicking on the form and setting its Size property to 655, 412.

  2. Add a Panel control to the form and resize it, as shown in Figure 8.11.

    Hint

    A Panel control is a control that that stores and organizes other controls.

  3. Add 10 TextBox controls inside the Panel control and resize them.

  4. Add a Label control to the form. By default, Visual C++ names it Label1.

  5. Just to the right of the Labell control, add a TextBox control and a Button control.

  6. Add a GroupBox control at the bottom of the form and resize it until it takes up the bottom 30 percent of the form.

  7. Inside the GroupBox control, add four Label and four TextBox controls.

  8. Add a PictureBox control to the lower-right corner of the form and set its size to 200,200.

  9. Finally, add an ImageList control, which will appear in a Component Tray, located at the bottom of the Form Designer.

Image from book
Figure 8.11: Examining the Layout of the Hangman game's user interface.

Now that you've completed the overall layout for the Hangman game user interface, you can begin form and control property customization.

Step 3: Customizing Form and Control Properties

Let's begin by modifying properties that are associated with the game's form, as shown in Table 8.2.

Table 8.2: Property Changes for Form1
Property | Value
Name | frmMain
Cursor | Hand
FormBorderStyle | Fixed3D
MaximizeBox | false
MinimizeBox | false
Size | 540,360
StartPosition | CenterScreen
Text | Hangman

Next, modify the properties associated with the Panel control, as shown in Table 8.3.

Table 8.3: Property Changes for the Panel Control
Property | Value
Name | pnlLetters
BackColor | Menu
BorderStyle | Fixed3D

Then modify the properties associated with the GroupBox control, as shown in Table 8.4.

Table 8.4: Property Changes for the GroupBox Control
Property | Value
Name | grpStats
Text | Game Stats:

Now modify the properties associated with the TextBox controls, as shown in Table 8.5.

Table 8.5: Property Changes for the TextBox Controls
Control | Property | Value
TextBox1 | Name | txtLetter1
 | BackColor | Menu
 | BorderStyle | None
 | Font.Size | 36
 | Font.Bold | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox2 | Name | txtLetter2
 | BackColor | Menu
 | BorderStyle | None
 | Font.Size | 36
 | Font.Bold | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox3 | Name | txtLetter3
 | BackColor | Menu
 | BorderStyle | None
 | Font.Size | 36
 | Font.Bold | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox4 | Name | txtLetter4
 | BackColor | Menu
 | BorderStyle | None
 | Font.Size | 36
 | Font.Bold | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox5 | Name | txtLetter5
 | BackColor | Menu
 | BorderStyle | None
 | Font.Size | 36
 | Font.Bold | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox6 | Name | txtLetter6
 | BackColor | Menu
 | BorderStyle | None
 | Font.Size | 36
 | Font.Bold | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox7 | Name | txtLetter7
 | BackColor | Menu
 | B Bold orderStyle | None
 | Font.Size | 36
 | Font. | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox8 | Name | txtLetter8
 | BackColor | Menu
 | BorderStyle | None
 | Font.Size | 36
 | Font.Bold | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox9 | Name | txtLetter9
 | BackColor | Menu
 | BorderStyle | None
 | Font.Size | 36
 | Font.Bold | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox10 | Name | txtLetter10
 | BackColor | Menu
 | BorderStyle | None
 | Font.Size | 36
 | Font.Bold | true
 | ForeColor | Menu Highlight
 | ReadOnly | true
 | TabStop | false
TextBox11 | Name | txtInput
 | CharacterCasing | Upper
 | Font.Size | 18
 | Font.Bold | true
TextBox12 | Name | txtMisses
 | ReadOnly | true
 | TabStop | false
TextBox13 | Name | txtGuesses
 | ReadOnly | true
 | TabStop | false
TextBox14 | Name | txtGamesWon
 | ReadOnly | true
 | TabStop | false
TextBox15 | Name | txtGamesLost
 | ReadOnly | true
 | TabStop | false

Then modify the properties associated with the Button control, as shown in Table 8.6.

Table 8.6: Property Changes for the Button Control
Property | Value
Name | btnSubmit
Font.Bold | true
Text | Submit

Modify the properties associated with the Label controls, as shown in Table 8.7.

Table 8.7: Property Changes for the Label Controls
Control | Property | Value
Label1 | Name | 1blInput
 | Text | Enter A Letter Guess:
 | Font.Bold | true
Label2 | Name | lblNoMissed
 | Text | No. Of Misses:
 | Font.Bold | true
Label3 | Name | 1blGuesses
 | Text | No. of Guesses:
 | Font.Bold | true
Label4 | Name | 1blGamesWon
 | Text | No. Games Won:
 | Font.Bold | true
Label5 | Name | lblGamesLost
 | Text | No. Games Lost:
 | Font.Bold | true

From there, modify the properties associated with the PictureBox control, as shown in Table 8.8.

Table 8.8: Property Changes for the PictureBox Control
Property | Value
Name | pbcHangmanBmp
BorderStyle | Fixed3D
Size | 200,200
SizeMode | StretchImage

Finally, change the Name property of the ImageList control to imlHangmanBmps and add the following bitmap images to the Images property (col1ection), as shown in Table 8.9. Don't worry about having to create these bitmap images yourself. I have included copies of them with the source for the game project on the book's companion Web site.

Table 8.9: Bitmap Images to Add to the ImageList Control's Images Collection
Property | File | Index No.
Name | 100.bmp | 0
Name | 80.bmp | 1
Name | 60.bmp | 2
Name | 40.bmp | 3
Name | 20.bmp | 4
Name | 10.bmp | 5
Name | 0.bmp | 6

Step 4: Adding a Little Programming Logic

Begin coding the Hangman game by double-clicking on the game's form, which causes Visual C++ to open the Code Editor and position the cursor on the game's Load event function, as shown here:

private: System::Void frmMain_Load(System::Object^  sender,\
System::EventArgs^  e)
{
}

Above the Load function, add the code to the area reserved for module variables, as shown next:

private:
     /// <summary>
     /// Required designer variable.
     /// </summary>
     //Array to hold game words
     array<String^>^ strWordListArray;

     //String for game's current word
     String^ strGameWord;
     //String for missed guesses
     String^ strWrong;
     //Counter for missed guesses
     Int32 intMisses;
     //Counter for correct guesses
     Int32 intNoRight;
     //Counter for games won
     Int32 intGamesWon;
     //Counter for games lost
     Int32 intGamesLost:
     //Controls display of Hangman image
     Int32 intHangmanNo;

These statements define a special type of .NET array capable of handling arrays of strings, two variables (handles) for holding the game's current word and missed guesses, and several Int32 counters that track the player's progress. The final variable, intHangmanNo, controls which image of the gallows to display, based on the player's progress in the game.

Now add the following statements to the Form1_Load function:

private: System::Void frmMain_Load(System::Object^  sender,\
System::EventArgs^  e)
{
     strGameWord = gcnew String("");
     strWrong = gcnew String("");
     intGamesWon = 0;
     intGamesLost = 0;
     intHangmanNo = 6;
     //Populate the array with words
     LoadWordArray();
     //Set up the game's starting values
     InitializeGameStats();
     StartTheGame();  //Start the game
}

The function begins by setting aside memory for two of the game's String handles—strGameWord and strWrong—and initializing both to an empty value (for example, using ""). Next, the number of games won and lost is set, as is the variable, intHangmanNo, that will later control what gallows image to display. Finally, the Form1_Load function sets up gameplay by calling three custom functions. The LoadWordArray function populates the strWordListArray array with 20 secret words. To create it, scroll down below the Form1_Load function and enter the following statements:

private: Void LoadWordArray( Void )
{
    const Int32 cintArraySize = 20;
    StrWordListArray = \
      gcnew array<String^>(cintArraySize);
    strWordListArray->SetValue( "ELEPHANT", 0 );
    strWordListArray->SetValue( "CARRIAGE", 1 );
    strWordListArray->SetValue( "ENVELOPE", 2 );
    strWordListArray->SetValue( "PRESIDENT", 3 );
    strWordListArray->SetValue( "ELLIPTICAL", 4 );
    strWordListArray->SetValue( "MARKER", 5 );
    strWordListArray->SetValue( "BATTLESHIP", 6 );
    strWordListArray->SetValue( "TERMINATE", 7 );
    strWordListArray->SetValue( "REJOICE", 8 );
    strWordListArray->SetValue( "LIBERTY", 9 );
    strWordListArray->SetValue( "CLASSIC", 10 );
    strWordListArray->SetValue( "REFLEX", 11 );
    strWordListArray->SetValue( "VERSION", 12 );
    strWordListArray->SetValue( "DWELLING", 13 );
    strWordListArray->SetValue( "APARTMENT", 14 );
    strWordListArray->SetValue( "MATRIX", 15 );
    strWordListArray->SetValue( "FAUCET", 16 );
    strWordListArray->SetValue( "BEDROOM", 17 );
    strWordListArray->SetValue( "VOLLEY", 18 );
    strWordListArray->SetValue( "WHISTLE", 19 );
}

This function first uses gcnew to initialize an object to hold all the strings. The format is a bit tricky to understand at first, but what the function does is to first declare a constant, cintArraySize, that is set to the value 20. This constant then sets the size of the array requested (20 elements). The gcnew keyword allocates an array (using the array keyword) of String handles, which are denoted by the syntax String^. The resulting block of memory is then populated with all the words within the game using the SetValue method for each element.

Next, the InitializeGameStats function sets the game statistics displayed in the GroupBox control to zeroes. You'll need to create this function from scratch by inserting it just under the LoadWordArray function. Its format is as follows:

private: Void InitializeGameStats( Void )
{
    //Reset and display games won and lost
    intGamesWon = 0;
    intGamesLost = 0;
    txtGamesWon->Text = intGamesWon.ToString();
    txtGamesLost->Text = intGamesLost.ToString();
}

The StartTheGame function is responsible for setting up the game to play a new round. It does so by making three function calls, which reset variable defaults, retrieve a secret game word, and format the word for display. The function ends by setting focus to the txtInput control to ready the game for the player input:

private: Void StartTheGame( Void )
{
    //Reset game settings
    ResetDefaultSettings();
    //Get a word for the player to guess
    RetrieveWord();
    //Format the display of the mystery word
    FormatGameWord();
    //Prepare to accept the player's guess
    txtInput->Focus();
}

Next, create the ResetDefaultSettings function, shown next, to prepare the game to play a new round:

private: Void ResetDefaultSettings( Void )
{
    //Reset all game settings
    intMisses = 0;
    intNoRight = 0;
    txtGuesses->Text = "";
    txtMisses->Text = intMisses.ToString();
    txtInput->Text = "";
    intHangmanNo = 6;
    pbcHangmanBmp->Image =\
    imlHangmanBmps->Images->default[intHangmanNo];
}

Note that in addition to resetting variable default values, the final statement in the previous function displays an empty hangman's gallows graphic in the PictureBox control.

Now create the RetrieveWord function. The function first creates a random number generating object, randNumGen, from the Random object and seeds it with the current time (expressed as DateTime::Now). Then you choose a random number based on a range specified by strWordListArray->Length, which is the length of the array. You use this value to access the array using strWordListArray->GetValue(intRandomNo)->ToString(). Note that this last statement looks more complicated than it actually is. It gets the value of the location specified by intRandomNo using the array object's GetValue method and then converts that value to a String data type. This allows the value to be assigned to strGameWord, thus creating the secret word:

private: Void RetrieveWord( Void )
{
    //Seed random number generator with current time
    DateTime moment = DateTime::Now;
    Random^ randNumGen = gcnew Random( moment.Millisecond );

    //Declare a variable to hold a randomly
    //  generated number
    Int32 intRandomNo = 0;

    //Use the Random object's Next method to retrieve
    //  a number between zero and the number
    //  of words in the array
    intRandomNo = randNumGen->Next( strWordListArray->Length );

    //Use the random number to select a word from
    // the array
    strGameWord = \
      strWordListArray->GetValue(intRandomNo)->ToString();
}

Next, create the FormatGameWord function, as shown next. The function begins by assigning an empty string to each of the 10 TextBox controls that display the letters making up the game's secret word. The function then sets up a for loop to display an underscore character for each letter in the secret word:

private: Void FormatGameWord( Void )
{

    //Game words are limited to 10 or fewer characters.
    //  Each letter is stored in a separate TextBox
    //  control. Start formatting by setting the value
    //  stored in each TextBox control to a blank character
    txtLetter1->Text = "";
    txtLetter2->Text = "";
    txtLetter3->Text = "";
    txtLetter4->Text = "";
    txtLetter5->Text = "";
    txtLetter6->Text = "";
    txtLetter7->Text = "";
    txtLetter8->Text = "";
    txtLetter9->Text = "";
    txtLetter10->Text = "";

    //Loop once for each word in the current letter and
    //  set an underscore in the appropriate text box
    for( Int32 intCounter = 0; intCounter <= strGameWord->Length;
         intCounter++ )
    {
      if( intCounter == 1 )
        txtLetter1>Text = "_";
      if( intCounter == 2 )
        txtLetter2->Text = "_";
      if( intCounter == 3 )
        txtLetter3->Text = "_";
      if( intCounter == 4 )
        txtLetter4->Text = "_";
      if( intCounter == 5 )
        txtLetter5->Text = "_";
      if( intCounter == 6 )
        txtLetter6->Text = "_";
      if( intCounter == 7 )
        txtLetter7->Text = "_";
      if( intCounter == 8 )
        txtLetter8->Text = "_";
      if( intCounter == 9 )
        txtLetter9->Text = "_";

      if( intCounter == 10 )
        txtLetter10->Text = "_";
     }
}

You can create the next function, shown below, by returning to the Form Designer, double-clicking on the btnSubmit control, and then modifying the function:

private: System::Void btnSubmit_Click(System::Object^  \
sender, System::EventArgs^  e)
{
    //Make sure input is valid
    if( !PlayerInputValid() )
      return;  //Exit on invalid guess

    //If the letter has already been guessed, display an error
    if( txtGuesses->Text->Contains( txtInput->Text->ToUpper() ) )
      MessageBox::Show("Error:"
      "That letter has already been guessed.");
    else //Check whether a correct letter was guessed
    {
      //Add the letter to the list of already guessed letters
      txtGuesses->Text = String::Concat( txtGuesses->Text,
                           txtInput->Text );

      //Look for the letter in the word
      if( !strGameWord->Contains( txtInput->Text->ToUpper() ) )
      {
        //The player's guess was wrong
        //Append letter to the list of missed guesses
        strWrong = String::Concat( strWrong,
                    " ", txtInput->Text->ToUpper() );
        //Update and display missed guesses
        intMisses += 1;
        txtMisses->Text = intMisses.ToString();

        //Reduce the counter used to control the Hangman picture and
        // update graphic
        intHangmanNo -= 1;

       pbcHangmanBmp->Image =\
         imlHangmanBmps->Images->default[intHangmanNo];

       //End game at six wrong guesses
       if( intMisses == 6 )
       {
         //Update lost games and inform player
         intGamesLost += 1;
         txtGamesLost->Text = intGamesLost.ToString();
         //Call procedure to see if player wants to play again
         MessageBox::Show( "Sorry. You have lost." );
         PromptForNewGame();
         return;
       }
     }

     //Use for loop to check each letter in the word
     for( Int32 intCounter = 0; intCounter <= \
         strGameWord->Length; intCounter++ )
     {
       //Select one letter at a time
       if( String::Compare( strGameWord, intCounter,
           txtInput->Text, 0, true ) == 0 )
       {
         //Update and display guesses
         intNoRight += 1;
         FlipGameLetter( intCounter );
       }
     }
    }

    //See if the player has guessed every letter in the word
    if( intNoRight == strGameWord->Length )
    {
      intGamesWon += 1;
      txtGamesWon->Text = intGamesWon.ToString();
      //Call the procedure to see if the player wants to play again
      MessageBox::Show( "Congratulations. You have Won!" );

      PromptForNewGame();
    }

    txtInput->Text = "";
    txtinput->Focus();
}

The function begins by making sure that the player input is correct by calling the PlayerInputValid function. If the input is okay, the function continues to execute.

Next, the function uses an if...else statement to see if the player has entered a letter guess that has already been tried. This is done by converting input to uppercase and then searching the string for an instance of the letter. Specifically, the txtInput->Text property is converted to uppercase using the ToUpper method. Then it is supplied as an argument to the txtGuesses->Text object's Contains method. (Incidentally, this method is available to all String objects.)

If the player guesses a new letter, that letter is appended to the end of the string displayed in the txtGuesses control. This is done, as in previous chapters, using the highly useful String::Concat method, which can join several strings.

Next, an embedded if statement checks whether the player's guess is wrong by using the object's Contains method. If the player guesses incorrectly, the StrWrong string containing incorrect guesses is updated. Then the value holding the number of misses is updated and stored in the txtMisses control, and the graphic displayed in the PictureBox control is changed to reflect the number of misses so far. A check is then made to see if the player has missed the maximum of six guesses and lost the game.

If the player has not lost, a for loop iterates through the secret word comparing each of its letters with the letter the player entered. For each correct letter, the game updates the counter, keeping track of the number of right answers. It also displays the corresponding letter using the FlipGameLetter function.

Finally, a check is made to see if the player has guessed all the letters that make up the secret word, thus winning the game. If the player has not won the game, the txtInput control is cleared and given focus, thus preparing the game for the player's next guess.

Next, you need to manually create the PlayerInputValid function. This function needs to return a value, so you must define it as shown here:

private: Boolean PlayerInputValid( Void )
{

    //Create a list of letters to compare input to
    String^ strAlphabet = gcnew String( \
    "ABCDEFGHIJKLMNOPORSTUVWXYZ" );
    //See if the player clicked on Submit without
    //  entering a guess
    if( txtInput->Text == "" )
    {
      MessageBox::Show("Error: You must enter a letter.");
      txtInput->Text = "";
      txtInput->Focus();
      return false;
    }

    //See if the player entered more than one character
    if( txtInput->Text->Length > 1 )
    {
      MessageBox::Show("Error: Please enter only 1 letter." );
      txtInput->Text = "";
      txtInput->Focus();
      return false;
    }

    //See if the player entered a number
    if( !strAlphabet->Contains( txtInput->Text ) )
    {
      MessageBox::Show("Error: Please enter a letter.");
      txtInput->Text = "";
      txtInput->Focus();
      return false;
    }
    return true;
}

The function performs three input validation tests to make sure the player has provided an acceptable guess. It accomplishes this using three if statements. The first if statement makes sure that the player has entered something. The second if statement makes sure that the player has not entered more than one character, and the third if statement makes sure that the player hasn't entered a number.

Each time the player correctly guesses a letter, the FlipGameLetter function executes. You need to manually create this function, as shown here:

private: Void FlipGameLetter( Int32 intLetterNumber )
{
     //Match the letter to be displayed with the
     //  correct text box and show the letter
     switch( intLetterNumber )
     {
       case 0 :
         txtLetter1>Text = txtInput->Text->ToUpper();
         break;
       case 1 :
         txtLetter2->Text = txtInput->Text->ToUpper();
         break;
       case 2 :
         txtLetter3->Text = txtInput->Text->ToUpper();
         break;
       case 3 :
         txtLetter4->Text = txtInput->Text->ToUpper();
         break;
       case 4 :
         txtLetter5->Text = txtInput->Text->ToUpper();
         break;
       case 5 :
         txtLetter6->Text = txtInput->Text->ToUpper();
         break;
       case 6 :
         txtLetter7->Text = txtInput->Text->ToUpper();
         break;
       case 7 :
         txtLetter8->Text = txtInput->Text->ToUpper();
         break;
       case 8 :
         txtLetter9->Text = txtinput->Text->ToUpper();
         break;
       case 9 :
         txtLetterl0->Text = txtInput->Text->ToUpper();
         break;
     }
}

This function consists of a single switch statement, which compares the player's guess to each letter in the secret word and flips (that is, displays) any letters that match the guess.

The last function that you need to create is the PromptForNewGame function. You must manually define this function and then set it up as shown here:

private: Void PromptForNewGame( Void )
{
    //Variable used to hold player response
    Windows::Forms::DialogResult drPlayAgain;

    //Prompt player to try again
    drPlayAgain = MessageBox::Show(
    "Would you like to play again?", "Hangman",
    MessageBoxButtons::YesNo, MessageBoxIcon::Question,
    MessageBoxDefaultButton::Button1 );

    //if player clicks on Yes, set up a new game
    if( drPlayAgain == Windows::Forms::DialogResult::Yes )
      StartTheGame(); //Start a new game
    else // End the game
      this->Close();
}

The function uses the MesssageBox::Show method to ask if the player would like to play another round. If the player clicks on the Yes button, the StartTheGame function executes. Otherwise, the Close method, accessed through your form application's this keyword, terminates the application.

Step 5: Testing the Execution of the Hangman Game

The Hangman game is now complete. Press F5 and test the game to make sure everything is working properly. If you run into errors, check to see if you have made one or more typing mistakes. If you decide to share the game with others, remember to test all aspects of the game, including feeding it good and bad input.


SUMMARY

In this chapter, you learned how to improve the overall organization and design of your Visual C++ applications using functions. This included learning how to create your own custom functions that could accept and return data. You also learned how to define default values for your functions and to employ some of the functions provided by the .NET Framework. In addition, you learned how to use the Panel control as a container for storing other controls. Before you move on to the next chapter, take a few extra minutes and see if you can improve on the Hangman game by implementing the following challenges.


CHALLENGES

  1. Improve the Hangman game by separating the display of letters correctly guessed from letters incorrectly guessed.

  2. Increase the size of the game's array and make the required modifications to the program's code so that you can provide a bigger pool from which to draw secret words.

  3. Add a CheckBox control to the game just under the PictureBox control and use it to give the player the option of displaying or hiding the GroupBox control and its contents. Adjust the size of the form as appropriate.

  4. The Hangman game can sometimes draw the same letter twice in a row. Prevent this from happening. (Hint: One way to do this is to use a static variable.)


Chapter 9: Getting Comfortable with Object-Oriented Programming

OVERVIEW

In this chapter, you learn fundamental concepts in Object-Oriented Programming using Visual C++. You are introduced to new programming concepts, including abstraction, encapsulation, and polymorphism.

You also learn more about objects and classes. This includes a look at classes within the .NET Framework and those you can create yourself. In addition, you learn how to use custom classes to store and protect the data and provide custom functionality. You also have an opportunity to create another Visual C++ application, this one based on the classic children's game Rock, Paper and Scissors.

In this chapter, you learn the following:

  • What Object-Oriented Programming is

  • How to define custom classes

  • How to instantiate objects based on your custom classes

  • How to set up method overloading within custom classes

  • How to provide controlled access to the data stored within objects


PROJECT PREVIEW: THE ROCK, PAPER AND SCISSORS GAME

This chapter's game project is the Rock, Paper and Scissors game. The rules of the game are quite simple. Each player attempts to outguess an opponent (in this case, the computer) by consistently selecting the better of three choices. The rules for resolving each game are as follows:

  • Rock crushes scissors to win.

  • Paper covers rock to win.

  • Scissors cuts paper to win.

  • Matching choices automatically tie.

Figures 9.1 to 9.5 illustrate how the Rock, Paper and Scissors game works, outlining the application's overall functionality and execution.

Image from book
Figure 9.1: The Rock, Paper and Scissors game begins by displaying the game board.
Image from book
Figure 9.2: When the player clicks on the Play button, a 1.5-second countdown begins.
Image from book
Figure 9.3: The player gets a half second at the end of the countdown to make a selection by choosing rock, paper, or scissors.
Image from book
Figure 9.4: As soon as both the computer and the player have made their choices, the game displays graphics showing each move and determines who won.
Image from book
Figure 9.5: The Rock, Paper and Scissors game also keeps a running tally of the number of wins, losses, and ties.


OBJECT-ORIENTED PROGRAMMING

Object-Oriented Programming (OOP) is a central feature of Visual C++. At its core is the concept of grouping related code and data. This philosophy allows for the creation and use of self-contained objects that are highly organized, easy to understand, and easy to use.

Objects have several valuable features. They can store data and provide mechanisms for changing, retrieving, or performing operations on data after it is stored. Objects also can validate the information they receive, ensuring that a program works only with data that is valid. These features allow an application to be made of parts that are robust and reliable.

Although you might not have been aware that you were doing so, you have already worked extensively with objects. Consider the many controls that you have employed throughout this book. Whenever you have added one to your program, you have been instructing your program to make use of an object. The TextBox control, for instance, is an object that, when added to your program, gives it the ability to display and accept data in the form of text and numbers.

In Visual C++, objects can have methods, properties, and events. Methods allow the object to run code that might manipulate data or provide other functionality. Properties store data. Events allow the object to respond to specific events generated by Windows or your application. A button's Enabled property is an example of an object property, whereas the Show() method of MessageBox is an example of a method. You can see an example of an event in the code that results when you double-click a form or control.

One of the most powerful aspects of OOP is that you don't need to understand how an object works internally to be able to use it within your program. Rather, you just need to employ an object's interface—those properties, methods, and events that it makes available for use. As an example, consider the TextBox control again. You only have access to the properties, methods, and events that the .NET programmers at Microsoft have provided. This allows you to use the control without worrying about how it is put together. Internal details such as how the control's program code manages fonts, limits text to the extents of the TextBox, or controls the placement of each letter are details that you can safely ignore.


OOP TERMS

Objects are created from classes. The class acts as a blueprint for the object, defining how it will behave within your program. You can use a class to create many objects, just as you can use a blueprint of a car or building to create many cars or buildings. It is important, however, to understand that just as a blueprint is not what is created from it, a class is not the same as an object. Rather, in OOP terminology, objects are instances of classes that are created at runtime.

Hint

A class is a user-created data type that can instantiate objects.

Visual C++ provides access to a large collection of classes. For example, the code that drives the behavior of a Windows Forms application is largely based on the Form class, which is located in the System::Windows::Forms namespace. Examples of other classes include System::Windows::Forms::Button, which defines the Button class and System::Windows::Forms::MessageBox, where the MessageBox class is defined.

Hint

A namespace is a kind of container that can store classes, program functions, and variables. The .NET Framework provides access to multiple namespaces, which it makes available in its class library.

Visual C++ also allows you to create your own custom classes, which is the focus of the bulk of this chapter. However, before you can start doing so, you need to know some basic terminology. The core concepts of OOP are known as abstraction, encapsulation, polymorphism, and inheritance.

Abstraction

In general terms, an abstraction is essentially a representation of something concrete, such as a real-world object like a car or house. Abstractions summarize the important details of what they represent so that you can understand and exploit similarities without getting bogged down in details. When you use the word car or house, for instance, you naturally understand that cars and houses have many different details, such as shape, size, and color, but that car or house represents the essentials of something.

In OOP terms, abstraction is used to model in program code certain essential behavior and information. Abstraction takes the form of the logical representation of that behavior and information as a class. This includes the specification of the base, or core functionality of the class, in the form of its methods and events. It also includes its most essential data, in the form of its properties.

Encapsulation

Encapsulation is the process whereby you decide how a class's data and functions will be grouped together and what elements of the class will be hidden or revealed. You make available to the programmer who will use your class only the information and data necessary for controlling the object he will use the class to create. You do this by designing an interface for the class that makes only certain properties, methods, and events usable and visible to the class's user.

When you encapsulate the internals of a class, you relieve the class's user of having to keep track of how the class works. The programmer doesn't have to worry about how code within the class functions or what data it relies on. This simplicity allows a programmer to focus on using the class where needed. It also cuts down on the overall task of managing complexity within their code.

Polymorphism

Polymorphism is the ability to create something in different forms. It is achieved in Visual C++ through a programming technique known as overloading. Using overloading, a programmer might develop multiple versions of a function, each with the same name, all designed to meet different needs. The varieties of the method or function would be distinct from one another because each would accept different combinations of arguments.

Hint

Overloading is the process of defining the same function multiple times, each with a different argument list.

A good example of polymorphism and overloading in action is the MessageBox class's Show method. This method supports 21 different formats, each useful in specific instances. Each of these overloads allows the Show() method to accept various combinations of arguments and data types.

Trick

To view the many available combinations of arguments and data that you can pass to the MessageBox::Show method, open the Visual C++ Code Editor and type MessageBox::Show. IntelliSense activates and displays a pop-up window showing the various forms of this method. Click on the up and down arrows in the upper-left corner of the pop-up window to explore the available options.

Inheritance

Inheritance is the process whereby one class is derived from another. This allows a programmer to base one class on another, in effect using the features of the base class without having to do extra work. You can see an example of inheritance each time you create a Windows Forms application. The application you create is derived from System::Windows::Forms::Form Each time you build an application, you effectively extend the original work done by the .NET team in new and different directions.


CLASSES AND OBJECTS

As previously discussed, objects are instances of classes that are instantiated at runtime. A class, in turn, is a template that defines all the properties, methods, and events required to create an object. Using abstraction, programmers develop the overall design of a class. Using encapsulation, they develop the interface for the class and hide the nonessential details. Programmers can also use polymorphism, via overloading, to any given method of the class to accept different arguments. Finally, they can use inheritance to derive the features and functionality of one class from another.

To use a class, you must instantiate it. This creates an instance of the class that the application can use. The process for doing so differs, depending on what type of class you are using. If, for example, you want to instantiate a Button or Checkbox class (control), you can drag it to your form. Visual C++ takes care of the necessary details automatically. On the other hand, if you want to create a control while your program is running or instantiate your own custom class, you must do so in code.

Creating a New Class

You can create a new class in various ways. First, any time you create a new Visual C++ application, a new class is created for you based on the System::Windows::Forms::Form class. You can control the name of the class by specifying the name of the form. (By default, it is Form1.)

You can also embed a class directly within the form code of your application. There are several types of classes you can use when doing so. The following are some of the most useful ones:

  • value. Provides the most efficient way to represent an object that is mainly composed of data

  • enum. Allows for the specification of an object with a specific series of values

  • ref. Provides the most flexibility when adding a class to your application

Understanding the Value Classes

The value class provides a means to create simple classes.

One of the best uses of the value class is in the creation of custom data types. These types allow you to group related items within a single object. You could use the value class, for instance, to create objects that represent points on a map. The format for defining such a class might look like the following example:

value class cLocation {
public:
  Int32 Longitude, Latitude;
};

The value class is intended to be used like .NET'S fundamental data types, such as Int32 or Double. You can create a custom type. For example, you can declare objects representing your current location:

cLocation myCurrentLocation;
cLocation myHomeLocation, myWorkLocation;

You can also use such an object just as you would any other data type:

myCurrentLocation.Longitude = 0;
myCurrentLocation.Latitude = 0;

Understanding Enum Classes

The enum class allows you to enumerate a series of related constant values. This feature can be extremely useful if your application needs to represent important states or events with an easy-to-read label. Enumerated classes are composed of a class name and store labels that represent any constant, unchanging value you want to represent. For example, you can use the code in the following listing to represent different types of playing cards:

enum class Suit {
  Hearts, Clubs, Diamonds, Spades
};

Enumerated types automatically number themselves sequentially. You can use them without concern for what their underlying values are. But if your application needs enumerated values to map to specific values, you can specify exact values for each element:

enum class ErrorCode {
  LogError = 1001, SystemError = 1005,
};

To use an enumerated type, you declare a variable using the name of the enum class as the type:

Suit playerCardSuit;
ErrorCode criticalError;

You can then use the enumerated object you have created in your program just as you might an Int16 or String data type:

playerCardSuit = Suit::Hearts;
criticalError = ErrorCode::SystemError;

By default, the enum class is based on the Int32 data type. You can change this, however. If you need enumerated types that derive from another fundamental type, you must specify the type after the class name when defining the class:

enum class Suit : Int16
{
      Hearts, Clubs, Diamonds, Spades
};

Enumerated classes are useful because they save you from having to represent an important, distinct program state with just a number or variable. If you needed to compare a value to an error code, for instance, not only would it be risky to use a number (what if it changed?), but it would make your code harder to read. Enumerated classes allow you to represent important but unchanging information in a way that is readable and consistent throughout your program.

Understanding Ref Classes

The ref class offers the most flexible and powerful features. In fact, you have used a ref class each time you've built a Windows Forms application. Open any project you have created so far (or simply create a new one), and look for the following code near the top of the Form1.h file. You see a line similar to this:

public ref class Form1 : public System::Windows::Forms::Form

This line appears complex, but essentially it indicates that Form1 is a ref class. The colon after the Form1 indicates that the form inherits from System::Windows::Forms::Form. To better understand the ref class, let's work with an example. Create a new project and double-click on the form so that Visual C++ generates the Load event function. Add the following code:

/// <summary>
/// Required designer variable.
/// </summary>
ref class Greeting
{
private:
  String^ message;

public:
  Greeting()
  {
    message = gcnew String("Greetings!"):
  }
  Void ShowMessage( Void )
  {
    MessageBox::Show( message );
  }
};

Next, add the following code to the form's Load event function:

private: System::Void Form1_Load(System::Object^ sender,\
System::EventArgs^ e) {
    Greeting startUpGreeting;
    startUpGreeting.ShowMessage();
  }

Press F5 to run the application. When the Load event handler starts, a Greeting object (called startUpGreeting) is instantiated. Immediately below this line of code, the startUpGreeting's ShowMessage() method is activated. This causes a message box containing a friendlymessage to display. Although the message box isn't fancy, it illustrates how you can use a ref class within your own applications.

Just as you define custom functions for your application, you can create custom methods for your ref class. In fact, because you're writing code within the Form1 ref class already, the rules are the same.

If you consider how detailed your programs have already become at this point, it should be clear that you can make the ref classes within your application just as complex. Classes can be composed of other classes, and large applications can be built on hundreds of such classes. For this reason, as your programs grow more complex, you will need to start separating classes into their own files. This is the better way to add classes to your code, but it does not become necessary until you begin building full-fledged applications. Then it becomes an organizational and readability issue.

Trap

Be sure to follow your class definitions with a semicolon to avoid compiler errors.


BACK TO THE ROCK, PAPER AND SCISSORS GAME

It's time to turn your attention back to the development of this chapter's game project, the Rock, Paper and Scissors game. You will create this game by following the five basic development steps that you've used to create all the previous chapter projects.

Designing the Game

The Rock, Paper and Scissors game is played on a single window and is made up of one form and the 22 controls listed in Table 9.1.

Table 9.1: Form Controls for the Rock, Paper and Scissors Game
Control Type | Control Name | Description
PictureBox | pcbLeft | Displays an image showing the computer's selection
PictureBox | pcbRight | Displays an image showing the player's selection
Label | lblComputer | Identifies the PictureBox control where the computer's selection is displayed
Label | lblPlayer | Identifies the PictureBox control where the player's selection is displayed
Label | lblCountDown | Identifies the function of the ProgressBar control
ProgressBar | pgbCountDown | Displays a graphical 1.5-second countdown
Button | btnPlay | Starts gameplay by enabling the Timer control
Button | btnRock | Allows the player to select Rock
Button | btnPaper | Allows the player to select Paper
Button | btnScissors | Allows the player to select Scissors
GroupBox | grpStatus | Contains Label and TextBox controls that identify and display game statistics
Label | lblWins | Identifies the TextBox control that displays the number of games won
Label | lblLosses | Identifies the TextBox control that displays the number of games lost
Label | lblTies | Identifies the TextBox control that displays the number of games tied
TextBox | txtWins | Displays the number of games the player has won
TextBox | txtLosses | Displays the number of games the player has lost
TextBox | txtTies | Displays the number of games the player has tied
Label | lblResults | Identifies the TextBox control where the results of each game are displayed
TextBox | lblOutput | Displays a test string detailing the results of each game
ToolTip | tltControl | Allows you to assign ToolTips to individual controls
Timer | tmrControl | Controls the 1.5-second countdown sequence and the half-second windows in which the player gets to make a selection
ImageList | imlHands | Stores the bitmap images that are displayed in the PictureBox controls during gameplay

Step 1: Creating a New Visual C++ Project

The first step in creating the Rock, Paper and Scissors game is to open Visual C++ and create a new project, as outlined here:

  1. If you have not already done so, start Visual C++ 2005 Express and then click on File, New Project. The New Project dialog box appears.

  2. Select Windows Application template.

  3. Type Rock Paper and Scissors as the name of your new application in the Name field located at the bottom of the New Project window. You need to type the name of the project without a comma, or Visual C++ might not recognize some of the project's file names during compiling.

  4. Click on OK to close the New Project dialog box.

Visual C++ now creates a new project and displays a new form upon which you will design the game's user interface.

Step 2: Creating the User Interface

Let's begin the development of the Rock, Paper and Scissors game by laying out and resizing all the controls that you need to set up the game's user interface. As you go about configuring the game's user interface, refer to Figure 9.6 so that you know where to place each control and when and how to resize it.

  1. Begin by clicking on the form and setting its Size property to 490, 460.

  2. Add two PictureBox controls, one in the upper-left corner of the form and the other in the upper-right corner. Set the Size property for both PictureBox controls to 150, 150.

  3. Next, add a pair of Label controls to the form. Place the first one under the first PictureBox control and the second one under the second PictureBox control.

  4. Add another Label control about an inch below the left side of the first PictureBox control, and then add a ProgressBar control beneath it, setting its Size property to 250, 40.

  5. Add four Button controls to the form.

  6. Add a GroupBox control to the lower-left corner of the form and set its Size property to 190, 100.

  7. Add three Label controls and three TextBox controls inside the GroupBox control.

  8. Add another Label control just to the right of the GroupBox control and then add a TextBox control beneath it. Set the Multiline property for the TextBox control to true and the Size property to 260, 80.

  9. Finally, add ToolTip, Timer, and ImageList controls.

Image from book
Figure 9.6: Completing the interface design for the Rock, Paper and Scissors game.

At this point, you have added all the controls you will need to develop the Rock, Paper and Scissors game. In addition, you have completed the overall layout of the game's user interface and are ready to start making property modifications to the game's form and controls.

Step 3: Customizing Form and Control Properties

Okay, let's get to work on making the required changes to the game's form and control properties, as listed in Table 9.2.

Table 9.2: Property Changes for Form1
Property | Value
BackColor | LightYellow
FormBorderStyle | Fixed3D
MaximizeBox | False
MinimizeBox | False
Size | 490, 460
StartPosition | CenterScreen
Text | Rock, Paper and Scissors

Make the property changes shown in Table 9.3 to the PictureBox controls.

Table 9.3: Property Changes for PictureBox Controls
Control | Property | Value
PictureBox1 | Name | pcbleft
 | BorderStyle | Fixed3D
 | Size | 150, 150
 | SizeMode | StretchImage
PictureBox2 | Name | pcbRight
 | BorderStyle | Fixed3D
 | Size | 150, 150
 | SizeMode | StretchImage

Make the property changes shown in Table 9.4 to the Label controls.

Table 9.4: Property Changes for Label Controls
Control | Property | Value
Label 1 | Name | lblComputer
 | Font.Bold | True
 | Text | Computer's Pick
Label 2 | Name | lblPlayer
 | Font.Bold | True
 | Text | Player's Pick
Label 3 | Name | lblCountDown
 | Font.Bold | True
 | Text | Countdown
Label 4 | Name | lblWins
 | Font.Bold | True
 | Text | Wins:
Label 5 | Name | lblLosses
 | Font.Bold | True
 | Text | Losses:
Label 6 | Name | lblTies
 | Font.Bold | True
 | Text | Ties:
Label 7 | Name | lblResults
 | Font.Bold | True
 | Text | Game Results

Next, change the name of the ProgressBar control to pgbCountDown and set its Size property to 250, 40. Then make the property changes shown in Table 9.5 to the four Button controls.

Table 9.5: Property Changes for Button Controls
Control | Property | Value
Button1 | Name | btnPlay
 | BackColor | ButtonFace
 | Font.Bold | True
 | Text | Play
 | ToolTip | Begin 1.5 second countdown
Button2 | Name | btnRock
 | BackColor | ButtonFace
 | Enabled | False
 | Font.Bold | True
 | Text | Rock
 | ToolTip | Select Rock
Button3 | Name | btnPaper
 | BackColor | ButtonFace
 | Enabled | False
 | Font.Bold | True
 | Text | Paper
 | ToolTip | Select Paper
Button4 | Name | btnScissors
 | BackColor | ButtonFace
 | Enabled | False
 | Font.Bold | True
 | Text | Scissors
 | ToolTip | Select Scissors
Trick

The ProgressBar control displays the status of a process. After you've added this control to a form, you can update its appearance by settings its Value property to 0 to represent a process that has not started. You can then set the Value property anywhere between 0 and 100 to represent the current status of a process. Finally, you can set the Value property to 100 to represent a process that has completed.

Make the property changes shown in Table 9.6 to the four TextBox controls.

Table 9.6: Property Changes for TextBox Controls
Control | Property | Value
TextBox 1 | Name | txtWins
 | Font.Bold | True
 | ReadOnly | True
 | TextAlign | Right
TextBox2 | Name | txtLosses
 | Font.Bold | True
 | ReadOnly | True
 | TextAlign | Right
TextBox3 | Name | txtTies
 | Font.Bold | True
 | ReadOnly | True
 | TextAlign | Right
TextBox4 | Name | txtoutput
 | Font.Bold | True
 | ReadOnly | True
 | Size | 260, 80

Next, change the name of the ToolTip control to tltControl. Then make the property changes shown in Table 9.7 to the Timer control.

Table 9.7: Property Changes for Timer Control
Control | Property | Value
Timer1 | Name | tmrControl
 | Interval | 500

Finally, change the name of the Name property for the ImageList control to imlHands and add the following bitmap images to its Images property (col1ection) as shown in Table 9.8. You'll find copies of the bitmap images required to complete this project, along with the source code, on this book's companion Web site.

Table 9.8: Bitmap Images to Add to the ImageList Control's Images Collection
Property | File | Index No.
Name | Left-Paper.bmp | 0
Name | Right-Paper.bmp | 1
Name | Left-Rock.bmp | 2
Name | Right-Rock.bmp | 3
Name | Left-Scissors.bmp | 4
Name | Right-Scissors.bmp | 5
Name | Blank.bmp | 6

That's it. The user interface for the Rock, Paper and Scissors game is now complete. Let's move on to the next step and begin adding program code.

Step 4: Adding a Little Programming Logic

To put together the code for the Rock, Paper and Scissors game, start by double-clicking on the game's form. This activates the Code Editor. In response, Visual C++ automatically defines a new class for you called frmMain (or whatever name you have assigned to Form1). This derived class inherits properties, methods, and events that are associated with the System.Windows.Forms base class.

Your class requires the following member variables:

private:
  /// <summary>
  /// Required designer variable.
  /// </summary>
  Int32 intCounter;
  Int32 intWins;
  Int32 intLosses;

  Int32 intTies;
  enum class GameChoice : Int16 {
    CHOICEROCK, CHOICEPAPER, CHOICESCISSORS
  };
  //Handle for random number generator
  Random^ randNumGen;

The first variable, intCounter, tracks the timer and implements the 1.5-second countdown. The next three variables—intWIns, intLosses, and intTies—keep track of whether the computer or the player is winning. Notice also the enum class GameChoice, which defines three possible game choices. GameChoice derives from the Int16 class and exists only to create meaningful state information for some functions to operate on. This section also includes a handle to a random number generator, randNumGen, which gives the computer the illusion of making a choice.

The Rock, Paper and Scissors game needs to execute a few tasks when it first loads. It must initialize its member variables. Then it needs to load a blank bitmap for each of the two PictureBox controls. Following that, the game's text boxes are initialized, and the random number generator is seeded with the current time:

private: System::Void Form1_Load(System::Object^  sender, \
System::EventArgs^  e) {
        intCounter = 0;
        intWins = 0;
        intLosses = 0;
        intTies = 0;
        //Load blank bitmap in picture boxes
        pcbLeft->Image = imlHands->Images[6];
        pcbRight->Image = imlHands->Images[6];
        //Set game statistics
        txtWins->Text = intWins.ToString();
        txtLosses->Text = intLosses.ToString();
        txtTies->Text = intTies.ToString();
        //Seed random number generator with current time
        DateTime moment = DateTime::Now;
        randNumGen = gcnew Random( moment.Millisecond );
 }

The game starts when the player clicks the Play button. This begins the game's 1.5-second countdown by setting the Value property of the ProgressBar control to 0 and enabling the Timer control. Any leftover text in the text box is cleared, and the two picture boxes are again loaded with black images to clear out the pictures from the previous game:

private: System::Void btnPlay_Click(System::Object^  sender, \
System::EventArgs^  e) {
        //Set ProgressBar to show 0 percent progress
        pgbCountdown->value = 0;
        //Start countdown by enabling the Timer
        tmrControl->Enabled = true;
        //Clear out any test stored in the text box
        txtOutput->Text = "";
        //Load blank bitmap in picture boxes
        pcbLeft->Image = imlHands->Images[6];
        pcbRight->Image = imlHands->Images[6];
}

The Timer control handles timing for the game. Because its Interval property is set to 500, the code in this function executes every 0.5 seconds. Each time it does, the counter is incremented by 1. When the counter exceeds 4, the game is over.

The Timer control also updates the progress bar each time it is called.

The tmrControl_Tick function, shown next, uses a switch block to control what happens at certain intervals. When the first half-second has passed, the value of intCounter is 1, and the ProgressBar control's Value property is set to 33 to give the player a visual indicator that a third of the countdown has elapsed. After the passage of a full second, the second case statement is triggered, and the ProgressBar control's Value property is updated to show that two-thirds of the countdown has elapsed:

private: System::Void tmrControl_Tick(System::Object^ \
sender, System::EventArgs^  e) {
        intCounter += 1;  //Increment counter

        //Set progress bar based on counter
        switch( intCounter )
        {
          case 1 : //At .5 seconds
            //Set progress bar to show 33%
            pgbCountdown->value = 33;
            break;
          case 2 : //At 1 second
            //Set progress bar to show 66%
            pgbCountdown->Value = 66;
            break;

          case 3 : //At 1.5 seconds
            //Set progress bar to show 100%
            pgbCountdown->Value = 100;
            //Enable the 3 game choice buttons
            btnRock->Enabled = true;
            btnPaper->Enabled = true;
            btnScissors->Enabled = true;
            break;
          case 4 : //At 2 seconds
            intCounter = 0;  //Reset counter
            //Disable the Timer control
            tmrControl->Enabled = false;
            //Disable the 3 game choice buttons
            btnRock->Enabled = false;
            btnPaper->Enabled = false;
            btnScissors->Enabled = false;
            //Set ProgressBar to show 0%
            pgbCountdown->Value = 0;
            break;
        }
}

At 1.5 seconds, the ProgressBar control's Value property is updated to indicate that the countdown is complete. When this occurs, the buttons representing the rock, paper, and scissors options are enabled, and the player has a half-second to decide which button to click. But should the half-second interval elapse, execution reaches the final case statement. This causes the game's buttons to be disabled, the progress bar to be reset, and the timer to be disabled.

The next listing shows the code for the Rock Button control. When clicked, the right picture box, pcbRight, is loaded with the appropriate image. An instance of the GameChoice enum class is created and initialized with the player's choice. Notice that instead of a number, which might be hard to understand, or a string, which would be wasteful, the use of an enum makes the code clearer. It is easy to understand that the player's choice is rock because of how the assignment to GameChoice::CHOICEROCK reads.

After the player's choice is instantiated, another GameChoice object is created to represent the computer's choice. This is assigned the results of the GetComputerChoice function. When the computer's choice is known, both are used as parameters in the CheckGameResults function:

private: System::Void btnRock_Click(System::Object^  sender,\
System::EventArgs^  e) {
          //Load rock picture into right picture box
          pcbRight->Image = imlHands->Images[3];
          //Set the game choices for both players
          GameChoice gmcPlayerPick = GameChoice::CHOICEROCK;
          //Get computer choice
          GameChoice gmcComputerPick;
          gmcComputerPick = GetComputerChoice();
          //Run function that determines who has won the game
          CheckGameResults(gmcPlayerPick, gmcComputerPick);
}

The click event function for the Button control representing the paper option is shown next. The code is nearly identical, except all references reflect the player's choice of paper as his move instead of rock:

private: System::Void btnPaper_Click(System::Object^  sender,\
System::EventArgs^  e) {
          //Load paper picture into right picture box
          pcbRight->Image = imlHands->Images[1];
          //Set the game choices for both players
          GameChoice gmcPlayerPick = GameChoice::CHOICEPAPER;
          //Get computer choice
          GameChoice gmcComputerPick;
          gmcComputerPick = GetComputerChoice();
          //Run function that determines who has won the game
          CheckGameResults(gmcPlayerPick, gmcComputerPick);
   }

The code for the Button control representing the scissors choice is shown next. Again, it varies only slightly from the two previous functions:

private: System::Void btnScissors_Click(System::Object^  sender,\
System::EventArgs^  e) {
          //Load scissors picture into right picture box
          pcbRight->Image = imlHands->Images[5];
          //Set the game choices for both players
          GameChoice gmcPlayerPick = GameChoice::CHOICESCISSORS;
          //Get computer choice

          GameChoice gmcComputerPick;
          gmcComputerPick = GetComputerChoice();
          //Run function that determines who has won the game
          CheckGameResults(gmcPlayerPick, gmcComputerPick);
}

The GetComputerTurn() function, shown next, is a custom-developed function that you must type from scratch. Within the function, the randNumGen object serves as an argument to a switch statement. The Next() method of randNumGen generates a number between (but not including) the upper and lower bounds. If the number falls between 1 and 2, the value that the method returns matches one of the two case labels. Within each label, the appropriate graphic is set for the computer's choice, and the correct enumerated value is returned. If neither is met, the function assumes that the only logical choice is paper and performs the appropriate steps:

private: GameChoice GetComputerChoice(System::Void) {
          //Get the computer's random choice
          switch( randNumGen->Next(0, 4) )
          {
            case 1 : //Computer chooses rock
              //Load picture of rock into left box
              pcbLeft->Image = imlHands->Images[2];
              //Return computer's choice
              return GameChoice::CHOICEROCK;
              break;
            case 2 : //Computer chooses scissors
              //Load picture of scissors into left box
              pcbLeft->Image = imlHands->Images[4];
              //Return computer's choice
              return GameChoice::CHOICESCISSORS;
              break;
          }
          //Only possible remaining choice is paper
          //Load picture of paper into left box
          pcbLeft->Image = imlHands->Images[0];
          //Return computer's choice
          return GameChoice::CHOICEPAPER;
  }

The logic within the Check Game Results () function is responsible for arbitrating between the computer and player moves. Each player's choice is used as the basis of comparison and causes execution to seek the nearest matching case label. Within each case block, three if statements determine how the player's choice stacks up against the computer's choice. The result is assigned to the Text property of txtOutput, the appropriate variable tracking the player's score is updated, and the results are translated to a string so that they can be stored in the correct corresponding text box:

private: System::Void CheckGameResults(GameChoice gmcPlayer,\
                                    GameChoice gmcComputer ) {
          //Check winner by comparing moves
          switch( gmcPlayer )
          {
            case GameChoice::CHOICEROCK :
              if( gmcComputer == GameChoice::CHOICEROCK )
              {
                //Display results
                txtOutput->Text = \
                "Rock versus Rock is a Tie!";
                intTies++;
                txtTies->Text = intTies.ToString();
              }
              if( gmcComputer == GameChoice::CHOICEPAPER )
              {
                //Display results
                txtOutput->Text = \
                "Paper covers Rock. You Lose!";
                intLosses++;
                txtLosses->Text = intLosses.ToString();
              }
              if( gmcComputer == GameChoice::CHOICESCISSORS )
              {
                //Display results
                txtOutput->Text = \
                "Rock crushes Scissors. You Win!";
                intWins++;
                txtWins->Text = intLosses.ToString();
              }
              break;

            case GameChoice::CHOICEPAPER :
              if( gmcComputer == GameChoice::CHOICEROCK )
              {
                //Display results
                txtOutput->Text = \
                "Paper covers Rock. You Win!";
                intWins++;
                txtWins->Text = intWins.ToString();
              }
              if( gmcComputer == GameChoice::CHOICEPAPER )
              {
                //Display results
                txtOutput->Text = \
                "Paper versus Paper is a Tie!";
                intTies++;
                txtTies->Text = intTies.ToString();
              }
              if( gmcComputer == GameChoice::CHOICESCISSORS )
              {
                //Display results
                txtOutput->Text = \
                "Scissors cuts Paper. You Lose!";
                intLosses++;
                txtLosses->Text = intLosses.ToString();
              }
              break;
            case GameChoice::CHOICESCISSORS :
              if( gmcComputer == GameChoice::CHOICEROCK )
              {
                //Display results
                txtOutput->Text = \
                "Rock breaks Scissors. You Lose!";
                intLosses++;
                txtLosses->Text = intLosses.ToString();
              }
              if( gmcComputer == GameChoice::CHOICEPAPER )
              {

                //Display results
                txtOutput->Text = \
                "Scissors cuts Paper. You Win!";
                intWins++;
                txtWins->Text = intWins.ToString();
              }
              if( gmcComputer == GameChoice::CHOICESCISSORS )
              {
                //Display results
                txtOutput->Text = \
                "Scissors versus Scissors is a Tie!";
                intTies++;
                txtTies->Text = intTies.ToString();
              }
              break;
          }
   }

Step 5: Testing the Execution of the Rock, Paper and Scissors Game

The Rock, Paper and Scissors game is ready to run. Start the game by pressing F5 and test the code to make certain it works as it should. If you run into problems, be sure to double-check your typing.


SUMMARY

In this chapter, you learned essential OOP concepts and how they relate to Visual C++ and .NET. You learned about classes and namespaces and how to create your own custom classes. This chapter also covered how to instantiate new objects using your custom classes. The custom objects that you created included their own properties and methods. You also learned how to overload object methods and how to provide controlled access to data stored within your objects. In addition to this, you created the Rock, Paper and Scissors game.

Before you move on to Chapter 10, "Integrating Graphics and Audio," try making improvements to the Rock, Paper and Scissors game by implementing the following challenges.


CHALLENGES

  1. Modify the Rock, Paper and Scissors game by adding another button to the form so that the player can receive instructions if needed. Display the help text in the txtOutput TextBox control.

  2. As it is currently written, the Rock, Paper and Scissors game does not clearly distinguish when the player fails to make a move within the allotted time (a half-second). Modify the game so that if the player fails to make a move in the allotted time, the game displays a message encouraging the player to be faster.

  3. The 1.5-second countdown is meant to simulate the amount of time that it typically takes for two players to sync up when manually playing a game of Rock, Paper and Scissors. Although the computer needs almost no time to make a decision, the time delay is key to giving the game a realistic feel. Experiment with different time delays and see if you can adjust them to make the game even more lifelike.


Chapter 10: Integrating Graphics and Audio

OVERVIEW

This chapter introduces you to various graphics and audio capabilities provided by Visual C++ 2005 Express. You learn how to work with a number of new classes associated with the System::Drawing::Graphics namespace. Using objects created from classes stored in this namespace, you find out how to draw custom graphics in your applications. You also learn how to use classes to play sounds in your applications. Finally, you discover how to create this chapter's game project, the VC++ Doodle game.

In this chapter, you learn the following:

  • How to work with the Graphics, Pen, and Brush classes

  • How to draw both graphics and text

  • How to work with both the SoundP1ayer and SystemSound classes to add sounds to your applications


PROJECT PREVIEW: THE VC++ DOODLE GAME

In this chapter, you gain knowledge of Visual C++ graphics capabilities by developing the VC++ Doodle game. VC++ Doodle is a drawing program that allows players to create freehand images and draw a number of shapes, such as circles, lines, and rectangles. Figures 10.1 to 10.4 show examples from the VC++ Doodle game, demonstrating its overall program flow.

Image from book
Figure 10.1: The user interface for the VC++ Doodle game consists of a control panel and a drawing area.
Image from book
Figure 10.2: VC++ Doodle gives the player a range of colors to choose from.
Image from book
Figure 10.3: The game assists the player in drawing an assortment of predefined shapes.
Image from book
Figure 10.4: The player also has the option of making a freehand drawing using any combination of colors.

After you have completed the VC++ Doodle game, you will have acquired a basic understanding of Visual C++'s built-in graphics drawing capabilities. This will serve as a good foundation to move on to more advanced graphics topics in the future.


INTEGRATING GRAPHICS INTO YOUR VISUAL C++ APPLICATIONS

Visual C++ 2005 Express provides graphic support based on GDI+ (Graphics Device Interface), a graphics library. GDI+ is implemented in .NET through properties and methods made available by classes organized within the System::Drawing namespace. It offers support for managing and displaying graphics images, drawing vector graphics, and drawing text.

Hint

GDI+ (Graphics Device Interface) is a graphics system that allows applications to create graphics and draw text.

GDI+ draws graphics using a coordinate system. Coordinates are measured using pixels. A graphic is rendered by specifying its starting position relative to coordinates (0,0) and other required coordinates to render a particular shape based on their distance from (0,0) on the x and y axes, as depicted in Figure 10.5.

Image from book
Figure 10.5: A graphical depiction of the coordinate system employed by GDI+ when drawing graphics.
Hint

A pixel (picture element) is a unit of measure. The computer's display is measured in terms of the number of pixels that it displays (such as 800×600, 1024×786, and so on).

Working with Graphics Images

As you have seen in previous chapter games, you can configure the PictureBox control's Image property to display a graphics image. You also learned through the creation of the Dice Poker game, shown in Figure 10.6, that you can preload graphics images into an ImageList control and then display these images in any control that is capable of displaying them.

Image from book
Figure 10.6: An example of an application that uses the PictureBox and ImageList controls to work with graphics.

GDI+ support for images also includes the ability to manipulate them in many different ways, including stretching, centering, and zooming.

Drawing Vector Graphics

Along with the ability to render an image, GDI+ gives Visual C++ the capability of drawing using coordinates passed to various methods. Visual C++ allows you to draw on various surfaces, including Button and Form backgrounds. You can execute methods that can draw such elements as lines, ellipses, rectangles, polygons, arcs, and curves. For example, if you want to draw an ellipse, just call the correct method and give it coordinates of where to draw.

Working with the Graphics Class

To draw graphics, you need a surface to draw on, such as a Form or Button control. But before you can begin drawing, you must create a Graphics object for the drawing surface you want to use. The first step in doing so is to create a handle to the instance of the Graphics class within your application, as demonstrated in the following example:

System::Drawing::Graphics ^FormGraphic;

After you have established this handle, you can use it to obtain an instance of the surface that you want to draw on by calling the CreateObjects() method of the object that the surface belongs to. This next example demonstrates the concept:

private: System::Void Form1_Load(System::Object^ sender,\
System::EventArgs^ e)  {
      FormGraphic = this->CreateGraphics();
}

In this example, the FormGraphic object has been set to the drawing surface of Form1 (represented by this because it is being done within the Form1 class). After the handle has been defined and the drawing surface has been established, you can begin drawing graphics within your application by calling on any of the Graphics class's methods, as listed in Table 10.1.

Table 10.1: Drawing Methods Associated with the System::Drawing::Graphics Class
Method | Description
Clear | Clears the drawing surface
DrawArc | Draws an arc
DrawBezier | Draws a Bezier curve
DrawBeziers | Draws a collection of Bezier curves
DrawClosedCurve | Draws a closed curve
DrawCurve | Draws a curve
DrawEllipse | Draws an ellipse
DrawIcon | Draws an icon
DrawIconUnstretched | Draws the image without scaling it
DrawImage | Draws an Image
DrawImageUnscaled | Draws an image without scaling its size
DrawLine | Draws a line
DrawLines | Draws a collection of line segments
DrawPath | Draws a graphics path
DrawPie | Draws a pie shape
DrawPolygon | Draws a polygon
DrawRectangle | Draws a rectangle
DrawRectangles | Draws a collection of rectangles
DrawString | Draws a text string
FillClosedCurve | Draws a filled curve
FillEllipse | Draws a filled ellipse
FillPath | Draws a filled path
FillPie | Draws a filled pie
FillPolygon | Draws a filled polygon
FillRectangle | Draws a filled rectangle
FillRectangles | Draws a collection of filled rectangles
FillRegion | Draws a filled region

Working with the Pen Class

One way in which to draw a graphic using the Graphics class is with the Pen class. This is done as follows:

FormGraphic->DrawLine( pen, ptStart, ptEnd );

In this example, pen represents a Pen object, and ptStart and ptEnd represent Point objects that determine the starting and ending points for a line. You can find the Pen class in the System::Drawing namespace. It allows you to specify how you want a given image to be drawn. One Pen property is Color, which allows you to specify the color of the line to be drawn. Another Pen property is Brush, which retrieves or sets a Brush object for the Pen. Using methods associated with the Brush class, you can draw filled-in shapes.

To define a color when drawing shapes with the Pen class or filling in shapes with the Brush class, you can specify any of a large collection of predefined colors that are provided by these classes. Table 10.2 shows a complete list of the colors provided by these two classes.

Image from book
Table 10.2: Predefined Colors for Pens and Brushes
AliceBlue | DarkTurquoise | LightSkyBtue | Pink
AntiqueWhite | DarkViolet | LightSlateGray | Plum
Aqua | DeepPink | LightSteelBlue | PowderBlue
Aquamarine | DeepSkyBlue | LightYellow | Purple
Azure | DimGray | Lime | Red
Beige | DodgerBlue | LimeGreen | RosyBrown
Bisque | Firebrick | Linen | RoyalBlue
Black | FloralWhite | Magenta | SaddleBrown
BlanchedAlmond | ForestGreen | Maroon | Salmon
Blue | Fuchsia | MediumAquamarine | SandyBrown
BlueViolet | Gainsboro | MediumOrchld | SeaGreen
Brown | GhostWhite | MediumPurple | SeaShell
BurlyWood | Gold | MediumSeaGreen | Sienna
CadetBlue | Goldenrod | MediumSlateBlue | Silver
Chartreuse | Gray | MediumSpringGreen | SkyBlue
Chocolate | Green | MediumTurquoise | SlateBlue
Coral | GreenYellow | MediumVioletRed | SlateGray
CornflowerBlue | Honeydew | MidnightBlue | Snow
Cornsilk | HotPink | MintCream | SpringGreen
Crimson | IndianRed | MistyRose | SteelBlue
Cyan | Indigo | Moccasin | Tan
DarkBlue | Ivory | NavajoWhite | Teal
DarkCyan | Khaki | Navy | Thistle
DarkGoldenrod | Lavender | OldLace | Tomato
DarkGray | LavenderBlush | Olive | Transparent
DarkGreen | LawnGreen | OliveDrab | Turquoise
DarkKhaki | LemonChiffon | Orange | Violet
DarkMagenta | LightBlue | OrangeRed | Wheat
DarkOliveGreen | LightCoral | Orchid | White
DarkOrange | LightCyan | PaleGoldenrod | WhiteSmoke
DarkOrchid | LightGoldenrodYellow | PaleGreen | Yellow
DarkRed | LightGray | PaleTurquoise | YellowGreen
DarkSalmon | LightGreen | PaleVioletRed |
DarkSeaGreen | LightPink | PapayaWhip |
DarkSlateBlue | LightSalmon | PeachPuff |
DarkSlateGray | LightSeaGreen | Peru |
Image from book

Drawing Basic Shapes

The best way to learn how to work with the Graphics class is to experiment with it. Let's begin with a couple of quick examples. The first example, shown next, demonstrates how to draw a green square:

private: System::Void button1_C1ick(System::Object^ sender, \
System::EventArgs^ e) {
       //Handle to form graphic surface
       System::Drawing::Graphics^ FormGraphic;
       //Handle to pen
       System::Drawing::Pen^ drawingPen;
       //Instantiate a pen object
       drawingPen = gcnew System::Drawing::Pen( \
       System::Drawing::Color::Black );
       //Create a rectangle object to hold the drawing extents
       System::Drawing::Rectangle drawingRect(100, 100, 100, 100);
       //Obtain the form's graphic surface
       FormGraphic = this->CreateGraphics();
       //Draw the image
       FormGraphic->DrawRectangle( drawingPen, drawingRect );
}

In this example, the program statements that draw the square are executed after the user clicks on the Button control. The first statement defines an object named FormGraphic based on the System::Drawing::Graphics class. The second statement defines an object named drawingPen, setting the object's Color property to black. The third statement uses the Rectangle class to instantiate an object named drawingRect so that it can represent the drawing extents for the rectangle to be drawn. The fourth statement sets the form's background as the drawing surface. Finally, the statement draws on the form's surface, using the data stored in the drawingPen and drawingRect objects.

Trick

Although the method used in this example is called Rectangle, you can draw squares, too, as long as the coordinates you specify for the rectangle create a square.

Figure 10.7 shows the drawing that is produced when this example is executed.

Image from book
Figure 10.7: Using the Graphics class's DrawRectangle method to draw a shape.

The next example demonstrates how to draw a filled-in circle. As you can see, the method is similar to the previous example:

private: System::Void button1_Click(System::Object^ sender, \
System::EventArgs^ e) {
       //Handle to form graphic surface
       System::Drawing::Graphics^ FormGraphic;
       //Handle to pen
       System::Drawing::Brush^ drawingBrush;
       //Instantiate a brush object
       drawingBrush = gcnew System::Drawing::SolidBrush( \
       System::Drawing::Color::Green );
       //Create a rectangle object to hold the drawing extents
       System::Drawing::Rectangle drawingRect(100, 100, 100, 100);
       //Obtain the form's graphic surface
       FormGraphic = this->CreateGraphics();
       //Draw the image
       FormGraphic->FillEllipse(drawingBrush,drawingRect);
}

As with the previous example, this example draws a shape (this time a filled-in circle) after the user clicks on the Button control. The first statement defines an object named FormGraphic based on the System::Drawing::Graphics class. The second statement creates an object named drawingPen, setting its Color property to green. The third statement again uses the Rectangle class to instantiate an object named drawingRect, which holds the bounds of the ellipse. The fourth statement sets the form's background as the drawing surface, as before. The last statement draws the filled ellipse on the form's surface based on the information stored in drawingBrush and drawingRect.

Trick

Although the Graphics class does not provide a FillCircle method, you can create a filled circle using FillEllipse by giving it a rectangle that is equal on all sides.

Figure 10.8 shows the drawing that is produced when this example is executed.

Image from book
Figure 10.8: Drawing a filled-in circle using the Graphics object's FillEllipse method.

Drawing Text

In addition to displaying and drawing graphics images, Visual C++'s GDI+ implementation allows you to draw text as a graphics image. You can do this using the Graphics class's DrawString() method. For example, one way to call on this method is shown here:

Dim objName As System::Drawing::Graphics
objName(TextString, FontType, BrushColor, Coordinates)

The following statement demonstrates how to create a text graphic:

private: System::Void Forml_Paint(System::Object^ sender, \
System::Windows::Forms::PaintEventArgs^ e) {
       System::Drawing::Font^ drawingFont;
       //Create a font object
       drawingFont = gcnew System::Drawing::Font("Arial", 18, FontStyle::Bold );
       //Obtain the form's graphic surface
       //Draw the string using the PaintEventArgs handle
       e->Graphics->DrawString("Hello World!", \
       drawingFont, Brushes::Red, 50, 50);
   }

In this example, the statements that draw the text image have been placed inside the Form1_Paint function. This function automatically executes each time the form needs to be repainted. Unlike with the earlier examples, if you do something that causes the form to be repainted (such as task to another program and then return), the text still appears because it is redrawn each time the form repaints itself.

In this example's first statement, a Font object named drawingFont is instantiated and passed arguments that set its font type, font size, and font style. The second statement draws a text string using the Graphics class's DrawString method. Note that the Graphics class is referenced through e->Graphics in this example. This reference is possible because painting event handlers automatically generate a handle to PaintEventArgs, which contains a reference to the System::Drawing class. This is expressed as the handle named e.

Trick

If you need to write code that responds to events generated by your application, select the Events icon in the Properties window while in Design view. Type in any function name you like for the event you want to respond to, and Visual C++ automatically generates a function so that you can write code that activates when the event triggers.

Figure 10.9 shows the output generated when this example is run.

Image from book
Figure 10.9: Visual C++ allows you to draw text as a graphic.


ADDING SOUNDS TO YOUR APPLICATIONS

Sound is a useful way to communicate information to those who use your application. You can use it to alert the user when a task is complete or a specific condition arises. You might, for instance, cause a sound to be played when an application has finished processing data or when a critical error occurs. Visual C++ 2005 Express provides functionality for playing sounds in the form of wave files.

Hint

A wave file is a digital audio file with a .wav file extension. Wave files store sound information in an uncompressed format. The .wav file format is widely supported on many different operating systems.

You can find wave files in various places. Many can be downloaded from the Internet. You can also find them on your computer. Windows XP, for example, stores several wave files in its Media folder, which is typically located in the Windows folder on your C drive.

Trick

If you can't locate a wave file that provides the sound you want to play, you can create your own. The Sound Recorder utility and a microphone are all you need. To access the Sound Recorder, click on Start, All Programs, Accessories, Entertainment, Sound Recorder. The Sound Recorder utility appears, as shown in Figure 10.10.

Image from book
Figure 10.10: Using the Windows Sound Recorder utility to create a custom wave file.

Working with the SoundPlayer Class

Visual C++ 2005 Express gives you several ways to play sounds within your applications. For starters, you can use the SoundPlayer class, found in the System::Media namespace. This class allows you to play a wave file located on your computer, on a network server, or even on the Internet.

When you reference a file that is stored locally, you must provide a path to the file, in the form of Drive Letter:\Path\WaveFileName.wav. When specifying the location of a wave file located on a network server, identify the location of the file as follows: \\NetworkComputerName\Path\WaveFileName.wav. Finally, to specify the location of a wave file on the Internet, you must specify the file's URL.

Note that when specifying path names, you must store them in a string. To play a wave file stored in the Windows Media folder, for example, you can specify C:\\Windows\\Media\\Chimes.wav as the value for a String variable. This would play the chimes sound when the SoundPlayer's Play() method is called.

Trap

You must use double backslashes if you want to represent a single backslash within any path you store in a string. In C++, a single backslash followed by certain characters is reserved for special functionality, such as tabbing or beginning a new line.

To use the SoundPlayer class, you must create an instance of it within your program. The SoundPlayer class requires the name of the wave file you want to play, specified as a string containing the full path and file name. After you have provided this, you can use the Play() method to play the wave file. For example, the following code segment demonstrates playing the chimes.wav file found in the Windows\Media folder whenever the user clicks a button:

  1. Load Visual C++ and open a new Windows Forms project.

  2. Add a button to the form and double-click it to generate its click function.

  3. Add the following statements to the newly generated function:

    //Create a string to contain the wave file
String^ strWinChimes = gcnew String("C:\\WINDOWS\\Media\\chimes.wav");
//Create an instance of the SoundPlayer
System::Media::SoundPlayer sndPlayer(strWinChimes);
//Play the wave file
sndPlayer.Play();

The following are some of the more useful properties and methods of the SoundPlayer class:

  • SoundLocation. A SoundPlayer property that specifies the location of the wave file to be played

  • Play(). A SoundPlayer method that plays the wave file specified by the SoundPlayer class's SoundLocation property

  • PlayLooping(). A SoundPlayer method that repeatedly plays the wave file specified by the SoundPlayer class's SoundLocation property

  • Stop(). A SoundPlayer method that stops playing any currently executing sound

Using the SystemSounds Class

By default, your application has access to certain sounds. The sounds available depend on what functionality your program invokes and the sounds that are specified by the sound scheme on the application user's computer.

Hint

A sound scheme is a set of sounds that Windows maps to certain events in Windows itself and within the applications it runs.

Some classes and controls automatically utilize sounds when their methods are invoked. The MessageBox class, for instance, automatically triggers a sound when its Show() method is called. In some cases, the sound changes, depending on the parameters passed to the method. If you instruct the MessageBox::Show method to display a dialog box containing a warning icon, for example, it will also play the appropriate warning sound that Windows plays for every warning dialog box.

Trick

You can pick different sound schemes by opening the Control Panel, selecting Sound, Speech, and Audio Devices, and then choosing Sounds and Audio Devices. This activates the Sounds and Audio Devices dialog box. Sound schemes are located under the Sounds tab.

Visual C++ also allows you to activate a default sound manually. The System::Media::SystemSounds namespace contains functionality to play common Windows sounds such as the Asterisk, Default Beep, and System Notification sounds. You can, for example, cause the Asterisk sound to play whenever the user clicks on a button by adding the following line to your button code:

System::Media::SystemSounds::Asterisk->Play();
Trap

If no sound exists in the sound scheme for the program event you reference, your code will function properly but fail to play a sound.

The following are some of the program event sounds you can activate:

  • Asterisk. A System::Media::SystemSounds property whose Play() methodtriggers the Windows Asterisk sound. Usually used in dialog boxes as an alert.

  • Beep. A System::Media::SystemSounds property whose Play() method plays the Windows Default Beep sound.

  • Exclamation. A System::Media::SystemSounds property whose Play() method activates the Windows Exclamation sound. Commonly used in dialog boxes to report an error or serious event.

  • Hand. A System::Media::SystemSounds property whose Play() method triggers the Windows Hand sound. Usually signifies a serious error.

  • Question . A System::Media::SystemSounds property whose Play() method invokes the Windows Question sound. Usually used in dialog boxes that query the user or provide information.


BACK TO THE VC++ DOODLE GAME

It's time to turn your attention back to the development of this chapter's game project, the VC++ Doodle game. The VC++ Doodle game is a drawing program. You will create it by following the five basic development steps that you've used to create all the previous game projects.

Designing the Game

The VC++ Doodle game runs in a single window and is made up of one form and the 11 controls listed in Table 10.3.

Table 10.3: Form Controls for the VC++ Doodle Game
Control Type | Control Name | Description
Panel1 | pntControl | Displays controls for drawing and painting
Label1 | lblControls | Identifies the location of the controls for the VC++ Doodle application
Label2 | lblColor | Identifies the ComboBox control where the player makes color selections
Button1 | btnRectangte | Initiates the process of drawing a rectangte
Button2 | btnLine | Initiates the process of drawing a line
Button3 | btnCircle | Initiates the process of drawing an ellipse
Button4 | btnFillRectangle | Initiates the process of drawing a filled-in rectangle
Button5 | btnFillCircle | Initiates the process of drawing a filled-in ellipse
Button6 | btnDraw | Initiates the process of making a freehand drawing
Button7 | btnClear | Initiates the clearing of the drawing area
ComboBox1 | cbxColor | Lists the available color choices provided by the application

Step 1: Creating a New Visual C++ Project

To create the VC++ Doodle game, use Visual C++ to create a new project, as outlined here:

  1. If you have not already done so, start up Visual C++ 2005 Express and then click on File, New Project. The New Project dialog box appears.

  2. Select the Windows Application template.

  3. Type VC++ Doodle as the name of your new application in the Name field located at the bottom of the New Project window.

  4. Click on OK to close the New Project dialog box.

Visual C++ then creates a new project for you and displays a new form upon which to design the game's user interface.

Step 2: Creating the User Interface

The first step in designing the game's user interface is to add the appropriate controls to the form and then move and resize them to the right locations. Use Figure 10.11 as a reference as you go through each of the following steps to make sure that you know where each control should be placed and how to size it.

  1. Resize Form1 by setting its Size property to 586, 458.

  2. Add a Panel control to the left side of the form and resize it until it takes up approximately 25 percent of the available form space.

  3. Add and center a Label control on top of the Panel control.

  4. Add six Button controls under the Label control.

  5. Add a second Label control beneath the last button that you added to the Panel control.

  6. Add a ComboBox control under the second Label control.

  7. Finally, add one more Button control on the Panel control.

Image from book
Figure 10.11: Completing the interface design for the VC++ Doodle game.

The overall layout of the VC++ Doodle game's user interface is now complete. The next step is to begin customizing form and control properties.

Step 3: Customizing Form and Control Properties

The VC Doodle game contains only a few properties to configure. To create the settings that the application needs, change the form properties listed in Table 10.4.

Table 10.4: Property Changes for FormI
Property | Value
Name | frmMain
BackColor | White
Cursor | Crosshair
FormBorderStyle | Fixed3D
Size | 586, 458
StartPosition | CenterScreen
Text | VC++ Doodle

Next, modify the properties listed in Table 10.5 for the Panel control.

Table 10.5: Property Changes for Panel Control
Property | Value
Name | pnlControl
Anchor | Top, Bottom, Left
BackColor | LightGray
BorderStyle | FixedSingle
Size | 130, 430
Trick

Take special note of the Anchor property setting. It has been set so that the Panel control will automatically resize itself if the form is resized. This gives the player the flexibility to change the size of the drawing area by maximizing the form without affecting the size and appearance of the Panel control.

Next, modify the properties listed in Table 10.6 for the two Label controls.

Table 10.6: Property Changes for Label Controls
Control | Property | Value
Label1 | Name | lblControls
 | Font.Bold | True
 | Text | Controls
Label2 | Name | lblColor
 | Font.Bold | True
 | Text | Select Color:

Now modify the properties listed in Table 10.7 for the seven Button controls.

Table 10.7: Property Changes for Button Controls
Control | Property | Value
Button1 | Name | btnRectangle
 | Text | Rectangle
Button2 | Name | btnLine
 | Text | Line
Button3 | Name | btnCircle
 | Text | Circle
Button4 | Name | btnFillRectangle
 | Text | Fill Rectangle
Button5 | Name | btnFillCircle
 | Text | Fill Circle
Button 6 | Name | btnDraw
 | Text | Draw
Button7 | Name | btnClear
 | Text | Clear

Next, change the properties listed in Table 10.8 for the ComboBox control.

Table 10.8: Property Changes for ComboBox Control
Property | Value
Name | cbxColor
Items | Red
 | Green
 | Blue
 | Black
 | Yellow
 | Purple
Text | Red

That's it. You have finished making all the design time property changes to the VC++ Doodle application's form and control properties.

Step 4: Adding a Little Programming Logic

The first step in coding the VC++ Doodle game is to define the objects to be used internally throughout the application. These are shown here:

private:
  /// <summary>
  /// Required designer variable.
  /// </summary>
  //Handle to manage form's drawing functionality
  System::Drawing::Graphics ^FormGraphic;
  //Handle to manage drawing pen
  System::Drawing::Pen ^pen;
  //Handle to manage graphical brush
  System::Drawing::SolidBrush ^brush;
  //Variables to manage drawing coordinates
  System::Drawing::Point ptStart, ptEnd;

  //Values for possible drawing states
  enum class DrawingMode: Int16 {
    DRAWRECTANGE, DRAWLINE, DRAWCIRCLE, DRAWFILLRECTANGLE,
    DRAWFILLCIRCLE, DRAWFREE, DRAWNONE
  };
  //Variables to track current drawing state
  DrawingMode drmCurrentMode;
  //Flag to determine if drawing is in progress
  Boolean blnDrawing;

The first declaration defines a handle to reference the Graphics class. Below that is the handle to manipulate an instance of a Pen class, which is used in drawing lines. That is followed by a similar declaration for a brush handle, which will control the way shapes are filled.

The code that follows is a declaration for two System::Drawing::Point objects. Both are used throughout the application to keep track of where the user is positioning the mouse cursor for drawing. The Point ptStart variable tracks the start of a drawing movement, whereas the ptEnd movement stores its end.

Hint

A Point class is a member of the System::Drawing namespace. The Point class can be used as a mechanism for storing sets of coordinates.

This chapter game again uses an enum class, derived from the Int16 class. The unique values it enumerates (defines) specify the possible drawing modes that the player might have triggered. These are later used to drive functionality that determines how the program performs drawing. The class definition is immediately followed by a declaration of an instance of the DrawingMode, drmCurrentMode. The drmCurrentMode object is used throughout the program to control drawing behavior.

Finally, a Boolean variable, blnDrawing, is declared to act as a monitor for whether the user is currently engaged in drawing.

The next step in building the VC++ Doodle program is to add the code shown in the next listing:

private: System::Void Form1_Load(System::Object^ sender,\
System::EventArgs^ e) {
     FormGraphic = this->CreateGraphics();
     pen = gcnew System::Drawing::Pen( \
         System::Drawing::Color::FromName( cbxColor->Text ) );
     brush = gcnew System::Drawing::SolidBrush( \
           System::Drawing::Color::FromName( cbxColor->Text ) );

    //Set the default drawing coordinates to center screen
    ptStart.X = this->Size.Width / 2;
    ptStart.Y = this->Size.Height / 2;
    ptEnd.X = this->Size.Width / 2;
    ptEnd.Y = this->Size.Height / 2;
    //Set default drawing mode
    drmCurrentMode = DrawingMode::DRAWNONE;
    blnDrawing = false;
}

As you can see, the first step that this function takes is to obtain access to its own CreateGraphics method, using this->CreateGraphics(). Then both pen and brush handles are instantiated, each using the color listed in the application's color combo box.

By default, the drawing coordinates are set to the center of the screen. This ensures that they start with some nonrandom value. (Zero would be just as acceptable, but for testing purposes would have started any graphical output under the application's panel on the upper-left side.) The application also sets its drawing mode defaults, indicating that no drawing mode has been selected and that drawing is not currently taking place.

To add functionality that causes the VC++ Doodle game to switch drawing modes when the appropriate buttons are clicked, you must double-click each control so that Visual C++ generates the necessary related code. The code to add to each control is quite simple. The sole task of each is to assign the enumerated object drmCurrentMode with contents corresponding to the appropriate button. Because each click event handler contains only one line, I've grouped the code for the controls next:

private: System::Void btnRectangle_Click(System::Object^ sender,
System::EventArgs^ e) {
      drmCurrentMode = DrawingMode::DRAWRECTANGE;
  }
private: System::Void btnLine_Click(System::Object^ sender,
System::EventArgs^ e) {
      drmCurrentMode = DrawingMode::DRAWLINE;
  }
private: System::Void btnCircle_Click(System::Object^ sender,
System::EventArgs^ e) {
      drmCurrentMode = DrawingMode::DRAWCIRCLE;
  }

private: System::Void btnFillRectangle_Click(System::Object^ sender,
System::EventArgs^  e) {
      drmCurrentMode = DrawingMode::DRAWFILLRECTANGLE;
  }
private: System::Void btnFillCircle_Click(System::Object^ sender,
System::EventArgs^  e) {
      drmCurrentMode = DrawingMode::DRAWFILLCIRCLE;
  }
private: System::Void btnDraw_Click(System::Object^ sender,
System::EventArgs^  e) {
      drmCurrentMode = DrawingMode::DRAWFREE;
  }

The next step involves updating the application's current drawing color. If the user selects a new color, you must adjust the pen and brush colors accordingly. To create the event handler, double-click on the cbxColor ComboBox control and add the code shown here:

private: System::Void cbxColor_SelectedIndexChanged(System: :Object^
sender, System::EventArgs^ e) {
     //Set pen and brush colors
     pen->Color = \
        System::Drawing::Color::FromName( cbxColor->Text );
     brush->Color = \
          System::Drawing::Color::FromName( cbxColor->Text );
  }

This function uses the FromName() method of the Color object located in the System:: Drawing namespace. The method accepts as an argument the current text string in the ComboBox control. It translates this to a value that the Pen and Brush objects understand.

To allow the user to clear the form, double-click the Clear button and add the following code to the click event function that Visual C++ defines:

private: System::Void btnClear_Click(System::Object^ sender, \
System::EventArgs^ e) {
      //Clear the form to the background color
      FormGraphic->Clear( this->BackColor );
  }

The Clear method of the System::Graphic class (in the instance of FormGraphic in this case) accepts a color and sets the surface of the form to that color. Controls or other elements on the form are unaffected because each has its own foreground and background color data in most cases. The form's current background color is obtained by using this to point to the class that the code is running within (the application's form).

No matter what kind of drawing operation the player wants to perform, such as drawing a circle, line, or freehand image, everything begins when the player clicks on the mouse button to set the starting point for whatever shape is being drawn. Therefore, you need to capture mouse events.

Hint

A mouse event occurs whenever the user performs any action with the mouse that an application can recognize, such as clicking, moving the mouse, or dragging and dropping an item.

Visual C++ doesn't give you a control you can use to capture the mouse events. Instead, you must switch back to Design view, select the application's form, and investigate the options under the Properties window. By default, this window displays the properties of all the controls. To switch to the event handlers attached to the controls, click an icon that represents events (shown as a lightning bolt).

Locate the MouseUp entry. In the text field next to it, enter HandleMouseUp. Just as it does when you double-click a form, this causes Visual C++ to generate code that executes each time the form is clicked. Add the following code to this event handler function:

private: System::Void HandleMouseUp(System::Object^ sender, \
System::Windows::Forms::MouseEventArgs^ e) {
     blnDrawing = false;
     //Stop drawing if current mode is freehand drawing
     if( drmCurrentMode = DrawingMode::DRAWFREE )
        return;
     //Draw shape
     if( drmCurrentMode != DrawingMode::DRAWNONE )
     {
       //If the current mode is a line, draw it
       if( drmCurrentMode == DrawingMode::DRAWLINE )
       {
        FormGraphic->DrawLine( pen, ptStart, ptEnd );
        return;
       }
       //Current mode is a shape
       //Create a rectangle to represent shape extents
       //  Height and width are composed of absolute

     // value difference between the two x and y
     // coordinates
     System::Drawing::Rectang1e shapeRect(
       ptStart.X, ptStart.Y,
       Math::Abs( ptEnd.X - ptStart.X ),
       Math::Abs( ptEnd.Y - ptStart.Y ) );
     //Draw the shape
     DrawShape( shapeRect );
   }
}

This code is activated when the user releases the mouse button, but only if he's over the form. It does not trigger when the user clicks a control or the panel. Each control or form within an application can be given its own mouse click event handler, allowing you to customize mouse behavior to a high level.

The code within the HandleMouseUp event handler sets the drawing mode to false because the mouse is released only when drawing is complete. If the user is in freehand drawing mode, this function has no more to do and returns. If the user is in the process of drawing a shape or line, however, the release of the mouse button signifies that the shape or line should draw from the starting to the ending point. Drawing a line is straightforward, but if the user is in the process of drawing a shape, the program must translate the starting and ending coordinates into a rectangular region. This is done by creating an instance of a shape and initializing it with the x and y properties of ptStart and ptEnd.

Take special note of the call made to Math::Abs. The System::Drawing::Rectang1e class accepts an x and y location as its first two parameters, but it does not for the last two. Instead, any Rectangle object needs a height and a width. You can obtain this by subtracting the two x and y properties of ptStart and ptEnd, respectively, but you must make sure that the math does not produce a negative number. This is why you should use the Abs() method. Finally, after you determine the shape extents, the handler calls a function to draw the shape.

The next mouse events that the application needs to capture are mouse moves. Switch to Design view and add a handler called HandleMouseMove to the form's MouseMove category. When you type the name, Visual C++ generates code just as it did for the HandleMouseUp handler. Supply the handler with the following code:

private:  System::Void HandleMouseMove(System::Object^ \
sender,  System::Windows::Forms::MouseEventArgs^  e) {
      if( blnDrawing == true )
      {

      ptEnd.X = e->X;
      ptEnd.Y = e->Y;
      if( drmCurrentMode == DrawingMode::DRAWFREE )
      {
        //Offset the current coordinates so that
        //  a small line can be drawn to represent
        //  the current point
        ptStart.X = e->X + 1;
        ptStart.Y = e->Y + 1;
        FormGraphic->DrawLine( pen, ptStart, ptEnd );
      }
   }
}

This event handler captures instances of the mouse moving over the application's form. It must first determine whether drawing is currently in process. Testing for this condition prevents the application from drawing lines or shapes accidentally when the user is moving the mouse over the form but has not started drawing.

If drawing is in progress, the application saves the current mouse coordinates. These are provided through e->X and e->Y. When you are drawing freehand, the current location is offset slightly so that a line can be drawn.

Finally, the application requires an event handler to capture each mouse down event. In Design view, add the handler by locating the MouseDown event entry and typing HandleMouseDown. Add the following code to the event handler that Visual C++ generates:

private:  System::Void HandleMouseDown(System::Object^\
sender, System::Windows::Forms::MouseEventArgs^ e) {
     if(  drmCurrentMode != DrawingMode::DRAWNONE )
     {
       //Now drawing, set starting coordinates
       ptStart.X = e->X;
       ptStart.Y = e->Y;
       b1nDrawing = true;
    }
}

This event handler captures the mouse click that initiates drawing. If a drawing mode has been selected, it saves the starting coordinates. It also toggles the variable tracking the drawing mode, blnDrawing, to true.

The VC++ Doodle game requires one final function to control which shape is drawn. The function must be created by hand, as shown here:

private: System::Void DrawShape( \
System::Drawing::Rectangle rect ) {
      //Set a default shape rectangle
      switch( drmCurrentMode )
      {
        case DrawingMode::DRAWRECTANGE :
          FormGraphic->DrawRectangle( pen, rect );
          break;
        case DrawingMode::DRAWCIRCLE :
          FormGraphic->DrawEllipse( pen, rect );
          break;
        case DrawingMode::DRAWFILLRECTANGLE :
          FormGraphic->FillRectangle( brush, rect );
          break;
        case DrawingMode::DRAWFILLCIRCLE :
          FormGraphic->FillEllipse( brush, rect );
          break;
      }
  }

This function uses a switch statement to determine whether to draw a rectangle, circle, filled rectangle, or filled circle. After you've added this code, you can test the game.

Step 5: Testing the Execution of the VC++ Doodle Game

Okay. That's it. The VC++ Doodle game is now ready to run. Go ahead and run the game by pressing F5, and make sure that everything works like it's supposed to. If you run into problems, go back and double-check your typing.


SUMMARY

In this chapter, you learned how to work with various classes and objects that allow you to work with graphics and audio. This included learning how to work with the System::Drawing::Graphics namespace.You discovered how to instantiate the Graphics object and the Pen and Brush objects and how to use their properties and methods to create various drawing applications. You also found out how to add sound to your Visual C++ applications using the SoundPlayer and SystemSounds class. In addition, you learned how to create the VC++ Doodle game.

Before you move on to Chapter 11, "Debugging Visual C++ Applications," and start learning various tools and techniques for debugging your Visual C++ applications, take a few extra minutes to improve the VC++ Doodle game by completing the following challenges.


CHALLENGES

  1. As the game is currently written, it is not always clear what type of shape the player is working with. To make the application easier to use, add a status bar control and use it to display a string identifying the currently selected shape.

  2. The Graphics class allows you to create numerous other shapes besides rectangles, ellipses, and lines. Enhance the VC++ Doodle game to support other shapes, such as a pie, arc, and polygon. You can get information on the arguments that need to be supplied to create each of the shapes using Visual C++'s Help system.

  3. The Visual C++ Pen and Brush classes provide access to dozens of predefined colors. Expand the VC++ Doodle game's list of supported colors to give the player additional choices.

  4. Use the MessageBox::Show method to require the player to confirm his desire to clear the drawing area before allowing the btnClear_Click event function to execute.

  5. Make the VC++ Doodle game a little more exciting by adding some sound effects. For example, consider playing the C:\Windows\Media\Tada.wav file when the application loads. Also, find a different sound to play when the player switches colors and when the player clicks on the button that clears the drawing surface.


Chapter 11: Debugging Visual C++ Applications

OVERVIEW

Welcome to the final chapter in this book. In this chapter, you learn how to handle syntax, logic, and runtime errors. This process includes understanding how your program functions while running by establishing breakpoints that reveal variable status and program flow. You discover how to use a variety of debugging windows. You also will learn how to develop custom exception-handling routines. In addition, you have an opportunity to apply what you learn through the development of the chapter's game project, the Tic-Tac-Toe game.

In this chapter, you learn the following:

  • About the different types of errors that can occur

  • How to set breakpoints and to step through code execution

  • How to how to use various debugging windows

  • How to create exception-handling routines


PROJECT PREVIEW: THE TIC-TAC-TOE GAME

For the final chapter's game project, you develop a two-player Visual C++ version of the Tic-Tac-Toe game. You track and validate player moves and determine when a game is won, lost, or tied. Figures 11.1 to 11.3 illustrate the overall functionality and flow of the Tic-Tac-Toe game.

Image from book
Figure 11.1: The Tic-Tac-Toe game begins by displaying a blank game board.
Image from book
Figure 11.2: The game keeps track of each player's turn.
Image from book
Figure 11.3: The game monitors each player's move and determines when there is a winner.

By the time you have created, tested, and run this game, you will have successfully placed yourself on the path to becoming a Visual C++ programmer. The examples in this book can serve as a foundation for you to further your explorations into the language. The techniques you have learned up to this point enable you to begin building more complex and capable Visual C++ applications.


DEALING WITH ERRORS

Errors are part of the programming experience. As your programs become larger and more complex, errors become even more likely. Even the most experienced programmers encounter errors as they build applications. But as you gain experience in dealing with errors, you develop techniques for minimizing their impact.

Your application can be afflicted with many different types of errors. In programming terminology, these are often referred to as bugs. As a programmer, your goal is to find and remove these bugs.

You can employ several techniques to reduce the number of errors in your applications. One of the most useful is to have a plan before you begin coding. By figuring out how the code should work before starting, you are less likely to create a class, module, or function that behaves improperly.

Another technique is to test your application for bugs as you're coding it. Periodically compiling and even running your application in stages helps you spot bugs early, before they become obscured by the full bulk of your application.

Some other good programming practices to consider include these:

  • Creating a simple and easy-to-use interface

  • Providing users with clear instructions

  • Validating user input data before accepting it

  • Using consistent naming schemes for constants, variables, classes, objects, arrays, and functions

  • Thinking through the overall program flow and anticipating where and how errors might occur

There are three basic categories of errors that you will experience when developing Visual C++ applications:

  • Syntax and compiler errors

  • Logical errors

  • Runtime errors

Syntax Errors

The syntax error is probably the most prevalent type of programming error. It involves creating any statement that Visual C++ does not recognize. This can occur as a result of misspelling a function name or forgetting to include a semicolon at the end of a line.

Visual C++ identifies syntax errors when you attempt to compile your program. It generates the result of all errors in the Output window, as demonstrated in Figure 11.4. If you click on the error, Visual C++ responds by taking you to the offending section of code.

Image from book
Figure 11.4: The Output window displays errors found at compile time.
Hint

A syntax error is an error that occurs when you do not write a code statement according to the rules of the programming language.

Logical Errors

Logical errors are those errors that result from the difference between how a program actually works versus how it is supposed to work. For example, you might create a logical error by multiplying two numbers that should have been added. This might cause your application to generate an undesired or unexpected result. Another example of a logical error is when you accidentally set up an endless loop.

Hint

A logical error is created when the programmer makes a mistake in implementing in code the logic used to perform a given task.

Visual C++ might generate warnings during compile time for some common logical errors. However, your best defense against them is trying to prevent them by carefully planning and testing your code. Organize your C++ applications into functions that are easy to read and only perform a limited number of related tasks. As you develop your application, test it periodically to see if it meets your expectations. This helps reduce logic errors because it makes them more apparent earlier in the development process.

Runtime Errors

A third category of errors is the runtime error, which occurs whenever a statement attempts to perform a task that is outside the bounds of its capabilities or simply impossible. For example, a runtime error occurs if an application attempts to divide one value by another that is zero. Or one might occur if your program attempts to access system resources, such as memory or disk space, that are unavailable.

Hint

A runtime error occurs when an application attempts to perform an illegal action.

Runtime errors can be ticking time bombs in your code. In fact, if a seldom-used function contains code that might produce a runtime error and you don't carefully test the functionality provided by that function, you might not catch the runtime error. This leaves your user to discover it.

If you come across a runtime error when running your Visual C++ application in Debug mode, you receive an error message like the one shown in Figure 11.5. However, if you don't catch the runtime error during testing and development, your application might or might not display an error message when its release version is executed. Worse still, your application might simply lock up and stop responding.

Image from book
Figure 11.5: An example of a visual C++ runtime error displayed when an application is being executed in Design mode.

A runtime error also might occur if the user gives your application incorrect or unexpected input, or if a user uses your application in unexpected ways. You can prevent these errors to some extent by adding logic within your applications that validates all data and limits certain risky tasks or activities. This gives you an important defense against runtime errors.

It can also help to have different people test your programs. Different users bring different perspectives and assumptions on how your application should be used. They might also be able to expose your application to different computer configurations, which might reveal flaws about the assumptions you made in terms of what resources would be available and how they would work.

Although it is critical to test your programs as thoroughly as possible, there is no way to completely avoid runtime errors. Your application might require memory or resources that suddenly aren't available. In such a situation, a runtime error is likely to occur. However, as you'll learn later in this chapter, Visual C++ allows you to develop exception handlers so that you can recover from or at least gracefully respond to unavoidable runtime errors.


ESTABLISHING BREAKPOINTS

Visual C++ 2005 Express gives you access to several tools that help in tracking down and dealing with errors. These tools can help you monitor your program code as it executes, examine the value of variables and properties, and track the execution path to determine what code is being called and from where.

Throughout this book, you have executed all Visual C++ applications by pressing the F5 key within the Visual C++ IDE. You have been creating what are known as debug versions of your applications. Debug versions contain information within them that enables Visual C++ to help you track down errors.

If your application has debug information embedded within it, you can use breakpoints to cause your application to stop on certain lines of code. This allows you to pause execution, explore your program's internals, and even resume execution after making changes. Such functionality can serve as a highly effective aid in tracking down and locating statements that might be incorrectly setting variable and property values. In Visual C++, this process is known as breaking into a program or debugging with breakpoints.

Setting Up Breakpoints

To set up a breakpoint within your application, click on the left margin of the Code Editor on the line where you want to place the breakpoint. After the breakpoint has been set, a circular marker is displayed in the margin, and the line of code where the breakpoint is set is highlighted, as demonstrated in Figure 11.6.

Image from book
Figure 11.6: Using a breakpoint to pause an application's execution.

Breakpoints are often useful if you place them at or above locations within your program where you suspect a problem might be occurring. You can set as many breakpoints as you want. When you press F5 to run your application and a breakpoint is reached, program execution pauses, and the circular marker for the current breakpoint changes to display an arrow, as demonstrated in Figure 11.7.

Image from book
Figure 11.7: The Visual C++ IDE changes the highlight of the currently active breakpoint.
Trick

After you have resolved any errors that you might have and no longer need breakpoints, you can remove them by clicking on the circular markers located in the left margin.

Breaking into your program can reveal information about how variable and properties have been set. As Figure 11.7 illustrates, the Locals window and the Call Stack window are opened. The Locals window displays information about variables that reside within the current function or method, including their current value and type. You can change the value assigned to a variable displayed in the Locals window by clicking its value.

You can also use the Call Stack to examine the path of execution through your program so far. For example, if you look at the Call Stack in Figure 11.7, you see ClearGameBoard at the top of the list, with btnPlay_Click just below it. If you click btnPlay_Click, Visual C++ takes you to the point where it called ClearGameBoard.

By using breakpoints and the windows mentioned earlier, you can track down many errors by locating where and when a value, property, or variable was incorrectly modified.

Stepping through Code Execution

Another important debugging technique is the ability to step through your program line by line while it is executing. This allows you to watch your program make changes in real-time. It also can help you identify a section of code that might be causing errors. You can set a breakpoint, allow the program to execute up to that point, and then step through and execute each subsequent statement one line at a time. When you do so, you can track the flow of logic, pausing at any point along the way to examine a value, related variables, or property.

Visual C++ gives you three different ways to step through your program statements:

  • Step Into. Executes the Breakpoint statement and pauses before the execution of statements that follow

  • Step Over. Executes entire functions, pausing before the execution of the next function

  • Step Out. Used inside a function to return to the calling function where program flow is then paused

You can selectively choose which of these step options you want to use at any moment by clicking on their icons, which are located in the Visual C++ standard toolbar, as shown in Figure 11.8.

Image from book
Figure 11.8: Using the Debug icons on the standard toolbar to step through program statements.


DEVELOPING EXCEPTION HANDLERS

Runtime errors, also referred to as exceptions, are anomalous conditions that can occur for various reasons. Some examples of exceptions are attempting to process user input that is in an invalid format or attempting to access a system resource, such as a file, that is no longer available. Visual C++ deals with exceptions in one of two ways: either allowing you to handle them or terminating the program (abruptly) with an error message. Obviously, your application's users would probably prefer a graceful error message that might allow them to recover or save their work to a cryptic message that aborts the program.

If you want your applications to handle exceptions, you must anticipate the likely locations where they will occur. Then you must add code that handles the problem. For example, if it is likely that user input would cause an error in a given section of your code, you would include validation checks at that point. Or if your application must access file resources, you should add logic that notifies the user if the required resources are unavailable. There are several other ways to deal with exceptions. For example, you can do the following:

  • Provide a clear, unambiguous, and easy-to-understand error message

  • Give the user a choice and possible courses of action

  • Apologize for the error and close down the application

  • Request that the user report the error

Exception handling gives your application greater flexibility when it encounters runtime errors. By adding exception-handling logic to your Visual C++ applications, you can better contain errors and respond in a more user-friendly fashion. Error handling can also save you the embarrassment of your applications crashing outright.

A Runtime Exception Demonstration

To better understand exception handling, we'll compare how Visual C++ handles exceptions to how your application could possibly handle exceptions. First, load Visual C++ and create a new Windows Forms project. Add to the form a button, and double-click it to cause Visual C++ to generate its click handler. Then add to the button1_C1ick function the following code:

private: System::Void buttonl_Click(System::Object^  sender, \
                                       System::EventArgs^  e)
{
  String^ strTest = gcnew String("Test");
  Int16 intValue = 0;
  intValue = Int16::Parse(strTest);
  MessageBox::Show( intValue.ToString()  );
}

Your application has an intentional flaw. Intl6::Parse() is designed to extract numerical contents from a string. However, the string that is supplied to it has a problem. Press F5 to test your application and click the button. Your application should immediately stop running and display results similar to those in Figure 11.9.

Image from book
Figure 11.9: Examining the error message that's generated when your application runs into an unhandled exception at runtime.

Visual C++ displays an error dialog box that contains the options of going to the source of the error, continuing execution, or (in some cases) ignoring the error. In the first two cases, your program ceases execution. If you select Break, the application ends, and Visual C++ displays the line that caused the error. At this point, you are still in debug mode, which might allow you to examine other aspects of the program, depending on the severity of the error. If you select Continue, however, your application terminates completely (that is, it crashes).

Now let's see what happens when you use an exception handler. Replace the previous code with the following:

private: System::Void button1 Click(System::obiect^   sender, \
System::EventArgs^  e) {
  String^ strTest = gcnew String("Test");
  Int16 intValue = 0;
  try
  {
    intValue = Int16::Parse(strTest);
  }
  catch(Exception^)
  {
    MessageBox::Show( "Error: Invalid Data!" );
  }
  MessageBox::Show( intValue.ToString() );
}

In this example, the exception handler is made up of try and catch blocks. The try block contains the risky, potentially (or actually, in this case) error-causing code. Should this code fail, the code within the catch block executes. In this example, the results of which are shown in Figure 11.10, the application simply continues executing, ignoring the result of the failure to convert the text within strTest into a number. Although this example is simple, you could use a similar mechanism to validate data from a text box, issuing an error, ignoring the problem, or closing down your application in response.

Image from book
Figure 11.10: Exception handling provides a more graceful means of dealing with runtime errors.


BACK TO THE TIC-TAC-TOE GAME

It's time to turn your attention to this book's final game project, the Tic-Tac-Toe game. You will create the Tic-Tac-Toe game by following the same five basic development steps that you have followed for all preceding game projects.

Designing the Game

You play the Tic-Tac-Toe game on a single window. The game is made up of one form and the 18 controls listed in Table 11.1.

Table 11.1: From Controls for the Tic-Tac-Toe Game
Control Type | Control Name | Description
Panel 1 | pnlLeft | Represents the left vertical bar on the game board
Panel2 | pnlRight | Represents the right vertical bar on the game board
Panel3 | pnlTop | Represents the top horizontal bar on the game board
Panel4 | pnlBottom | Represents the bottom horizontal bar on the game board
PictureBox 1 | pbxAl | Holds the left square on the first row of the game board
PictureBox2 | pbxA2 | Holds the middle square on the first row of the game board
PictureBox 3 | pbxA3 | Holds the right square on the first row of the game board
PictureBox4 | pbxB1 | Holds the left square on the second row of the game board
PictureBox5 | pbxB2 | Holds the middle square on the second row of the game board
PictureBox6 | pbxb3 | Holds the right square on the second row of the game board
PictureBox7 | pbxC1 | Holds the left square on the third row of the game board
PictureBox8 | pbxC2 | Holds the middle square on the third row of the game board
PictureBox9 | pbxC3 | Holds the right square on the third row of the game board
Button 1 | btnPlay | Initiates gameplay
Button2 | btnExit | Terminates the game
Label 1 | lblOutput | Identifies the TextBox control that displays the status messages
TextBox 1 | txtOutput | Displays status messages
ImageList 1 | imlSquares | Stores an indexed collection of graphics that represent player moves

Step 1 : Creating a New Visual C++ Project

The first step in creating the Tic-Tac-Toe game is to open Visual C++ and create a new project, as outlined here:

  1. If you have not already done so, start Visual C++ 2005 Express and then click on File, New Project. The New Project dialog box appears.

  2. Select the Windows Application template.

  3. Type Tic-Tac-Toe as the name of your new application in the Name field at the bottom of the New Project window.

  4. Click OK to close the New Project dialog box.

Visual C++ creates a new project for you and displays a form, which you can use to design your new game's user interface.

Step 2: Creating the User Interface

The first step in laying out the user interface is to add controls to the form and to move and resize them to the appropriate locations. As you go through each step, make sure that you reference Figure 11.11 so that you know where each control needs to be placed and what size it needs to be.

  1. Begin by setting the Size property of the form to 605, 591.

  2. Next, create the grid lines that organize the game board by adding four Panel controls and resizing them, as shown in Figure 11.11.

  3. Add PictureBox controls inside each of the game board's nine cells and resize them until they take up almost all the available space.

  4. Add two Button controls to the bottom-left corner.

  5. Add a TextBox control to the bottom-right side of the game board, set its Multiline property to true, and resize it.

  6. Add a Label control and place it just over the upper-left corner of the TextBox control.

  7. Finally, add an ImageList control and set its size to 100, 100.

Image from book
Figure 11.11: Completing the interface design for the Tic-Tac-Toe game.

At this point, the overall layout of the Tic-Tac-Toe game's user interface is complete. You can start making changes to the form and control properties.

Step 3: Customizing Form and Control Properties

Let's begin by making the required changes to properties belonging to the Form object, as listed in Table 11.2.

Table 11.2: Property Changes for Form1
Property | Value
Name | frmMain
ControlBox | false
Cursor | Hand
FormBorderStyle | Fixed3D
StartPosition | CenterScreen
Text | Tic-Tac-Toe

Make the property changes shown in Table 11.3 to the Panel controls.

Table 11.3: Property Changes for Panel Controls
Control | Property | Value
Panel1 | Name | pnlLeft
 | BackColor | Black
Panel2 | Name | pnlRight
 | BackColor | Black
Panel3 | Name | pnlTop
 | BackColor | Black
Panel4 | Name | pnlBottom
 | BackColor | Black

Make the property changes shown in Table 11.4 to the PictureBox controls.

Table 11.4: Property Changes for PictureBox Controls
Control | Property | Value
PictureBox1 | Name | pbxA1
 | Enabled | false
 | Size | 100, 100
 | SizeMode | StretchImage
PictureBox2 | Name | pbxA2
 | Enabled | false
 | Size | 100, 100
 | SizeMode | StretchImage
PictureBox3 | Name | pbxA2
 | Enabled | false
 | Size | 100, 100
 | SizeMode | StretchImage
PictureBox4 | Name | pbxB1
 | Enabled | false
 | Size | 100, 100
 | SizeMode | StretchImage
PictureBox5 | Name | pbxB2
 | Enabled | false
 | Size | 100, 100
 | SizeMode | StretchImage
PictureBox6 | Name | pbxB3
 | Enabled | false
 | Size | 100, 100
 | SizeMode | StretchImage
PictureBox7 | Name | pbxC1
 | Enabled | false
 | Size | 100, 100
 | SizeMode | StretchImage
PictureBox8 | Name | pbxC2
 | Enabled | false
 | Size | 100, 100
 | SizeMode | StretchImage
PictureBox9 | Name | pbxC3
 | Enabled | false
 | Size | 100, 100
 | SizeMode | StretchImage

Make the property changes shown in Table 11.5 to the Button controls.

Table 11.5: Property Changes for Button Controls
Control | Property | Value
Button 1 | Name | btnPlay
 | Text | Play
Button2 | Name | btnExit
 | Text | Exit

Make the property changes shown in Table 11.6 to the Label control.

Table 11.6: Property Changes for Label Control
Control | Property | Value
Label1 | Name | lbl0utput
 | Font.Bold | true
 | Text | Status

Finally, make the property changes shown in Table 11.7 to the TextBox control.

Table 11.7: Property Changes for TextBox Control
Control | Property | Value
TextBox1 | Name | txtOutput
 | Font.Bold | true
 | Readonly | true
 | TabStop | false

Step 4: Adding a Little Programming Logic

Let's add the class and variable definitions needed throughout the Tic-Tac-Toe game, as shown next. These variables help support the game's logic across many of its functions:

private:
  /// <summary>
  /// Required designer variable.
  /// </summary>
  //Values for possible square states
  enum class SquareStates : Int16 {
    SQUAREOPEN, SQUAREX, SQUAREO
  };
  //Values to help keep track of whose
  //  turn it is
  enum class Player : Int16 {
    PLAYERX, PLAYERO, PLAYERNONE,
  };
  //Game board
  array <SquareStates>^ sgsGameBoardArray;
  Player plyActivePlayer;

The first is an enumerated type definition, SquareStates, which helps create meaningful labels for the possible moves within each square. This class defines three states that indicate that a board position is open, filled with an X, or filled with an O. This helps prevent the errors that might occur if you have to refer to positions on the board with numbers or some other value.

This definition is followed by another enumerated type definition that allows the game to track the current player. The game also uses a handle to an array of type SquareStates, which holds the state of the game board.

The form's Load event function, shown next, is responsible for preparing the game for initial play. This is accomplished by calling three custom functions:

private: System::Void Form1_Load(System::Object^  sender,\
System::EventArgs^  e) {
     //Get memory for the game board
     sqsGameBoardArray = gcnew array<SquareStates>(9);
     //Set no player on startup
     plyActivePlayer = Player::PLAYERNONE;
     //Establish the game board
     SetGameDefaultS();

     ClearGameBoard();
     EnableGameBoard( false );
   }

First, the game acquires memory for nine positions, each of which represents a space on the board. Then the game sets the starting player and establishes the game board. Create the next listing by typing the following program code:

private: System::Vo1d SetGameDefaults(System::Void) {
    //Set the game's starting message and player
    txtOutput->Text = "Click Play to begin.";
    SwapPlayerTurn();
  }

This function, SetGameDefaults(), sets the starting game text and triggers the switching of player positions. This function is called after a player wins to ensure that the loser of that game starts the next game.

The next function clears all squares of the game board. Add it to your project by typing the code shown here:

private: System::Void ClearGameBoard(System::Void) {
    //Set all squares in game board to open
    for( Int32 intCounter = 0; intCounter < \
    sqsGameBoardArray->Length; intCounter++ )
    sqsGameBoardArray[intCounter] = SquareStates::SQUAREOPEN;
    //Blank all images on the game board
    pbxA1->Image = imlSquares->Images[0];
    pbxA2->Image = imlSquares->Images[0];
    pbxA3->Image = imlSquares->Images[0];
    pbxB1->Image = imlSquares->Images[0];
    pbxB2->Image = imlSquares->Images[0];
    pbxB3->Image = imlSquares->Images[0];
    pbxC1->Image = imlSquares->Images[0];
    pbxC2->Image = imlSquares->Images[0];
    pbxC3->Image = imlSquares->Images[0];
  }

This function is responsible for clearing the data that represents the game board. It loops through an array to do so, using sqsGameBoardArray->Length to ensure that the intCounter does not loop too far. The function also sets each square to a blank image. Unfortunately, this cannot be done as conveniently in an array because each control name is unique.

Gameplay cannot begin until the first player clicks on the Button control labeled Play. This causes the btnPlay function, shown next, to execute. This function executes two custom functions. The first function, ClearGameBoard(), you have already examined. The second function, EnableGameBoard(), controls whether you can click the squares on the board. To generate this next button event handler, double-click the Play button in Design view and then add the code shown here:

private: System::Void btnPlay_Click(System::Object^  sender, \
System::EventArgs^  e) {
     //Start with a fresh board
    ClearGameBoard();
     //Set squares as clickable
     EnableGameBoard( true );
     //Disable Play button until done
     btnPlay->Enabled = false;
  }

You must manually add the EnableGameBoard() function, shown next. It causes all squares on the game board to become enabled or disabled:

private: System::Void EnableGameBoard(System::Boolean \
blnEnableBoard ) {
      //Enable or disable all picture
      //  squares based on blnEnableBoard
      if( blnEnableBoard )
      {
        pbxA1->Enabled = true;
        pbxA2->Enabled = true;
        pbxA3->Enabled = true;
        pbxB1->Enabled = true;
        pbxB2->Enabled = true;
        pbxB3->Enabled = true;
        pbxC1->Enabled = true;
        pbxC2->Enabled = true;
        pbxC3->Enabled = true;
      }
      else
      {
        pbxA1->Enabled = false;
        pbxA2->Enabled = false;

        pbxA3->Enabled = false;
        pbxB1->Enabled = false;
        pbxB2->Enabled = false;
        pbxB3->Enabled = false;
        pbxC1->EnabLed = false;
        pbxC2->EnabLed = false;
        pbxC3->Enabled = false;
      }
  }

Players can end the game at any time by clicking on the Button control labeled Exit. When a player does this, the btnExit function, shown next, is executed:

private: System::Void btnExit_Click(System::Object^  sender,\
System::EventArgs^  e) {
     //End the application
     this->C1ose();
  }

Each cell on the game board is made up of a PictureBox control. The following statements make up the click event function for the game's first PictureBox control:

private: System::Void pbxA1_Click(System::Object^  sender,\
System::EventArgs^  e) {
     //Claim square Al according to which
     //  player is active
     if( plyActivePlayer == Player::PLAYERX )
     {
       pbxA1-image = imlSquares->Images[1];
       txtOutput->Text = "X claims square A1!";
       sqsGameBoardArray[0] = SquareStates::SQUAREX;
     }
     if( plyActivePlayer == Player::PLAYERO )
     {
       pbxA1->Image = imlSquares->Images[2];
       txtOutput->Text = "0 claims square A1!";
       sqsGameBoardArray[0] = SquareStates::SQUAREO;
     }
     pbxA1->Enabled = false;
     CheckForWinner();
  }

This code claims the square for the active player, which is stored in plyActivePlayer. Depending on which player it is, the appropriate image is selected, the text displayed in the game's output text box is changed, and the board is set with either a SQUAREX or SQUAREO in the appropriate position. The game then closes off access to the PictureBox control by disabling it. Then it calls the CheckForWinner function to determine if this move was the final winning move.

The code for the other eight PictureBoxes is nearly identical. Double-click each PictureBox in Design view to generate its event handler functions. Because they are so similar, I have grouped them in the following listing:

private: System::Void pbxA2_ClickCSystem::Object^  sender,\
System::EventArgs^  e) {
      //Claim square A2 according to which
      //  player is active
      if( plyActivePlayer == Player::PLAYERX )
      {
        pbxA2->Image = imlSquares->Images[1];
        txtOutput->Text = "X claims square A2!";
        sqsGameBoardArray[1] = SquareStates::SQUAREX;
      }
      if( plyActivePlayer == Player::PLAYERO )
      {
        pbxA2->Image = imlSquares->Images[2];
        txtOutput->Text = "0 claims square A2!";
        sqsGameBoardArray[l] = SquareStates::SQUAREO;
      }
      pbxA2->Enabled = false;
      CheckForWinner();
  }
private: System::Void pbxA3_Click(System::Object^  sender, \
System::EventArgs^  e) {
      //Claim square A3 according to which
      //  player is active
      if( plyActivePlayer == Player::PLAYERX )
      {
        pbxA3->Image = imlSquares->Images[1];
        txtOutput->Text = "X claims square A3!";
        sqsGameBoardArray[2] = SquareStates::SQUAREX;
      }
      if( plyActivePlayer == Player::PLAYERO )

      {
        pbxA3->Image = imlSquares->Images[2];
        txtOutput->Text = "0 claims square A3!";
        sqs6ameBoardArray[2] = SquareStates::SQUAREO;
      }
      pbxA3->Enabled = false;
      CheckForWinner();
  }
private: System::Void pbxB1_Click(System::Object^  sender,\
System::EventArgs^  e) {
      //Claim square B1 according to which
      //  player is active
      if( plyActivePlayer == Player::PLAYERX )
      {
        pbxB1-Image = imlSquares->Images[1];
        txtOutput->Text = "X claims square B1!";
        sqsGameBoardArray[3] = SquareStates::SQUAREX;
      }
      if( plyActivePlayer == Player::PLAYER0 )
      {
        pbxB1->Image = imlSquares->Images[2];
        txtOutput->Text = "0 claims square B1!";
        sqsGameBoardArray[3] = SquareStates::SQUAREO;
      }
      pbxB1->Enabled = false;
      CheckForWinner();
  }
private: System::Void pbxB2_Click(System::Object^  sender,\
System::EventArgs^  e) {
      //Claim square B2 according to which
      //  player is active
      if( plyActivePlayer == Player::PLAYERX )
      {
        pbxB2->Image = imlSquares->Images[1];
        txtOutput->Text = "X claims square B2!";
        sqsGameBoardArray[4] = SquareStates::SQUAREX;
      }
      if( plyActivePlayer == Player::PLAYERO )
      {

        pbxB2->Image = imlSquares->Images[2];
        txtOutput->Text = "0 claims square B2!";
        sqsGameBoardArray[4] = SquareStates::SQUAREO;
      }
      pbxB2->Enabled = false;
      CheckForWinner();
  }
private: System::Void pbxB3_Click(System::Object^  sender,\
System::EventArgs^  e) {
      //Claim square B3 according to which
      //  player is active
      if( plyActivePlayer == Player::PLAYERX )
      {
        pbxB3->Image = imlSquares->Images[1];
        txtOutput->Text = "X claims square B3!";
        sqsGameBoardArray[5] = SquareStates::SQUAREX;
      }
      if( plyActivePlayer == Player::PLAYERO )
      {
        pbxB3->Image = imlSquares->Images[2];
        txtOutput->Text = "0 claims square B3!";
        sqsGameBoardArray[5] = SquareStates::SQUAREO;
      }
      pbxB3->Enabled = false;
      CheckForWinner();
  }
private: System::Void pbxC1_Click(System::Object^  sender,\
System::EventArgs^  e) {
      //Claim square C1 according to which
      //  player is active
      if( plyActivePlayer == Player::PLAYERX )
      {
        pbxCl->Image = imlSquares->Images[1];
        txtOutput->Text = "X claims square C1!";
        sqsGameBoardArray[6] = SquareStates::SQUAREX;
      }
      if( plyActivePlayer == Player::PLAYERO )
      {
        pbxC1->Image = imlSquares->Images[2];

        txtOutput->Text = "0 claims square C1!";
        sqsGameBoardArray[6] = SquareStates::SQUAREO;
      }
      pbxC1->Enabled = false;
      CheckForWinner();
  }
private: System::Void pbxC2_Click(System::Object^   sender,\
System::EventArgs^  e) {
      //Claim square C2 according to which
      //  player is active
      if( plyActivePlayer == Player::PLAYERX )
      {
        pbxC2->Image = imlSquares->Images[1];
        txtOutput->Text = "X claims square C2!";
        sqsGameBoardArray[7] = SquareStates::SQUAREX;
      }
      if( plyActivePlayer == Player::PLAYERO )
      {
        pbxC2->Image = imlSquares->Images[2];
        txtOutput->Text = "0 claims square C2!";
        sqsGameBoardArray[7] = SquareStates::SQUAREO;
      }
      pbxC2->Enabled = false;
      CheckForWinner();
  }
private: System::Void pbxC3_Click(System::Object^  sender,\
System::EventArgs^  e) {
      //Claim square C3 according to which
      //  player is active
      if( plyActivePlayer == Player::PLAYERX )
      {
        pbxC3->Image = imlSquares->Images[1];
        txtOutput->Text = "X claims square C3!";
        sqsGameBoardArray[8] = SquareStates::SQUAREX;
      }
      if( plyActivePlayer == Player::PLAYERO )
      {
        pbxC3->Image = imlSquares->Images[2];
        txtOutput->Text = "0 claims square C3!";

        sqsGameBoardArray[8] = SquareStates::SQUAREO;
      }
      pbxC3->Enabled = false;
      CheckForWinner();
  }

Each time a move is made, the game must determine if it was the winning move by analyzing every square on the board. Fortunately, it does this instantly. To add this behavior, create the custom function illustrated here:

private: System::Void CheckForWinner(System::Void) {
     //Set a variable to track the winning player
     Player plyWinningPlayer = Player::PLAYERNONE;
     //Establish a generic counter for looping
     //  through game board
     Int32 intCounter = 0;
     //Check rows for X or 0 win
     for( intCounter = 0; intCounter <
          sqsGameBoardArray->Length;  intCounter += 3 )
     {
       //Check if Xs win
       if( sqsGameBoardArray[intCounter] ==
         SquareStates::SQUAREX )
         if( sqsGameBoardArray[intCounter + 1] ==
             SquareStates::SQUAREX )
           if( sqsGameBoardArray[intCounter + 2] ==
               SquareStates::SQUAREX )
             plyWinningPlayer = Player::PLAYERX;
       //Check if Os win
       if( sqsGameBoardArray[intCounter] ==
         SquareStates::SQUAREO )
         if( sqsGameBoardArray[intCounter + 1] ==
             SquareStates::SQUAREO )
           if( sqsGameBoardArray[intCounter + 2] ==
               SquareStates::SQUAREO )
             plyWinningPlayer = Player::PLAYERO; )
     }
     //Check columns for X or 0 win
     for( intCounter - 0; intCounter <
          sqsGameBoardArray->Length / 3;  intCounter += 1 )
     {

       //Check if Xs win
       if( sqsGameBoardArray[intCounter] ==
           SquareStates::SQUAREX )
        if( sqsGameBoardArray[intCounter + 3] ==
            SquareStates::SQUAREX )
          if( sqsGameBoardArray[intCounter + 6] ==
              SquareStates::SQUAREX )
            plyWinningPlayer = Player::PLAYERX:
       //Check if Os win
       if( sqsGameBoardArray[intCounter] ==
           SquareStates::SQUAREO )
        if( sqsGameBoardArray[intCounter + 3] ==
            SquareStates::SQUAREO )
          if( sqsGameBoardArray[intCounter + 6] ==
              SquareStates::SQUAREO )
            plyWinningPlayer = Player::PLAYERO;
     }
     //Check diagonals if X or 0 has claimed the center
     if( sqsGameBoardArray[4] != SquareStates::SQUAREOPEN )
     {
       //Check if X or 0 wins upper left to
       //  lower right
       if( sqsGameBoardArray[0] == SquareStates::SQUAREX &&
         sqsGameBoardArray[4] == SquareStates::SQUAREX &&
         sqsGameBoardArray[8] == SquareStates::SQUAREX )
         plyWinningPlayer = Player::PLAYERX:
       if( sqsGameBoardArray[0] == SquareStates::SQUAREO &&
         sqsGameBoardArray[4] == SquareStates::SQUAREO &&
         sqsGameBoardArray[8] == SquareStates::SQUAREO )
         plyWinningPlayer = Player::PLAYERO;
       //Check if X or 0 wins lower left to
       //  upper right
       if( sqsGameBoardArray[6] == SquareStates::SQUAREX &&
         sqsGameBoardArray[4] == SquareStates::SQUAREX &&
         sqsGameBoardArray[2] == SquareStates::SQUAREX )
         plyWinningPlayer = Player::PLAYERX;
       if( sqsGameBoardArray[61 == SquareStates::SQUAREO &&
         sqsGameBoardArray[4] == SquareStates::SQUARED &&
         sqsGameBoardArray[2] == SquareStates::SQUAREo )
         plyWinningPlayer = Player::PLAYERO;

     }
     //If neither player has won, check to see if board is
     //  filled
     if( plyWinningPlayer == Player::PLAYERNONE )
     {
      for( intCounter = 0; intCounter <
           sqsGameBoardArray->Length; intCounter += 1 )
        if( sqsGameBoardArray[intCounter] ==
            SquareStates::SQUAREOPEN )
        {
           //Found at least one open square, so
           //  the game continues
           SwapPlayerTurn();
           return;
         }
     }
     //No open squares; either someone won or it's a tie
     EndGame( plyWinningPlayer );
  }

The first step that the function takes is to create an instance of a player named plyWinningPlayer. This object keeps track of who the winner of the game is as each square is examined. The function also creates a counter to handle looping through the board several times.

The first search is made by row. A for loop is designed to skip across each row. Within its code bock, a test is made first for X and then for O each iteration. The test involves looking not only at whether the current square specified by intCounter has an X or O value, but also whether its two neighbors share the same value. Because intCounter is designed to skip by threes, this ensures that each row is read as a block of three positions.

If neither X nor O has claimed any of the three rows, the search switches to check each column. To understand how this works, think of the squares of a Tic-Tac-Toe board as being numbered, starting with a zero in the upper-left corner and ending with an eight in the lower right. If you look at any square in the top row, you will see that the next row is only three squares (counting from left to right) from the square in the same column below it. The same square in the bottom row is always only six squares from the square in the top row. This function exploits that fact by searching columns in groups of three.

If neither side has claimed the columns, the only possible positions are the two diagonal reaches, from upper left to lower right and upper right to lower left. This is possible only if the center square is claimed, so the function first checks for this fact and then checks the appropriate game squares. If a winner is still not found, then the game is a tie, or there is still a move left to make. The remainder of the logic accounts for these two options. A for loop searches for an open square. If it finds one, it calls for the players to be swapped and continues the game. But if no open square is found, a function is called that ends the game.

Finally, the game calls the EndGame function. This is a custom function whose code is shown next:

Private Sub Determine_Game_Status(ByVal strGameOver As String)
private: System::Void EndGame(Player plyWinner) {
      //Declare winner
      if( plyWinner == Player::PLAYERX )
        MessageBox::Show( "Player X wins!" );
      if( plyWinner == Player::PLAYERO )
        MessageBox::Show( "Player 0 wins!" );
      if( plyWinner == Player::PLAYERNONE )
        MessageBox::Show( "Game is a Tie!" );
      //Reset game and allow replay
      SetGameDefaults();
      EnableGameBoard( false );
      ClearGameBoard();
      btnPlay->Enabled = true;
      txtOutput->Text = "Click Play to start again.";
  }

The function uses if statements to match the winner with the appropriate Player value. Notice again that rather than having to compare plyWinner to a number whose meaning you might forget, the enumerated class Player provides a clear way of making comparisons and assignments.

The Switch_Players function, shown next, is straightforward. When called, it changes the value of plyActivePlayer, which determines who the active player is. It also updates the output of text in the game's output box to alert the players to this fact:

private: System::Void SwapPlayerTurn(System::Void) {
      //Switch current player
      if( plyActivePlayer == Player::PLAYERX )
      {
       plyActivePlayer = Player::PLAYERO;
       txtOutput->Text = String::Concat( txtOutput->Text,
       "  It is Player 0's turn." );
      }

      else
      {
       plyActivePlayer = Player::PLAYERX;
       txtOutput->Text = String::Concat( txtOutput->Text,
       "  It is Player X's turn." );
      }
  }

Step 5: Testing the Execution of the Tic-Tac-Toe Game

The Tic-Tac-Toe game is ready to run. Go ahead and test it by pressing F5. Does everything work like it is supposed to? If you run into problems, try using the troubleshooting tips presented in this chapter to track down errors. After things are in order, try it with a few friends.


SUMMARY

In this chapter, you learned about syntax, logic, and runtime errors. You discovered how to set breakpoints and step through program execution. You also found out how to work with an assortment of debugging windows and to create exception-handling routines. In addition to all of this, you created the Tic-Tac-Toe game.

Don't look at the completion of the material in this book as the end of your Visual C++ programming education. Think of it as a launching point. Although this book has given you a solid foundation, there is still plenty more to learn. Before you run off and start tackling new and bigger programming projects, why not take just a little extra time and improve the Tic-Tac-Toe game by completing the following challenges?


CHALLENGES

  1. Add sound effects to the game that indicate when the game has been won or tied.

  2. Add logic to the game that keeps track of the number of games won, lost, and tied for each player.

  3. Add logic to the game that identifies not only when a game has been won, but how it was won (diagonally, horizontally, or vertically).


Appendix A: What's on the Companion Web Site?

The companion Web site contains all the material you need to get each of the chapter games up and running. It is organized by chapter and contains the source code and the executable files. In addition, you will find that for the games requiring art all files are located in the appropriate project directory. You can access the companion Web site by navigating to http://www.courseptr.com/ and typing the book's title in the Search box that is located in the upper-right corner of the page.

The chapter projects on the companion Web site are organized as follows:

  • The Joke Machine

  • Click Race Game

  • The Speed Typing Game

  • Lottery Assistant

  • The Story of Mighty Molly

  • Guess A Number

  • Dice Poker

  • Hangman Game

  • Rock Paper Scissors Game

  • VC++ Doodle

  • Tic-Tac-Toe

You can create each chapter game by copying the appropriate folder to your hard drive and double-clicking the project file. Project files have the same name as the folder and end in the extension .sln. Double-clicking the project file automatically launches Visual C++ 2005 Express Edition so that you can examine the project and make any desired changes.

Alternatively, if you're simply interested in running a chapter program, you can click on its executable file. Executable files have the same name as the folder and end in the extension.exe.


Appendix B: What's Next?

OVERVIEW

Congratulations! If you've been reading the chapters and doing the exercises and have made it this far, you're well on your way to becoming a proficient Visual C++ programmer. Even if you've mostly been skimming or don't understand all that you've read, you're still on your way to mastering the language. Why? Because you've started!

By taking on the challenge of learning Microsoft Visual C++ 2005 Express Edition, you have opened the door to a wide world of learning. The material and program examples in this book are just the beginning. I recommend that you continue with your education by experimenting and practicing what you've learned. Challenge yourself to build small programs that allow you to test an area of your understanding thoroughly. By trying new avenues—and even making plenty of mistakes—your understanding of Visual C++ will grow by leaps and bounds.


LOCATING VISUAL C++ 2005 EXPRESS RESOURCES ONLINE

As .NET becomes more popular, the number of tutorials and help resources available will continue to grow. When you're ready to tap into the power of the Internet and World Wide Web, you will find numerous resources waiting. These include online communities that you can join and Web sites that you can browse. The sections in this appendix are just a sample of what's available online.

Making Use of Usenet Newsgroups

Usenet is one of the oldest and most widely used discussion boards on the Internet. You can access it through one of the many popular newsreaders, such as Agent. Or you can use Google's Groups Web site to view and search the groups you want.

If you're not familiar with Usenet, it is a loose collection of servers that host discussions on almost every conceivable topic you can imagine. It is completely free to use and open to the public. All you need to know is the newsgroup you're interested in, and you can point your newsreader or Google's Groups Web site to the boards containing the discussions.

You can find some of the most useful .NET-related material in groups that are heavily supported by Microsoft. The articles you will find in the Microsoft groups often contain answers to frequently asked questions and discussions about how to use .NET features.

Here is a listing of some of the most active .NET-related groups:

  • microsoft.public.dotnet.general. One of the most .NET-related discussion groups on Usenet, this group is a catchall for all the .NET languages and technologies.

  • microsoft.public.dotnet.vc. This group is devoted to Visual C++, including Microsoft Visual C++ 2005 Express Edition and older versions.

  • microsoft.public.dotnet.interop. This group is devoted to the techniques and philosophy behind getting the various .NET languages to work together.

  • microsoft.public.dotnet.windowsforms. This group is the best place to frequent if you have questions or are interested in discussions about WinForms.

  • microsoft.public.dotnet.windowsforms.controls A subgroup of the WinForms group, this discussion board hosts questions and talks on the technology behind the controls that you use in your forms.

  • microsoft.public.dotnet.windowsforms. This group contains a great deal of information on using Windows Forms.

Usenet is organized in a hierarchical fashion. Each label preceding a period is a group, and the label following it is a subgroup. As you can see with the final bullet, microsoft is a main group, followed by the subgroup public, and then dotnet, and so on.

Unfortunately, most Usenet providers keep these topics on their servers for only a limited time. The length varies with each Internet Service Provider, but it's usually no longer than a few months. Because of this, if you don't frequent the boards, you might miss out on some good information.

Fortunately, Google archives a vast number of posts for many (although not all) of the groups that are available. If you point your browser to http://www.google.com and select the Google Groups option, you will have a powerful research tool at your fingertips. By placing a topic in the Search field, you can access valuable information that you might have to search for extensively elsewhere. Or you can select the option on this page entitled Browse All of Usenet, which allows you to click directly to access the groups you are interested in.

Google Groups also contains an Advanced Search option that allows you to narrow your search to specific boards. In the Search field, you can select the topic of interest and type group: followed by a newsgroup's name. For example, if you were interested in information forms in general, you might type the word forms into the Search field followed by group:microsoft.public.dotnet. Because Usenet is organized in a hierarchical, tree-like fashion, you can also perform searches of subgroups, using an asterisk as a wildcard in place of a subgroup's name. For example, if you wanted to search all groups beneath the microsoft.public.dotnet level, you would type the word or words you were looking for followed by microsoft.public.dotnet*, which incidentally might include a great many hits.

Some Useful Web Sites

There is a vast number of .NET-related Web sites on the World Wide Web. As more programmers are adopting the .NET technologies and employing the Visual Studio languages, more Web sites are becoming available. Because it is really impossible to catalog them all, I'll just briefly clue you in on some of the ones I know of.

General Information

Here are some Web sites devoted to hosting general .NET information:

  • http://msdn.microsoft.com/vstudio/express/visualc/. You might already be aware of Microsoft's general Visual Studio Express site, but if not, this one is useful to bookmark. This site contains information on the various Visual Studio Express options, including an overview of .NET and the specifics of each of the language technologies available to you.

  • http://www.gotdotnet.com. This Microsoft-supported site contains a large developer community and many articles on the .NET Framework. There are a huge number of blogs, articles, and resources available, and the site is growing rapidly.

  • http://www.codeproject.com. This general programming Web site hosts a large number of easy-to-search-for articles covering everything from general programming tips to specific solutions to common problems. You can find the .NET-specific material at http://www.codeproject.com/dotnet/dotnet.asp.

  • http://msdn.microsoft.com/visualc/. When you're ready to explore Visual C++ in more depth, this Web site is a handy resource. The official home page of Visual C++, it contains a wealth of technical and industry-related articles that will help you improve your programming skills and get the most out of your development tools.

Game and Hobby Specific

Here are some game- and hobby-specific .NET programming Web sites that you might find useful:

  • http://msdn.microsoft.com/coding4fun/. Microsoft built this Web site for enthusiasts and first-time programmers. It contains a wide variety of hints and help for creating demos, small games, and school projects.

  • http://www.gamedev.net. This is a well-run Web site containing a numerous articles and information relating to game development. One of its best features is its discussion boards, which are backed by an active member community of thousands and a helpful, friendly moderating staff. The site features a specific .NET forum in which anyone can participate.


USING THE MICROSOFT DEVELOPER NETWORK

The Microsoft Developer Network is a body of online and offline articles, services, and information. It is designed to aid developers in writing applications using Microsoft products and technologies. The service is quite expensive and includes software and even technical support. However, one of the most useful aspects of the Microsoft Developer Network, the Microsoft Developer Network Library, is absolutely free.

In the MSDN Library are thousands of articles spread over dozens of interconnecting Web sites. The result is an immense storehouse of information that includes a knowledgebase of common issues and questions and documentation on every feature of the .NET Framework.

To access the Web site, open your browser and navigate to http://www.msdn.microsoft.com. The home page contains links to different technologies. The most useful feature, however, is Search. You can search magazine articles, theoretical and technical information related to every Microsoft technology, and helps and hints.

Because the service is so vast, one of the downsides is that it can be easy to get lost. The search facility is not as discriminatory as it needs to be. (I recommend using Google to search the site, because you'll have more options.) Because of this, I've provided a number of jumping-off points that you might find useful:

  • http://msdn.microsoft.com/library/default.asp. This is the home page of the MSDN Library. It can be helpful for exploring Visual C++ and NET's many features. Click the .NET Development option in the left frame to start your exploration of the technology.

  • http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpqstart/html/cpsmpwindowsformsquickstart.asp. This is an excellent starter page on learning how to use forms in Windows applications. It is designed to acquaint you with how the technology works and how it relates to your programs.

  • http://msdn.microsoft.com/visualc/using/multimedia/newc/default.aspx. This page links to a superb Webcast series that gives a broad overview of Visual C++ and .NET and is especially practical for users of previous versions of Visual C++ and .NET because it quickly familiarizes you with the changes in the technology.

  • http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/VSO5Cplus.asp. This page is a technical article outlining how Visual C++ fits into the .NET Framework.

These are but a small handful of the possible resources available. The MSDN Library is growing and changing, so you're sure to find even more in the months ahead.


Index

A

About menus, 139–140
abstraction (classes), 284
access keys (menus), 112
adding. See also creating
breakpoints, 340–342
buttons, 21
code, 23
controls, 20–21
dialog boxes, 78–84
labels, 20
menu systems, 106–109
menus
access keys, 112
check marks, 113–114
items, 108
separator bars, 114–115
shortcut keys, 111
submenus, 108
sound, 318–321
Status Strips, 72–76
text boxes, 21
toolbars, 120–122
Align command (Format menu), 36
alignment. See also moving
Align command (Format menu), 36
controls, 22, 35–36
dialog boxes, 82
windows/forms, 35–36, 66–67
alternatives (.NET Framework), 13
anchoring controls, 324
ANSI/ISO Standard (.NET Framework), 8
applications. See also projects
code (storing), 36–37
debug versions, 84, 340
development speed, 181
menus. See menus
.NET Framework. See .NET Framework
release versions, 84–85
running, 20
runtime versions, 84–85
sound, 318–321
standalone, 84–85
toolbars
adding, 120–122
buttons, 121–122, 124–125
code, 124–125
commands, 33–34
customizing, 32, 34
event handling, 124–125
graphics, 122–123
.NET Framework, 120
overview, 33–34
Standard, 33
styles, 122
text, 121–122
ToolTips, 122
troubleshooting. See troubleshooting code
windows/forms. See windows/forms
arguments (functions), 246
default arguments, 253–254
passing, 251–254
arrays
defined, 146, 159
defining, 150–160
elements, 150–160
indexes, 159, 236
loops, 160
overview, 158–159
troubleshooting, 160
asterisks (windows/forms), 35
ATL support, 10
audio. See sound
AutoDock, 30–31
autohide (windows/forms), 31–32


Previous Page
Next Page

Index

B

backslashes
code, 24
troubleshooting, 320
Bookmark window, 50
borders (windows/forms), 67–68
break statements (loops), 215–216
breakpoints (debugging)
adding, 340–342
deleting, 342
overview, 340
stepping, 342–343
bugs (troubleshooting), 160
building projects, 25
buttons
adding, 21
code, 124–125
dialog boxes, 80–81, 83–84
event handling, 124–125
size, 122
toolbars, 121–122, 124–125
ToolTips, 122


Previous Page
Next Page

Index

C

Call Browser window, 50
calling functions, 245
camelCase naming conventions, 88
capitalization
camelCase, 88
menus, 109
case sensitivity (declaring variables), 152
Center in Form command (Format menu), 36
check marks (menus), 113–114
CheckBox control, 192
class library (.NET Framework), 14–15
Class View window, 50
classes
abstraction, 284
class library, 14–15
constants, 287–288
creating, 286–289
data types, 286–287
DateTime functions, 254–256
defined, 284
defining, 289
encapsulation, 284–285
enum, 287–288
event handling, 330
Graphics
CreateObjects function, 311–312
DrawString function, 317–318
functions, 311–313, 315–317
inheritance, 285
instantiating, 286
MessageBox (Show function), 78–84, 285
.NET Framework, 14–15, 254–257
objects relationship, 14, 283–284, 286
overview, 283–284
Pen functions, 313–314
Point, 327
polymorphism, 285
ref, 288–289
SoundPlayer, 319–320
System (Drawing function), 327
SystemSounds, 320–321
types, 286
value, 286–287
click events, 124–125
Click Race
code, 55–59
controls, 51, 53–55
creating, 51
design, 50–51
GUIs, 51–53
preview, 27–29
testing, 60
windows/forms, 51, 53–55
clicking (controls), 20–21
closing windows/forms, 31–32
CLR (Common Language Runtime), 14–16
code. See also Code Editor
applications, storing, 36–37
arrays
defined, 146,159
defining, 150–160
elements, 150–160
indexes, 159, 236
loops, 160
overview, 158–159
troubleshooting, 160
backslashes, 24
buttons (toolbars), 124–125
camelCase, 88
classes. See classes
Click Race, 55–59
color, 39
comments, 57, 143–145
compiling, 4, 15
constants
creating, 287–288
declaring, 147–148
defined, 145
overview, 146
controls. See controls
cursors, 37
customizing, 36
deleting, 56
Dice Poker, 225–239
functions. See functions
Guess a Number, 196–205
Hangman, 266–277
indentation, 39
IntelliSense, 40–42
Lottery Assistant, 132–140
menus, 109–110
namespaces, 80
naming conventions, 88
numbers, 132–136
OOP, 37–38
reserved words, 162–163
Rock, Paper and Scissors, 297–305
spacing, 39
Speed Typing, 91–99
storing, 36–37
Story of Mighty Molly, 169–175
strings, 132–136
Tic-Tac-Toe, 352–364
troubleshooting. See troubleshooting code
variables. See variables
VC++ Doodle, 326–333
windows/forms. See windows/forms
Code Editor. See also code
code, adding, 23
color, 39
cursors, 37
customizing, 36
indentation, 39
Members list, 37
OOP, 37–38
overview, 36–37
Scopes list, 37
size, 24
spacing, 39
windows/forms, selecting, 37
color
Code Editor, 39
menus, 137–138
COM components, 44
ComboBox control, 184–185
Command window, 50
commands
menus. See menus
toolbars, 33–34
comments, 57, 143–145
Common Language Runtime (CLR), 14–16
comparison operators, 189
compatibility
DirectX, 10
.NET Framework, 7–8, 12
Win32, 10
compiling, defined, 4, 15
Component Tray (controls), 48–49
components (.NET Framework), 14–16
conditional logic
if statements
ComboBox control, 184–185
if…else if statements, 184–185
if…else statements, 182–184
multiline, 182
nesting, 185–187
operators, 189
overview, 180–181
pseudo-code, 180–181
single-line, 181–182
String Collection Editor, 184–185
syntax, 181
operators, 189
overview, 177,179
switch statements, 187–188
conditions (loops), 212–213
Configuration Manager, 85
constants
creating, 287–288
declaring, 147–148
defined, 145
overview, 146
context menus, 118–120
continue statements (loops), 216–217
controls
adding, 20–21
alignment, 22
anchoring, 324
buttons
adding, 21
code, 124–125
dialog boxes, 80–81, 83–84
event handling, 124–125
size, 122
toolbars, 121–122, 124–125
ToolTips, 122
CheckBox, 192
clicking, 20–21
code
Joke Machine, 23–25
ComboBox
statements, 184–185
Component Tray, 48–49
creating
Click Race, 51
Dice Poker, 217–218
Guess a Number, 190–191
Hangman, 257–258
Joke Machine, 20–21
Lottery Assistant, 125–126
Rock, Paper and Scissors, 290–291
Speed Typing, 86
Story of Mighty Molly, 163–164
Tic-Tac-Toe, 346
VC++ Doodle, 322
event handling, 330
focus, 70–72, 93
GroupBox, 191–192
ImageList, 122–123, 220, 225
labels, 20
MenuStrip control. See menus
moving, 20–21
NotifyIcon, 76–78
organizing, 259
Panel, 259, 324
PictureBox, 220
graphics, 310–311
ProgressBar, 295
properties
Click Race, 53–55
Dice Poker, 221–225
Guess a Number, 193–196
Hangman, 260–266
Joke Machine, 21–22
Lottery Assistant, 127–131
overview, 45–48
Rock, Paper and Scissors, 293–297
Speed Typing, 87–90
Story of Mighty Molly, 165–169
Tic-Tac-Toe, 348–351
VC++ Doodle, 324–326
RadioButton, 192
size, 20–21
Status Strips, 72–76, 99
storing, 259
tabs, 70–72
text boxes, 21
Timer, 49
ToolBar. See toolbars
Toolbox
COM components, 44
grouping, 44
moving, 42
.NET Framework, 44
viewing/hiding, 42–44
ToolTips, 86, 89–90
windows/forms
alignment, 35–36
guides, 35–36
locking, 36
moving, 35–36
conventions (declaring variables), 152–153
Convert object (ToDateTime function), 255
coordinates
graphics, 310–317
storing, 327
Course Technology Web site, 225
crashes (troubleshooting), 134, 160
CreateObjects function (Graphics class), 311–312
creating. See also adding
classes, 286–289
constants, 287–288
controls
Click Race, 51
Dice Poker, 217–218
Guess a Number, 190–191
Hangman, 257–258
Joke Machine, 20–21
Lottery Assistant, 125–126
Rock, Paper and Scissors, 290–291
Speed Typing, 86
Story of Mighty Molly, 163–164
Tic-Tac-Toe, 346
VC++ Doodle, 322
data types, 286–287
functions, 244–250, 318
GUIs
Click Race, 51–53
Dice Poker, 219–220
Guess a Number, 190–193
Hangman, 259–260
Joke Machine, 20–21
Lottery Assistant, 126–127
Rock, Paper and Scissors, 290–292
Speed Typing, 87
Story of Mighty Molly, 164–165
Tic-Tac-Toe, 347–348
VC++ Doodle, 323–324
projects
Click Race, 51
Dice Poker, 217–219
Guess a Number, 190–191
Hangman, 257–259
Lottery Assistant, 125–126
Joke Machine, 16–20
Rock, Paper and Scissors, 290–291
Speed Typing, 85–86
Story of Mighty Molly, 163–164
Tic-Tac-Toe, 345–347
VC++ Doodle, 322–323
release versions, 84–85
runtime versions, 84–85
standalone versions, 84–85
windows/forms
Click Race, 51
Dice Poker, 217–218
Guess a Number, 190–191
Hangman, 257–258
Lottery Assistant, 125–126
Rock, Paper and Scissors, 290–291
Speed Typing, 86
Story of Mighty Molly, 163–164
Tic-Tac-Toe, 346
VC++ Doodle, 322
cursors (code), 37
customizing
code, 36
Code Editor, 36
functions (defining), 248–250
toolbars, 32, 34
windows/forms, 32


Previous Page
Next Page

Index

D

data
retrieving, 145–146
returning (functions), 246
storing, 145–146
data types
arrays
defined, 146,159
defining, 150–160
elements, 150–160
indexes, 159, 236
loops, 160
overview, 158–159
troubleshooting, 160
constants
creating, 287–288
declaring, 147–148
defined, 145
overview, 146
creating (classes), 286–287
functions, 249
overview, 145–147
structures
defined, 146
overview, 160–162
variables. See variables
date/time, 254–256
DateTime class, 254–256
debug versions (applications), 84, 340
debugging breakpoints. See also error handling
adding, 340–342
deleting, 342
overview, 340
stepping, 342–343
declaring. See also names
constants, 147–148
variables, 149–150
case sensitivity, 152
conventions, 152–153
scope, 152–153
strings, 156–157
default arguments (functions), 253–254
defining
arrays, 150–160
classes, 289
functions, 248–250
variables, 149–150
local, 150–151
scope, 152
static, 151–152
deleting
breakpoints (debugging), 342
code, 56
menus
check marks, 113–114
items, 109
design
Click Race, 50–51
Dice Poker, 217–218
Guess a Number, 190–191
GUIs, 65–66
Hangman, 257–258
Joke Machine, 16
Lottery Assistant, 125–126
menu systems, 104–106
Rock, Paper and Scissors, 290–291
Speed Typing, 85–86
Story of Mighty Molly, 163–164
Tic-Tac-Toe, 346
VC++ Doodle, 322
developing applications
.NET Framework, 14
speed, 181
dialog boxes
adding, 78–84
alignment, 82
buttons, 80–81, 83–84
icons, 80–81
Import and Export Settings Wizard, 31
MessageBox class Show function, 78–84
parameters, 79–84
text, 79, 82–83
user input, 83
viewing/hiding, 82
Dice Poker
code, 225–239
controls
creating, 217–218
properties, 221–225
creating, 217–219
design, 217–218
GUIs, 219–220
preview, 207–210
testing, 239
windows/forms
creating, 217–218
properties, 221–225
DirectX compatibility, 10
do…while loops, 212–213
docking windows/forms, 31–32
DoubleTryParse function, 133
downloading Visual C++, 8
dragging. See moving
drawing. See graphics
Drawing function (System class), 327
DrawString function (Graphics class), 317–318


Previous Page
Next Page

Index

E

elements (arrays), 150–160
ellipses (menus), 109
enabling/disabling (menus), 115–116
encapsulation (classes), 284–285
endless loops, 214
enum class, 287–288
error handling. See also debugging breakpoints
logical errors, 338–339
overview, 337
runtime errors (exceptions), 339–340, 343–345
syntax errors, 338
Error List window, 50
errors (variables), 152
event handling
classes, 330
controls, 330
functions, 247–248, 318
toolbar buttons, 124–125
exceptions. See runtime errors
Exit menus, 137
exiting loops, 215–217
expectations (menus), 106


Previous Page
Next Page

Index

F

files
finding (Solution Explorer), 44–45
wave files (sound), 319
finding files (Solution Explorer), 44–45
focus, controls, 70–72, 93
folders, moving, 19
font size (menus), 138–139
for loops, 213–214
Form Designer. See windows/forms
Format menu commands, 36
forms. See windows/forms
functions (methods), 157
arguments, 246
default arguments, 253–254
passing, 251–254
calling, 245
code, 56
Convert object, 255
CreateObjects, 311–312
creating, 244–250, 318
custom. See defining
data types, 249
DateTime class, 254–256
defined, 244
defining, 248–250
Double TryParse, 133
Drawing, 327
DrawString, 317–318
event handling, 247–248, 318
Graphics class, 311–313, 315–318
Int32 Parse, 134
MessageBox class, 78–84, 285
names, 248–249
.NET Framework, 254–257
Next function, 199
Now, 254–255
OOP, 249
overloading, 285
overview, 241, 244–245
parameters, 246, 249, 251
Pen class, 313–314
private, 249
protected, 249
public, 249
Random object, 199
return types, 249
returning data, 246
Show, 78–84, 285
String object, 256–257
strings
manipulating, 256–257
variables, 155–158
stubbing, 250
Subtract, 255–256
syntax, 244
System class, 327
TimeSpan object, 255–256
ToDateTime, 255
ToString, 154


Previous Page
Next Page

Index

G

games
projects. See projects
Web site, 9
garbage collection (memory), 156
GDI+, 310–317
Graphical User Interfaces. See GUIs
graphics
coordinates, 310–317
GDI+, 310–317
overview, 307
PictureBox control, 310–311
pixels, 310
storing, 220, 225
text, 317–318
toolbars, 122–123
vectors, 311–317
viewing/hiding, 220
Graphics class
CreateObjects function, 311–312
DrawString function, 317–318
functions, 311–313, 315–317
GroupBox control, 191–192
grouping
menu items, 114–115
Toolbox controls, 44
Guess a Number
code, 196–205
controls
creating, 190–191
properties, 193–196
creating, 190–191
design, 190–191
GUIs, 190–193
preview, 177–179
testing, 205
windows/forms
creating, 190–191
properties, 193–196
guides (controls), 35–36
GUIs (Graphical User Interfaces). See also windows/forms
controls. See controls
creating
Click Race, 51–53
Dice Poker, 219–220
Guess a Number, 190–193
Hangman, 259–260
Joke Machine, 20–21
Lottery Assistant, 126–127
Rock, Paper and Scissors, 290–292
Speed Typing, 87
Story of Mighty Molly, 164–165
Tic-Tac-Toe, 347–348
VC++ Doodle, 323–324
defined, 4
design, 65–66
menus. See menus
overview, 4–5, 63
RAD, 5
toolbars
adding, 120–122
buttons, 121–122, 124–125
code, 124–125
commands, 33–34
customizing, 32, 34
event handling, 124–125
graphics, 122–123
.NET Framework, 120
overview, 33–34
Standard, 33
styles, 122
text, 121–122
ToolTips, 122
windows/forms. See windows/forms


Previous Page
Next Page

Index

H

handling events. See event handling
Hangman
code, 266–277
controls
creating, 257–258
properties, 260–266
creating, 257–259
design, 257–258
GUIs, 259–260
preview, 242–243
testing, 277
windows/forms
creating, 257–258
properties, 260–266
help, Visual C++ 2005 Express, 367–371
history
.NET Framework, 7, 13
Visual C++, 6–8


Previous Page
Next Page

Index

I

icons
dialog boxes, 80–81
System Tray, 76–78
IDE (Integrated Development Environment), 27
Component Tray (controls), 48–49
overview, 27, 30–32
restoring, 31
identifiers (variables), 149
if…else if statements, 184–185
if…else statements, 182–184
if statements
ComboBox control, 184–185
if…else if statements, 184–185
if…else statements, 182–184
multiline, 182
nesting, 185–187
operators, 189
overview, 180–181
pseudo-code, 180–181
single-line, 181–182
String Collection Editor, 184–185
syntax, 181
ImageList control, 122–123, 220, 225
images. See graphics
Import and Export Settings command (Tools menu), 31
Import and Export Settings Wizard, 31
indentation (code), 39
indexes (arrays), 159, 236
infinite loops, 214
inheritance (classes), 285
initializing. See defining
input (users)
dialog boxes, 83
focus. See focus
Status Strips, 75
Insert Standard Items (menus), 109
installing Visual C++, 8
instantiating classes, 286
Int32 Parse function, 134
Integrated Development Environment. See IDE
IntelliSense, 40–42
interfaces. See GUIs
interoperability
DirectX, 10
.NET Framework, 7–8, 12
Win32, 10
items (menus)
adding, 108
code, 109–110
deleting, 109
enabling/disabling, 115–116
grouping, 114–115
moving, 109
viewing/hiding, 117–118
Items Collection Editor, 74–75
iterative processing. See loops


Previous Page
Next Page

Index

J

Joke Machine
controls
code, 23–25
creating, 20–21
properties, 21–22
creating, 16–20
design overview, 16
GUIs, 20–21
preview, 2–3
testing, 25


Previous Page
Next Page

Index

K

keyboards
access keys, 112
shortcut keys, 111
keyword, this, 69


Previous Page
Next Page

Index

L

labels, 20
local variables, 150–151
Lock Controls command (Format menu), 36
locking controls, 36
logic
conditional. See conditional logic
programming. See code
logical errors (error handling), 338–339
loops
arrays, 160
conditions, 212–213
defined, 210
do…while, 212–213
exiting, 215–217
for, 213–214
infinite, 214
overview, 210–211
statements, 213
break, 215–216
continue, 216–217
types, 211
while, 211–213
Lottery Assistant
code, 132–140
controls
creating, 125–126
properties, 127–131
creating, 125–126
design, 125–126
GUIs, 126–127
menus, 129–131
preview, 102–104
testing, 140
windows/forms
creating, 125–126
properties, 127–131


Previous Page
Next Page

Index

M

managing projects (Solution Explorer), 44–45
manipulating strings (functions), 256–257
Members list (Code Editor), 37
memory (garbage collection), 156
menu systems
adding, 106–109
design, 104–106
names, 107
menus
About, 139–140
access keys, 112
AutoDock, 30–31
capitalization, 109
check marks, 113–114
code, 109–110
colors, 137–138
commands, 32–33
context menus, 118–120
ellipses, 109
enabling/disabling, 115–116
Exit menus, 137
font size, 138–139
Format menu commands, 36
Insert Standard Items, 109
items
adding, 108
code, 109–110
deleting, 109
enabling/disabling, 115–116
grouping, 114–115
moving, 109
viewing/hiding, 117–118
Lottery Assistant, 129–131
menu systems
adding, 106–109
design, 104–106
names, 107
separator bars, 114–115
shortcut keys, 111
spelling, 109
submenus, 108
templates, 109
Tools menu commands, 31–32
user expectations, 106
viewing/hiding, 117–118
Window menu commands, 31
MenuStrip control. See menus
MessageBox class (Show function), 78–84, 285
methods. See functions
MFC support, 10
Microsoft Developer Network, 370–371
Microsoft Web site
downloading, 8
games, 9
.NET Framework, 16
projects, 9
moving
alignment
Align command (Format menu), 36
controls, 22, 35–36
dialog boxes, 82
windows/forms, 35–36, 66–67
controls, 20–21
alignment, 22, 35–36
Toolbox, 42
windows/forms, 35–36
menu items, 109
project folders, 19
windows/forms, 35–36, 66–67
multiline if statements, 182


Previous Page
Next Page

Index

N

names. See also declaring
camelCase, 88
code conventions, 88
functions, 248–249
menu systems, 107
projects, 18–19
namespaces, 80, 284
nesting if statements, 185–187
.NET Framework
alternatives, 13
ANSI/ISO Standard, 8
application development process, 14
classes
functions, 254–257
library, 14–15
CLR, 15–16
compatibility, 7–8, 12
components, 14–16
controls (Toolbox), 44
history, 7, 13
overview, 12–16
toolbars, 120
Web site, 16
Next function (Random object), 199
NotifyIcon control, 76–78
Now function (DateTime class), 254–255
numbers (code), 132–136


Previous Page
Next Page

Index

O

Object-Oriented Programming. See OOP
objects. See also OOP
classes relationship, 14, 283–284, 286
Convert object, 255
overview, 283–284
properties, 69
Random, 199
String, 256–257
TimeSpan object, 255–256
OOP (Object-Oriented Programming)
classes. See classes
code, 37–38
Code Editor, 37–38
functions, 249
namespaces, 80, 284
objects
classes relationship, 14, 283–284, 286
Convert object, 255
overview, 283–284
properties, 69
Random, 199
String, 256–257
TimeSpan object, 255–256
overview, 5–6, 283
terminology, 283–284
variables, 154–155
opening/closing windows/forms, 31–32
operators (comparison), 189
Options command (Tools menu), 32
organizing controls, 259
Other Windows command (Window menu), 31
Output window, 50
overloading functions, 285


Previous Page
Next Page

Index

P-Q

palettes (AutoDock), 30–31
Panel control, 259, 324
parameters
dialog boxes, 79–84
functions, 246, 249, 251
passing arguments (functions), 251–254
Pen class functions, 313–314
PictureBox control, 220, 310–311
pixels (graphics), 310
Point class, 327
polymorphism (classes), 285
pop-up windows/forms (IntelliSense), 40–42
previews
Click Race, 27–29
Dice Poker, 207–210
Guess a Number, 177–179
Hangman, 242–243
Joke Machine, 2–3
Lottery Assistant, 102–104
Rock, Paper and Scissors, 280–282
Speed Typing, 64–65
Story of Mighty Molly, 142–143
Tic-Tac-Toe. 335–337
VC++ Doodle, 307–309
private functions, 249
programming. See code; OOP
programs. See applications
ProgressBar control, 295
projects. See also applications
building, 25
Click Race
code, 55–59
controls, 51, 53–55
creating, 51
design, 50–51
GUIs, 51–53
preview, 27–29
testing, 60
windows/forms, 51, 53–55
controls. See controls
Dice Poker
code, 225–239
controls, 217–218, 221–225
creating, 217–219
design, 217–218
GUIs, 219–220
preview, 207–210
testing, 239
windows/forms, 217–218, 221–225
folders, moving, 19
Guess a Number
code, 196–205
controls, 190–191, 193–196
creating, 190–191
design, 190–191
GUIs, 190–193
preview, 177–179
testing, 205
windows/forms, 190–191, 193–196
Hangman
code, 266–277
controls, 257–258, 260–266
creating, 257–259
design, 257–258
GUIs, 259–260
preview, 242–243
testing, 277
windows/forms, 257–258, 260–266
Joke Machine
code, 23–25
controls, 20–25
creating, 16–20
design overview, 16
GUIs, 20–21
preview, 2–3
testing, 25
Lottery Assistant
code, 132–140
controls, 125–131
creating, 125–126
design, 125–126
GUIs, 126–127
menus, 129–131
preview, 102–104
testing, 140
windows/forms, 125–131
managing (Solution Explorer), 44–45
menus. See menus
names, 18–19
Rock, Paper and Scissors
code, 297–305
controls, 290–291, 293–297
creating, 290–291
design, 290–291
GUIs, 290–292
preview, 280–282
testing, 305
windows/forms, 290–291, 293–297
Solutions, 18–19
Speed Typing
code, 91–99
controls, 86–90
creating, 85–86
design, 85–86
GUIs, 87
overview, 85
preview, 64–65
testing, 99
windows/forms, 86–90
Story of Mighty Molly
code, 169–175
controls, 163–169
creating, 163–164
design, 163–164
GUIs, 164–165
preview, 142–143
testing, 176
windows/forms, 163–169
templates, 17–18
Tic-Tac-Toe
code, 352–364
controls, 346, 348–351
creating, 345–347
design, 346
GUIs, 347–348
preview, 335–337
testing, 364
windows/forms, 346, 348–351
toolbars
adding, 120–122
buttons, 121–122,124–125
code, 124–125
commands, 33–34
customizing, 32, 34
event handling, 124–125
graphics, 122–123
.NET Framework, 120
overview, 33–34
Standard, 33
styles, 122
text, 121–122
ToolTips, 122
troubleshooting. See troubleshooting code
types, 17
VC++ Doodle
code, 326–333
controls, 322, 324–326
creating, 322–323
design, 322
GUIs, 323–324
preview, 307–309
testing, 333
windows/forms, 322, 324–326
viewing/hiding (tabs), 24
Web site, 9
windows/forms. See windows/forms
properties
controls
Click Race, 53–55
Dice Poker, 221–225
Guess a Number, 193–196
Hangman, 260–266
Joke Machine, 21–22
Lottery Assistant, 127–131
overview, 45–48
Rock, Paper and Scissors, 293–297
Speed Typing, 87–90
Story of Mighty Molly, 165–169
Tic-Tac-Toe. 348–351
VC++ Doodle, 324–326
objects, 69
Properties window overview, 45–48
String object, 256–257
variables (strings), 157–158
windows/forms
Click Race, 53–55
Dice Poker, 221–225
Guess a Number, 193–196
Hangman, 260–266
Lottery Assistant, 127–131
overview, 45–48
Rock, Paper and Scissors, 293–297
Speed Typing, 87–90
Story of Mighty Molly, 165–169
Tic-Tac-Toe, 348–351
VC++ Doodle, 324–326
Properties window. See properties
protected functions, 249
pseudo-code, 180–181
public functions, 249


Previous Page
Next Page

Index

R

RAD, 5
RadioButton control, 192
Random object (Next function), 199
Rapid Application Development, 5
recording sound, 319
ref class, 288–289
release versions, 84–85
rendering. See graphics
reserved words, 162–163
resources, online, 367–370
restoring IDE, 31
retrieving data, 145–146
return types (functions), 249
returning data (functions), 246
Rock, Paper and Scissors
code, 297–305
controls
creating, 290–291
properties, 293–297
creating, 290–291
design, 290–291
GUIs, 290–292
preview, 280–282
testing, 305
windows/forms
creating, 290–291
properties, 293–297
running applications, 7, 20
runtime errors (error handling), 339–340, 343–345
runtime versions (creating), 84–85


Previous Page
Next Page

Index

S

saving windows/forms (asterisks), 35
scope (variables), 152–153
Scopes list (Code Editor), 37
selecting windows/forms (Code Editor), 37
separator bars (menus), 114–115
shortcut keys, 111
Show function (MessageBox class), 78–84, 285
single-line if statements, 181–182
size
Code Editor, 24
controls, 20–21
menu fonts, 138–139
toolbar buttons, 122
windows/forms, 66–67, 324
Solution Explorer, 44–45
Solutions (projects), 18–19
sound
adding, 318–321
overview, 307
recording, 319
sound schemes, 320–321
wave files, 319
sound schemes, 320–321
SoundPlayer class, 319–320
spacing (code), 39
speed (developing applications), 181
Speed Typing
code, 91–99
controls, 86–90
creating, 85–86
design, 85–86
GUIs, 87
overview, 85
preview, 64–65
testing, 99
windows/forms, 86–90
spelling (menus), 109
standalone applications, 84–85
Standard toolbar, 33
start position (windows/forms), 66–67
statements
if statements
ComboBox control, 184–185
if…else if statements, 184–185
if…else statements, 182–184
multiline, 182
nesting, 185–187
operators, 189
overview, 180–181
pseudo-code, 180–181
single-line, 181–182
String Collection Editor, 184–185
syntax, 181
loops, 213
break, 215–216
continue, 216–217
switch, 187–188
static variables, 151–152
Status Strips, 72–76, 99
StatusBar control. See Status Strips
stepping breakpoints (debugging), 342–343
storing
code, 36–37
controls, 259
coordinates, 327
data, 145–146
graphics, 220, 225
Story of Mighty Molly
code, 169–175
controls
creating, 163–164
properties, 165–169
creating, 163–164
design, 163–164
GUIs, 164–165
preview, 142–143
testing, 176
windows/forms
creating, 163–164
properties, 165–169
String Collection Editor, 184–185
String object, 256–257
strings
code, 132–136
defined, 155
functions
manipulating, 256–257
variables, 155–158
variables
declaring, 156–157
functions, 155–158
properties, 157–158
structures, 146, 160–162
stubbing functions, 250
styles (toolbars), 122
submenus, adding, 108
Subtract function, 255–256
support, 10
switch statements, 187–188
syntax
functions, 244
if statements, 181
syntax errors (error handling), 338
System class (Drawing function), 327
System Tray, 76–78
SystemSounds class, 320–321


Previous Page
Next Page

Index

T

tabs
controls, 70–72
viewing/hiding (projects), 24
windows/forms, 31, 70–72
Task List window, 50
templates
menus, 109
projects, 17–18
terminology (OOP), 283–284
testing
Click Race, 60
Dice Poker, 239
Guess a Number, 205
Hangman, 277
Joke Machine, 25
Lottery Assistant, 140
Rock, Paper and Scissors, 305
Speed Typing, 99
Story of Mighty Molly, 176
Tic-Tac-Toe, 364
VC++ Doodle, 333
text
dialog boxes, 79, 82–83
font size (menus), 138–139
graphics, 317–318
System Tray, 77
text boxes, 21
toolbars, 121–122
windows/forms, 68–70
text boxes, 21
this keyword, 69
thumbtacks (windows/forms), 31–32
Tic-Tac-Toe
code, 352–364
controls
creating, 346
properties, 348–351
creating, 345–347
design, 346
GUIs, 347–348
preview, 335–337
testing, 364
windows/forms
creating, 346
properties, 348–351
time, 254–256
Timer control, 49
TimeSpan object (Subtract function), 255–256
title bars (windows/forms), 68–70
ToDateTime function, 255
tool windows, 68
ToolBar control. See toolbars
ToolBarButton Collection Editor, 121–123
toolbars
adding, 120–122
buttons, 121–122,124–125
code, 124–125
commands, 33–34
customizing, 32, 34
event handling, 124–125
graphics, 122–123
.NET Framework, 120
overview, 33–34
Standard, 33
styles, 122
text, 121–122
ToolTips, 122
Toolbox, 42–44
tools (AutoDock), 30–31
Tools menu commands
Import and Export Settings, 31
Options, 32
ToolTips
controls, 86, 89–90
System Tray, 77
toolbar buttons, 122
ToString function, 154
trial version (Visual C++), 8
troubleshooting code
arrays, 160
backslashes, 320
bugs, 160
classes, defining, 289
crashes, 134, 160
debugging breakpoints
adding, 340–342
deleting, 342
overview, 340
stepping, 342–343
error handling
logical errors, 338–339
overview, 337
runtime errors (exceptions), 339–340, 343–345
syntax errors, 338
restoring IDE, 31
variables, 152
types
classes, 286
loops, 211
projects, 17


Previous Page
Next Page

Index

U

users
input
dialog boxes, 83
focus. See focus
Status Strips, 75
menu expectations, 106


Previous Page
Next Page

Index

V

value class, 286–287
values (constants), 287–288
variables
declaring, 149–150
case sensitivity, 152
conventions, 152–153
scope, 152–153
defined, 145, 148
defining, 149–150
local, 150–151
scope, 152
static, 151–152
errors, 152
identifiers, 149
OOP, 154–155
overview, 148–149
strings. See strings
VC++ Doodle
code, 326–333
controls
creating, 322
properties, 324–326
creating, 322–323
design, 322
GUIs, 323–324
preview, 307–309
testing, 333
windows/forms
creating, 322
properties, 324–326
vector graphics, 311–317
viewing/hiding
code, 38
controls (Toolbox), 42–44
dialog boxes, 82
graphics, 220
IntelliSense, 41–42
menus, 117–118
projects (tabs), 24
windows/forms, 38, 41–42
views. See windows/forms
Visual Basic 2005 Express, 10–11
Visual C# 2005 Express, 10–12
Visual C++ 2005 Express Edition
downloading, 8
history, 6–8
installing, 8
overview, 3–4, 8–11
trial version, 8
Visual C++ 2005 Professional Edition, 10–11
Visual C++ 2005 Standard Edition, 10–11
Visual J# 2005 Express, 11–12
Visual Studio .NET Enterprise Architect, 11
Visual Studio .NET Enterprise Developer, 11
Visual Studio Express, 10–12
Visual Web Developer 2005 Express Edition, 10


Previous Page
Next Page

Index

W–Z

wave files (sound), 319
Web sites
book, 365–366
Course Technology, 225
Microsoft
downloading, 8
games, 9
.NET Framework, 16
projects, 9
while loops, 211–213
Win32 compatibility, 10
Window menu command, Other Windows, 31
windows/forms. See also GUIs
alignment, 66–67
autohide, 31–32
Bookmark, 50
borders, 67–68
Call Browser, 50
Class View, 50
code, 36–38
Code Editor. See also code
color, 39
cursors, 37
customizing, 36
indentation, 39
Members list, 37
OOP, 37–38
overview, 36–37
Scopes list, 37
selecting, 37
size, 24
spacing, 39
windows/forms, selecting, 37
Command, 50
Component Tray, 48–49
controls. See controls
creating
Click Race, 51
Dice Poker, 217–218
Guess a Number, 190–191
Hangman, 257–258
Lottery Assistant, 125–126
Rock, Paper and Scissors, 290–291
Speed Typing, 86
Story of Mighty Molly, 163–164
Tic-Tac-Toe, 346
VC++ Doodle, 322
customizing, 32
docking, 31–32
Error List, 50
focus, 70–72
Form Designer overview, 34–36
IntelliSense, 40–42
menus. See menus
moving, 66–67
opening/closing, 31–32
Output, 50
overview, 34–36
pop-up, 40–42
properties
Click Race, 53–55
Dice Poker, 221–225
Guess a Number, 193–196
Hangman, 260–266
Lottery Assistant, 127–131
overview, 45–48
Rock, Paper and Scissors, 293–297
Speed Typing, 87–90
Story of Mighty Molly, 165–169
Tic-Tac-Toe, 348–351
VC++ Doodle, 324–326
Properties window. See properties
saving (asterisks), 35
size, 66–67, 324
Solution Explorer, 44–45
start position, 66–67
Status Strips, 72–76, 99
storing, 36–37
tabs, 31, 70–72
Task List, 50
text, 68–70
thumbtacks, 31–32
title bars, 68–70
tool windows, 68
toolbars
adding, 120–122
buttons, 121–122,124–125
code, 124–125
commands, 33–34
customizing, 32, 34
event handling, 124–125
graphics, 122–123
.NET Framework, 120
overview, 33–34
Standard, 33
styles, 122
text, 121–122
ToolTips, 122
Toolbox, 42–44
viewing/hiding, 38, 41–42
wizards. See dialog boxes


List of Figures

Chapter 1: An Introduction to Visual C++ 2005 Express

Figure 1.1: The starting screen of the Joke Machine.
Figure 1.2: Clicking the first button triggers the first joke.
Figure 1.3: Clicking the second button triggers the second joke.
Figure 1.4: Visual C++ 2005 Express Edition showing the Start Page.
Figure 1.5: The Microsoft .NET Framework is utilized by multiple languages to build applications for several target platforms.
Figure 1.6: The New Project dialog box allows you to control the creation of a new project.
Figure 1.7: Visual C++ presents a blank form when you begin a new project based on a Windows Forms Application template.
Figure 1.8: You can resize many form controls by dragging their borders.
Figure 1.9: Visual C++ adds descriptive text to controls as you add them to a form.
Figure 1.10: You can give controls functionality by adding code to them in the Code Editor.

Chapter 2: Navigating the Visual C++ 2005 Express Edition Environment

Figure 2.1: Starting up the Click Race game.
Figure 2.2: Players score points by clicking on the currently active game button.
Figure 2.3: To score another point, the player must click on the second game button.
Figure 2.4: Plays ends at 30 seconds when both game buttons are disabled.
Figure 2.5: The Visual C++ IDE has room to show only a portion of the available toolbars and windows at any one time.
Figure 2.6: Microsoft has implemented several clever organizational tricks to make the IDE more manageable.
Figure 2.7: The Standard toolbar provides access to the most commonly used IDE commands and windows.
Figure 2.8: Visual C++ automatically creates a new form containing basic Windows elements each time you open a new Visual C++ project.
Figure 2.9: As you drag elements to a form, alignment indicators appear to assist you in aligning form controls.
Figure 2.10: The Code Editor has two drop-down lists (Scope and Functions) used to quickly navigate within an application source code.
Figure 2.11: The Visual C++ Code Editor automatically color-codes statements and indents them to make them easier to read.
Figure 2.12: IntelliSense provides dynamic assistance as you enter your code statements.
Figure 2.13: IntelliSense can assist you in the creation of complex code statements and in reducing typos.
Figure 2.14: You can manually activate IntelliSense by using the Ctrl and Spacebar keys.
Figure 2.15: The Toolbox window provides access to the controls you can use to create a Windows application.
Figure 2.16: Using Solution Explorer, you can manage the projects and files that make up your Visual C++ applications.
Figure 2.17: Examining the properties associated with an application's Form control.
Figure 2.18: When the available range of values for a property is limited, the Properties window produces a drop-down list for your selection.
Figure 2.19: When properties have a wide range of possible options, selecting them initiates a separate dialog box where you can choose the values to customize the property.
Figure 2.20: The Component Tray uses icons to represent all controls that affect your application but that the user cannot see or manipulate.
Figure 2.21: The design view of the Click Race game's interface.

Chapter 3: Creating an Application Interface

Figure 3.1: The Speed Typing game begins when the player clicks on the Go button.
Figure 3.2: Players advance by typing the required text string within the allotted amount of time.
Figure 3.3: Players who fail to type the required text in time receive a strike.
Figure 3.4: Players who make a typo when keying in the required text string receive a strike.
Figure 3.5: The player's typing skill level is analyzed and displayed at the end of gameplay.
Figure 3.6: Unless you specify otherwise, Visual C++ allows users to alter the size of your application's window.
Figure 3.7: By default, Visual C++ displays a form's name in its title bar.
Figure 3.8: Programmatically changing the text string displayed in the window's title bar.
Figure 3.9: Modifying the default tab order of the controls Located on a Visual C++ form.
Figure 3.10: A Windows Status Strip displaying a time and date in two separate panels.
Figure 3.11: You can modify Status Strip controls directly or by using the Items Collection Editor.
Figure 3.12: Status Strips provide an effective means of communicating important information as the application runs.
Figure 3.13: The Windows System Tray provides single- and double-click access to various Windows utilities, processes, and applications.
Figure 3.14: The MessageBox——Show method is perfect for displaying a small amount of text.
Figure 3.15: Twenty-one different formats of the MessageBox——Show methods are supported.
Figure 3.16: Prompting the user for permission to continue.
Figure 3.17: Displaying a simple informational message.
Figure 3.18: Prompting the user to select from three options.
Figure 3.19: Viewing the results of the button selection the user made.
Figure 3.20: The Configuration Manager allows you to build debug or release versions of your application.

Chapter 4: Working with Menus and Toolbars

Figure 4.1: The Lottery Assistant game begins by collecting player input.
Figure 4.2: Players control the game using its menu system.
Figure 4.3: Up to 10 sets of lottery numbers can be generated at a time.
Figure 4.4: Players can configure the game's background color.
Figure 4.5: Using the Font Size submenu, the user can specify the font size used to display lottery numbers.
Figure 4.6: By clicking on the About menu item located on the Help menu, players can learn more about the game.
Figure 4.7: This menu illustrates the contents of the Visual C++ Express 2005 File menu.
Figure 4.8: You can use the MenuStrip control to add a menu system to a Visual C++ application.
Figure 4.9: The first menu heading in the application's menu system is defined by typing its name.
Figure 4.10: Additional menus can be added to the application's menu system.
Figure 4.11: Menu items can be added by typing in the boxes under a menu heading.
Figure 4.12: Entering text automatically enables you to add submenu items to the menu system.
Figure 4.13: Visual C++ allows you to insert a standard menu system into a form.
Figure 4.14: Clicking any menu item allows you to easily add code to it.
Figure 4.15: You can specify the shortcut you want to assign to a menu or menu item.
Figure 4.16: You can specify shortcut keys to activate menus and menu items.
Figure 4.17: This example shows the process of adding access keys to menus and menu items.
Figure 4.18: A check mark indicates when a menu item has been selected.
Figure 4.19: Using separator bars can visually group related menu items.
Figure 4.20: Menu items can be disabled at design time.
Figure 4.21: Associated submenus are disabled when a menu item is disabled.
Figure 4.22: Here the Custom submenu item has been made invisible on the Background submenu.
Figure 4.23: You can also control user access to menu items by hiding and redisplaying them when appropriate.
Figure 4.24: Here the menu items for a context menu are configured.
Figure 4.25: This button has been given an associated context menu.
Figure 4.26: The ToolBarButton Collection Editor a allows you to add and remove buttons on a toolbar.
Figure 4.27: Use the up and down arrows to configure the order in which buttons are displayed on the toolbar.
Figure 4.28: The Images Collection Editor lets you specify the images that you will add to your toolbar.
Figure 4.29: Here a graphic image is added to a ToolBar control button.
Figure 4.30: A dialog box is displayed as a result of clicking within the correct area.
Figure 4.31: The interface design for the Lottery Assistant game is complete.

Chapter 5: Storing and Retrieving Data in Memory

Figure 5-1: The Story of Mighty Molly game begins by presenting the player with five questions and then allowing him to tell the story by clicking a button.
Figure 5.2: An introduction tells the story of Mighty Molly.
Figure 5.3: The game issues an error if all text is not filled in.
Figure 5.4: A progress bar located on the status bar indicates when all required information has been collected.
Figure 5.5: Data input collected from the player is then plugged into the story line and displayed for the player to enjoy.
Figure 5.6: By assigning a string to a constant, you can use it throughout your application without worrying that the value will change.
Figure 5.7: Using IntelliSense to view methods and properties associated with a variable object.
Figure 5.8: Completing the interface design for The Story of Mighty Molly.

Chapter 6: Applying Conditional Logic

Figure 6.1: The game begins by allowing the player to specify configuration options, including the range of numbers to pick from and the amount of information the game displays.
Figure 6.2: When gameplay starts, the player's access to the configuration options is disabled and the player is prompted to take the first guess.
Figure 6.3: The game gives players clues to help them home in on the answer. It also displays a running count of the number of guesses the player makes.
Figure 6.4: At the end of each game, the player gets a chance to modify the game's configuration options and reset the score.
Figure 6.5: Validating the player age before allowing the game to be played.
Figure 6.6: Using an if...else if statement to process the contents of a ComboBox control.
Figure 6.7: Using the String Collection Editor at design time to populate the contents of a ComboBox control.
Figure 6.8: Completing the interface design for the Guess a Number game.

Chapter 7: Processing Lots of Data with Loops

Figure 7.1: The Dice Poker game begins by giving the player $20 in an account.
Figure 7.2: Players can elect to hold onto specific dice before rolling the dice a second time.
Figure 7.3: Two dollars are deducted from the player's account for each losing hand.
Figure 7.4: Winning hands are rewarded with additional credits to the player's account.
Figure 7.5: Winning hands include 3, 4, and 5 of a kind, full house, and high and low straights.
Figure 7.6: The game automatically ends if the player's account runs out of money.
Figure 7.7: Completing the interface design for the Dice Poker game.

Chapter 8: Enhancing Code Structure and Organization

Figure 8.1: When the game is started, it displays a graphic showing an empty hangman's gallows and a series of underscore characters representing the secret word.
Figure 8.2: As the game progresses, each correct guess is displayed at the top of the window, and a visual record of every letter guessed is displayed at the bottom of the window.
Figure 8.3: The game prevents the player from making the same letter guess more than once.
Figure 8.4: The game permits the player to enter only one letter at a time.
Figure 8.5: The game prevents the player from entering numeric input.
Figure 8.6: The game congratulates the player when he correctly guesses the secret word.
Figure 8.7: If the player fails to guess the secret word within six guesses, he loses the game, and the picture of the hangman's gallows is updated to show a full hangman image.
Figure 8.8: Entering data into the Vitals application.
Figure 8.9: A function within the Vitals application shows the information passed to it.
Figure 8.10: Using the DateTime.Now() function to display the current date and time.
Figure 8.11: Examining the Layout of the Hangman game's user interface.

Chapter 9: Getting Comfortable with Object-Oriented Programming

Figure 9.1: The Rock, Paper and Scissors game begins by displaying the game board.
Figure 9.2: When the player clicks on the Play button, a 1.5-second countdown begins.
Figure 9.3: The player gets a half second at the end of the countdown to make a selection by choosing rock, paper, or scissors.
Figure 9.4: As soon as both the computer and the player have made their choices, the game displays graphics showing each move and determines who won.
Figure 9.5: The Rock, Paper and Scissors game also keeps a running tally of the number of wins, losses, and ties.
Figure 9.6: Completing the interface design for the Rock, Paper and Scissors game.

Chapter 10: Integrating Graphics and Audio

Figure 10.1: The user interface for the VC++ Doodle game consists of a control panel and a drawing area.
Figure 10.2: VC++ Doodle gives the player a range of colors to choose from.
Figure 10.3: The game assists the player in drawing an assortment of predefined shapes.
Figure 10.4: The player also has the option of making a freehand drawing using any combination of colors.
Figure 10.5: A graphical depiction of the coordinate system employed by GDI+ when drawing graphics.
Figure 10.6: An example of an application that uses the PictureBox and ImageList controls to work with graphics.
Figure 10.7: Using the Graphics class's DrawRectangle method to draw a shape.
Figure 10.8: Drawing a filled-in circle using the Graphics object's FillEllipse method.
Figure 10.9: Visual C++ allows you to draw text as a graphic.
Figure 10.10: Using the Windows Sound Recorder utility to create a custom wave file.
Figure 10.11: Completing the interface design for the VC++ Doodle game.

Chapter 11: Debugging Visual C++ Applications

Figure 11.1: The Tic-Tac-Toe game begins by displaying a blank game board.
Figure 11.2: The game keeps track of each player's turn.
Figure 11.3: The game monitors each player's move and determines when there is a winner.
Figure 11.4: The Output window displays errors found at compile time.
Figure 11.5: An example of a visual C++ runtime error displayed when an application is being executed in Design mode.
Figure 11.6: Using a breakpoint to pause an application's execution.
Figure 11.7: The Visual C++ IDE changes the highlight of the currently active breakpoint.
Figure 11.8: Using the Debug icons on the standard toolbar to step through program statements.
Figure 11.9: Examining the error message that's generated when your application runs into an unhandled exception at runtime.
Figure 11.10: Exception handling provides a more graceful means of dealing with runtime errors.
Figure 11.11: Completing the interface design for the Tic-Tac-Toe game.


List of Tables

Chapter 2: Navigating the Visual C++ 2005 Express Edition Environment

Table 2.1: Additional IDE Windows
Table 2.2: Form Controls for the Click Race Game
Table 2.3: Property Changes for the TextBox1 Control
Table 2.4: Property Changes for the Label1 Control
Table 2.5: Property Changes for the Button Controls
Table 2.6: Property Changs for the Timer1 Control

Chapter 3: Creating an Application Interface

Table 3.1: Values Supported by the Form StartPosition Property
Table 3.2: Available Options for the FormBorderStyle Property
Table 3.3: Available Controls Within a StatusStrip Control
Table 3.4: Papameters Available to the MessageBox::Show Method
Table 3.5: Buttons Available to the MessageBox::Show Method
Table 3.6: Icons Available to the MessageBox::Show Method
Table 3.7: Default Button Value Options for the MesageBox::Show Method
Table 3.8: Options Values for the MessageBox::Show Method
Table 3.9: Return Values Associated with the MessageBox::Show Method
Table 3.10: Form Controls for the Speed Typing Game
Table 3.11: Property Changes for the Form
Table 3.12: Property Changes for the TextBox Controls
Table 3.13: Property Changes for the Label Controls
Table 3.14: Property Changes for the Button Controls

Chapter 4: Working with Menus and Toolbars

Table 4.1: Form Controls for the Lottery Assistant Game
Table 4.2: Property Value Assignments for the Lottery Assistant Game's Form
Table 4.3: Property Changes for Each of the Label Controls
Table 4.4: Property Changes for Each of the TextBox Controls
Table 4.5: Menus for the Lottery Assistant Game
Table 4.6: Menu Items Residing Under the File Menu
Table 4.7: Menu Items Residing Under the Options Menu
Table 4.8: Menu Items Residing Under the Help Menu
Table 4.9: Menu Items Residing on the Background Submenu
Table 4.10: Menu Items Residing on the Font Size Submenu

Chapter 5: Storing and Retrieving Data in Memory

Table 5.1: Visual C++ Supported Data Types
Table 5.2: String Handling Properties and Methods
Table 5.3: List of Visual C++ Reserved Words
Table 5.4: Form Controls for the Story of Mighty Molly
Table 5.5: Property Changes for Form1
Table 5.6: Property Changes for the Label Controls
Table 5.7: Property Changes for the Button Controls
Table 5.8: Property Changes for the StatusStrip Control
Table 5.9: Property Changes for the TextBox Controls
Table 5.10: Property Changes for the ToolStripStatusLabel Control
Table 5.11: Property Changes for the ProgressBar Control
Table 5.12: Property Changes for the ToolTip Control

Chapter 6: Applying Conditional Logic

Table 6.1: Visual C++ Comparison Operators
Table 6.2: Form Controls for the Guess a Number Game
Table 6.3: Property Changes for Form1
Table 6.4: Property Changes for the GroupBox Controls
Table 6.5: Property Changes for the RadioButton Controls
Table 6.6: Property Changes for the Button Controls
Table 6.7: Property Changes for the CheckBox Control
Table 6.8: Property Changes for the Label Controls
Table 6.9: Property Changes for the TextBox Controls
Table 6.10: Property Changes for the StatusStrip Control

Chapter 7: Processing Lots of Data with Loops

Table 7.1: Form Controls for the Dice Poker Game
Table 7.2: Property Changes for Form1
Table 7.3: Property Changes for Label Controls
Table 7.4: Property Changes for PictureBox Controls
Table 7.5: Property Changes for CheckBox Controls
Table 7.6: Property Changes for Button Controls
Table 7.7: Property Changes for GroupBox Controls
Table 7.8: Property Changes for TextBox Control
Table 7.9: Bitmap Images to Add to the ImageList Control's Images Collection

Chapter 8: Enhancing Code Structure and Organization

Table 8.1: Form Controls for the Hangman Game
Table 8.2: Property Changes for Form1
Table 8.3: Property Changes for the Panel Control
Table 8.4: Property Changes for the GroupBox Control
Table 8.5: Property Changes for the TextBox Controls
Table 8.6: Property Changes for the Button Control
Table 8.7: Property Changes for the Label Controls
Table 8.8: Property Changes for the PictureBox Control
Table 8.9: Bitmap Images to Add to the ImageList Control's Images Collection

Chapter 9: Getting Comfortable with Object-Oriented Programming

Table 9.1: Form Controls for the Rock, Paper and Scissors Game
Table 9.2: Property Changes for Form1
Table 9.3: Property Changes for PictureBox Controls
Table 9.4: Property Changes for Label Controls
Table 9.5: Property Changes for Button Controls
Table 9.6: Property Changes for TextBox Controls
Table 9.7: Property Changes for Timer Control
Table 9.8: Bitmap Images to Add to the ImageList Control's Images Collection

Chapter 10: Integrating Graphics and Audio

Table 10.1: Drawing Methods Associated with the System::Drawing::Graphics Class
Table 10.2: Predefined Colors for Pens and Brushes
Table 10.3: Form Controls for the VC++ Doodle Game
Table 10.4: Property Changes for FormI
Table 10.5: Property Changes for Panel Control
Table 10.6: Property Changes for Label Controls
Table 10.7: Property Changes for Button Controls
Table 10.8: Property Changes for ComboBox Control

Chapter 11: Debugging Visual C++ Applications

Table 11.1: From Controls for the Tic-Tac-Toe Game
Table 11.2: Property Changes for Form1
Table 11.3: Property Changes for Panel Controls
Table 11.4: Property Changes for PictureBox Controls
Table 11.5: Property Changes for Button Controls
Table 11.6: Property Changes for Label Control
Table 11.7: Property Changes for TextBox Control


List of In The Real Worlds

Introduction

IN THE REAL WORLD

Chapter 1: An Introduction to Visual C++ 2005 Express

IN THE REAL WORLD
IN THE REAL WORLD
IN THE REAL WORLD
IN THE REAL WORLD
IN THE REAL WORLD

Chapter 3: Creating an Application Interface

IN THE REAL WORLD

Chapter 4: Working with Menus and Toolbars

IN THE REAL WORLD

Chapter 5: Storing and Retrieving Data in Memory

IN THE REAL WORLD

Chapter 8: Enhancing Code Structure and Organization

IN THE REAL WORLD
IN THE REAL WORLD