Ivor Horton’s
Beginning Visual C++® 2005 Ivor Horton
Ivor Horton’s
Beginning Visual C++® 2005
Ivor Horton’s
Begi...
223 downloads
2051 Views
18MB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Ivor Horton’s
Beginning Visual C++® 2005 Ivor Horton
Ivor Horton’s
Beginning Visual C++® 2005
Ivor Horton’s
Beginning Visual C++® 2005 Ivor Horton
Ivor Horton’s Beginning Visual C++® 2005 Published by Wiley Publishing, Inc. 10475 Crosspoint Boulevard Indianapolis, IN 46256 www.wiley.com Copyright © 2006 by Ivor Horton Published by Wiley Publishing, Inc., Indianapolis, Indiana Published simultaneously in Canada ISBN-13: 978-0-7645-7197-8 ISBN-10: 0-7645-7197-4 Manufactured in the United States of America 10 9 8 7 6 5 4 3 2 1 1B/QY/QS/QW/IN Library of Congress Cataloging-in-Publication Data: Horton, Ivor. Ivor Horton’s Beginning Visual C++ 2005 / Ivor Horton. p. cm. Includes index. ISBN-13: 978-0-7645-7197-8 (paper/website) ISBN-10: 0-7645-7197-4 (paper/website) 1. C++ (Computer program language) 2. Microsoft Visual C++. I. Title: Beginning Visual C++ 2005. II. Title. QA76.73.C15I6694 2006 005.13’3—dc22 2005032051 No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning or otherwise, except as permitted under Sections 107 or 108 of the 1976 United States Copyright Act, without either the prior written permission of the Publisher, or authorization through payment of the appropriate per-copy fee to the Copyright Clearance Center, 222 Rosewood Drive, Danvers, MA 01923, (978) 750-8400, fax (978) 646-8600. Requests to the Publisher for permission should be addressed to the Legal Department, Wiley Publishing, Inc., 10475 Crosspoint Blvd., Indianapolis, IN 46256, (317) 572-3447, fax (317) 572-4355, or online at http://www.wiley.com/go/permissions. LIMIT OF LIABILITY/DISCLAIMER OF WARRANTY: THE PUBLISHER AND THE AUTHOR MAKE NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO THE ACCURACY OR COMPLETENESS OF THE CONTENTS OF THIS WORK AND SPECIFICALLY DISCLAIM ALL WARRANTIES, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE. NO WARRANTY MAY BE CREATED OR EXTENDED BY SALES OR PROMOTIONAL MATERIALS. THE ADVICE AND STRATEGIES CONTAINED HEREIN MAY NOT BE SUITABLE FOR EVERY SITUATION. THIS WORK IS SOLD WITH THE UNDERSTANDING THAT THE PUBLISHER IS NOT ENGAGED IN RENDERING LEGAL, ACCOUNTING, OR OTHER PROFESSIONAL SERVICES. IF PROFESSIONAL ASSISTANCE IS REQUIRED, THE SERVICES OF A COMPETENT PROFESSIONAL PERSON SHOULD BE SOUGHT. NEITHER THE PUBLISHER NOR THE AUTHOR SHALL BE LIABLE FOR DAMAGES ARISING HEREFROM. THE FACT THAT AN ORGANIZATION OR WEBSITE IS REFERRED TO IN THIS WORK AS A CITATION AND/OR A POTENTIAL SOURCE OF FURTHER INFORMATION DOES NOT MEAN THAT THE AUTHOR OR THE PUBLISHER ENDORSES THE INFORMATION THE ORGANIZATION OR WEBSITE MAY PROVIDE OR RECOMMENDATIONS IT MAY MAKE. FURTHER, READERS SHOULD BE AWARE THAT INTERNET WEBSITES LISTED IN THIS WORK MAY HAVE CHANGED OR DISAPPEARED BETWEEN WHEN THIS WORK WAS WRITTEN AND WHEN IT IS READ. For general information on our other products and services please contact our Customer Care Department within the United States at (800) 762-2974, outside the United States at (317) 572-3993 or fax (317) 572-4002. Trademarks: Wiley, the Wiley logo, Wrox, the Wrox logo, Programmer to Programmer, and related trade dress are trademarks or registered trademarks of John Wiley & Sons, Inc. and/or its affiliates, in the United States and other countries, and may not be used without written permission. Visual C++ is a registered trademark of Microsoft Corporation in the United States and/or other countries. All other trademarks are the property of their respective owners. Wiley Publishing, Inc., is not associated with any product or vendor mentioned in this book. Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be available in electronic books.
Credits Executive Editor
Vice President and Executive Publisher
Bob Elliott
Joseph B. Wikert
Senior Development Editor
Project Coordinator
Kevin Kent
Development Editor Howard Jones
Technical Editor John Mueller
Production Editor Pamela Hanley
Copy Editor Susan Hobbs
Editorial Manager Mary Beth Wakefield
Production Manager Tim Tate
Ryan Steffen
Graphics and Production Specialists Brian Drumm Lauren Goddard Brooke Graczyk Denny Hager Joyce Haughey Jennifer Heleine Stephanie D. Jumper Barry Offringa Alicia South Erin Zeltner
Quality Control Technicians Laura Albert John Greenough Leeann Harney
Proofreading TECHBOOKS Production Services
Vice President and Executive Group Publisher
Indexing
Richard Swadley
Infodex Indexing Services Inc.
About the Author Ivor Horton graduated as a mathematician and was lured into information technology by promises of great rewards for very little work. In spite of the reality being usually a great deal of work for relatively modest rewards, he has continued to work with computers to the present day. He has been engaged at various times in programming, systems design, consultancy, and the management of the implementation of projects of considerable complexity. Horton has many years of experience in the design and implementation of computer systems applied to engineering design and to manufacturing operations in a variety of industries. He also has considerable experience in developing occasionally useful applications in a wide variety of programming languages, and of teaching primarily scientists and engineers to do likewise. He has written books on programming for more than 10 years; his currently published works include tutorials on C, C++, and Java. At the present time, when he is not writing programming books or providing advice to others, he spends his time fishing, travelling, and trying to speak better French.
This book is dedicated to Alexander Gilbey. I look forward to his comments, but I’ll probably have to wait a while.
Acknowledgments I’d like to acknowledge the efforts and support of the John Wiley & Sons, and Wrox Press editorial and production team in the production of this book, especially Senior Development Editor Kevin Kent who has been there from way back at the beginning and has stayed through to the end. I’d also like to thank Technical Editor John Mueller for going through the text to find hopefully most of my mistakes, for checking out all the examples in the book, and for his many constructive comments that helped make the book a better tutorial. Finally, I would like to thank my wife, Eve, for her patience, cheerfulness, and support throughout the long gestation period of this book. As I have said on many previous occasions, I could not have done it without her.
Contents Acknowledgments
Chapter 1: Programming with Visual C++ 2005 The .NET Framework The Common Language Runtime (CLR) Writing C++ Applications Learning Windows Programming Learning C++ The C++ Standards Console Applications Windows Programming Concepts
What Is the Integrated Development Environment? Components of the System The The The The
Editor Compiler Linker Libraries
Using the IDE Toolbar Options Dockable Toolbars Documentation Projects and Solutions
xi
1 2 2 3 4 5 5 6 6
8 9 9 9 9 9
10 10 12 12 13
Defining a Project Debug and Release Versions of Your Program Dealing with Errors
13 19 23
Setting Options in Visual C++ 2005 Creating and Executing Windows Applications
27 28
Creating an MFC Application Building and Executing the MFC Application
28 30
Creating a Windows Forms Application
Summary
31
35
xiii
Contents Chapter 2: Data, Variables, and Calculations The Structure of a C++ Program Program Comments The #include Directive — Header Files Namespaces and the Using Declaration
The main() Function Program Statements Whitespace Statement Blocks Automatically Generated Console Programs
37 38 44 45 46
46 47 49 49 50
Defining Variables
51
Naming Variables
51
Keywords in C++
Declaring Variables Initial Values for Variables
52
52 53
Fundamental Data Types
54
Integer Variables Character Data Types Integer Type Modifiers The Boolean Type Floating-Point Types
54 55 56 57 57
Fundamental Types in ISO/ANSI C++
Literals Defining Synonyms for Data Types Variables with Specific Sets of Values Specifying the Type for Enumeration Constants
58
59 60 60 62
Basic Input/Output Operations
62
Input from the Keyboard Output to the Command Line Formatting the Output Escape Sequences
62 63 64 65
Calculating in C++ The Assignment Statement Understanding Lvalues and Rvalues
Arithmetic Operations
xiv
67 67 68
68
The const Modifier Constant Expressions Program Input Calculating the Result Displaying the Result
70 70 71 71 73
Calculating a Remainder
73
Contents Modifying a Variable The Increment and Decrement Operators The Sequence of Calculation
73 74 77
Operator Precedence
77
Variable Types and Casting
78
Rules for Casting Operands Casts in Assignment Statements Explicit Casts Old-Style Casts The Bitwise Operators The The The The The
Bitwise Bitwise Bitwise Bitwise Bitwise
AND OR Exclusive OR NOT Shift Operators
Understanding Storage Duration and Scope Automatic Variables Positioning Variable Declarations Global Variables Static Variables
Namespaces Declaring a Namespace Multiple Namespaces
C++/CLI Programming
78 79 80 81 81 82 84 85 86 86
88 88 91 91 94
95 96 98
99
C++/CLI Specific: Fundamental Data Types C++/CLI Output to the Command Line C++/CLI Specific — Formatting the Output C++/CLI Input from the Keyboard Using safe_cast C++/CLI Enumerations
99 104 104 107 108 109
Specifying a Type for Enumeration Constants Specifying Values for Enumeration Constants
111 111
Summary Exercises
Chapter 3: Decisions and Loops Comparing Values The if Statement Nested if Statements The Extended if Statement Nested if-else Statements
112 113
115 115 117 118 120 122
xv
Contents Logical Operators and Expressions Logical AND Logical OR Logical NOT
The Conditional Operator The switch Statement Unconditional Branching
Repeating a Block of Statements What Is a Loop? Variations on the for Loop Using the continue Statement Floating-Point Loop Counters
The while Loop The do-while Loop Nested Loops
C++/CLI Programming The for each Loop
Summary Exercises
Chapter 4: Arrays, Strings, and Pointers Handling Multiple Data Values of the Same Type Arrays Declaring Arrays Initializing Arrays Character Arrays and String Handling String Input
Multidimensional Arrays Initializing Multidimensional Arrays
124 125 125 126
127 129 132
132 132 135 139 143
143 146 147
150 153
156 157
159 160 160 161 164 166 167
169 170
Indirect Data Access
172
What Is a Pointer? Declaring Pointers
172 173
The Address-Of Operator
Using Pointers The Indirection Operator Why Use Pointers?
Initializing Pointers Pointers to char
The sizeof Operator Constant Pointers and Pointers to Constants
xvi
173
174 174 174
176 177
181 183
Contents Pointers and Arrays Pointer Arithmetic Using Pointers with Multidimensional Arrays Pointer Notation with Multidimensional Arrays
Dynamic Memory Allocation The Free Store, Alias the Heap The new and delete Operators Allocating Memory Dynamically for Arrays Dynamic Allocation of Multidimensional Arrays
Using References What Is a Reference? Declaring and Initializing References
C++/CLI Programming Tracking Handles Declaring Tracking Handles
CLR Arrays Sorting One-Dimensional Arrays Searching One-Dimensional Arrays Multidimensional Arrays Arrays of Arrays
Strings Joining Strings Modifying Strings Searching Strings
Tracking References Interior Pointers
Summary Exercises
Chapter 5: Introducing Structure into Your Programs Understanding Functions Why Do You Need Functions? Structure of a Function The Function Header The Function Body The return Statement
Using a Function Function Prototypes
Passing Arguments to a Function The Pass-by-value Mechanism Pointers as Arguments to a Function
185 185 190 191
192 192 193 194 196
197 197 197
198 199 199
200 205 206 209 213
216 217 220 222
225 225
228 230
231 232 233 233 233 234 235
235 235
239 240 241
xvii
Contents Passing Arrays to a Function Passing Multi-Dimensional Arrays to a Function
References as Arguments to a Function Use of the const Modifier Arguments to main() Accepting a Variable Number of Function Arguments
Returning Values from a Function Returning a Pointer A Cast Iron Rule for Returning Addresses
Returning a Reference A Teflon-Coated Rule: Returning References
Static Variables in a Function
Recursive Function Calls Using Recursion
C++/CLI Programming Functions Accepting a Variable Number of Arguments Arguments to main()
Summary Exercises
Chapter 6: More about Program Structure Pointers to Functions Declaring Pointers to Functions A Pointer to a Function as an Argument Arrays of Pointers to Functions
243 245
247 249 250 252
254 254 256
258 260
260
262 264
265 266 267
268 269
271 271 272 275 277
Initializing Function Parameters Exceptions
277 279
Throwing Exceptions Catching Exceptions Exception Handling in the MFC
281 282 283
Handling Memory Allocation Errors Function Overloading What Is Function Overloading? When to Overload Functions
Function Templates
284 285 286 288
288
Using a Function Template
289
An Example Using Functions
291
Implementing a Calculator
291
Analyzing the Problem
292
Eliminating Blanks from a String Evaluating an Expression
xviii
294 295
Contents Getting the Value of a Term Analyzing a Number Putting the Program Together Extending the Program Extracting a Substring Running the Modified Program
C++/CLI Programming Understanding Generic Functions Defining Generic Functions Using Generic Functions
A Calculator Program for the CLR Removing Spaces from the Input String Evaluating an Arithmetic Expression Obtaining the Value of a Term Evaluating a Number Extracting a Parenthesized Substring
Summary Exercises
Chapter 7: Defining Your Own Data Types The struct in C++ What Is a struct? Defining a struct Initializing a struct Accessing the Members of a struct Intellisense Assistance with Structures The struct RECT Using Pointers with a struct Accessing Structure Members through a Pointer The Indirect Member Selection Operator
Data Types, Objects, Classes and Instances
298 299 302 304 305 307
308 309 309 310
315 316 316 318 318 319
320 321
323 324 324 324 325 325 329 330 330 332 332
332
First Class Operations on Classes Terminology
334 334 335
Understanding Classes
335
Defining a Class Access Control in a Class
Declaring Objects of a Class Accessing the Data Members of a Class Member Functions of a Class
336 336
336 337 339
xix
Contents Positioning a Member Function Definition Inline Functions
Class Constructors What Is a Constructor? The Default Constructor Assigning Default Parameter Values in a Class Using an Initialization List in a Constructor
Private Members of a Class Accessing private Class Members The friend Functions of a Class Placing friend Function Definitions Inside the Class
The Default Copy Constructor
The Pointer this const Objects of a Class const Member Functions of a Class Member Function Definitions Outside the Class
Arrays of Objects of a Class Static Members of a Class Static Data Members of a Class Static Function Members of a Class
Pointers and References to Class Objects Pointers to Class Objects References to Class Objects Implementing a Copy Constructor
C++/CLI Programming Defining Value Class Types The ToString() Function in a Class Literal Fields
Defining Reference Class Types Class Properties Defining Scalar Properties Trivial Scalar Properties Defining Indexed Properties More Complex Indexed Properties Static Properties Reserved Property Names
initonly Fields Static Constructors
Summary Exercises
xx
341 342
343 343 345 347 350
350 353 354 356
356
358 360 361 362
363 364 365 367
368 368 371 371
372 373 376 377
378 381 382 384 388 392 393 394
394 396
396 397
Contents Chapter 8: More on Classes Class Destructors What Is a Destructor? The Default Destructor Destructors and Dynamic Memory Allocation
399 399 399 400 402
Implementing a Copy Constructor Sharing Memory Between Variables
405 407
Defining Unions Anonymous Unions Unions in Classes and Structures
408 409 410
Operator Overloading Implementing an Overloaded Operator Implementing Full Support for an Operator Overloading the Assignment Operator Fixing the Problem
Overloading the Addition Operator Overloading the Increment and Decrement Operators
Class Templates Defining a Class Template Template Member Functions
Creating Objects from a Class Template Class Templates with Multiple Parameters
Using Classes The Idea of a Class Interface Defining the Problem Implementing the CBox Class Comparing CBox Objects Combining CBox Objects Analyzing CBox Objects
Defining the CBox Class Adding Data Members Defining the Constructor Adding Function Members Adding Global Functions
Using Our CBox Class
Organizing Your Program Code Naming Program Files
C++/CLI Programming Overloading Operators in Value Classes Overloading the Increment and Decrement Operators Overloading Operators in Reference Classes
Summary Exercises
410 411 414 418 418
423 426
427 428 430
431 434
436 436 436 437 438 439 441
445 446 447 448 453
455
458 460
461 461 467 467
470 471
xxi
Contents Chapter 9: Class Inheritance and Virtual Functions Basic Ideas of OOP Inheritance in Classes
473 473 475
What Is a Base Class? Deriving Classes from a Base Class
475 476
Access Control Under Inheritance
479
Constructor Operation in a Derived Class Declaring Class Members to be Protected The Access Level of Inherited Class Members
The Copy Constructor in a Derived Class Class Members as Friends Friend Classes Limitations on Class Friendship
Virtual Functions What Is a Virtual Function? Using Pointers to Class Objects Using References With Virtual Functions Incomplete Class Definitions
Pure Virtual Functions Abstract Classes Indirect Base Classes Virtual Destructors
Casting Between Class Types Nested Classes C++/CLI Programming Inheritance in C++/CLI Classes Interface Classes Defining Interface Classes Classes and Assemblies Visibility Specifiers for Classes and Interfaces Access Specifiers for Class and Interface Members
Functions Specified as new Delegates and Events Declaring Delegates Creating Delegates Unbound Delegates Creating Events
Destructors and Finalizers in Reference Classes Generic Classes Generic Interface Classes Generic Collection Classes
Summary Exercises
xxii
482 486 489
490 495 496 496
497 499 501 503 504
505 505 508 511
516 516 520 520 526 527 531 531 531
536 536 537 537 541 545
549 551 554 555
561 562
Contents Chapter 10: Debugging Techniques Understanding Debugging Program Bugs Common Bugs
Basic Debugging Operations Setting Breakpoints Advanced Breakpoints
Setting Tracepoints Starting Debugging Inspecting Variable Values Viewing Variables in the Edit Window
Changing the Value of a Variable
Adding Debugging Code Using Assertions Adding Your Own Debugging Code
565 565 567 567
568 570 572
572 573 576 577
577
578 578 580
Debugging a Program
585
The Call Stack Step Over to the Error
585 587
Testing the Extended Class Finding the Next Bug
Debugging Dynamic Memory Functions Checking the Free Store Controlling Free Store Debug Operations Free Store Debugging Output
Debugging C++/CLI Programs Using the Debug and Trace Classes Generating Output Setting the Output Destination Indenting the Output Controlling Output Assertions
Summary
Chapter 11: Windows Programming Concepts Windows Programming Basics Elements of a Window Windows Programs and the Operating System Event-Driven Programs Windows Messages The Windows API Windows Data Types Notation in Windows Programs
591 593
593 594 595 596
602 602 603 604 604 605 607
611
613 614 614 616 617 617 617 618 619
xxiii
Contents The Structure of a Windows Program The WinMain() Function Specifying a Program Window Creating a Program Window Initializing the Program Window Dealing with Windows Messages A Complete WinMain() Function
Message Processing Functions The WindowProc() Function Decoding a Windows Message Ending the Program A Complete WindowProc() Function
A Simple Windows Program
620 621 623 625 627 627 631
632 633 633 636 636
637
Windows Program Organization The Microsoft Foundation Classes
638 640
MFC Notation How an MFC Program Is Structured
640 640
The Application Class The Window Class Completing the Program The Finished Product
Using Windows Forms Summary
Chapter 12: Windows Programming with the Microsoft Foundation Classes The Document/View Concept in MFC What Is a Document? Document Interfaces What Is a View? Linking a Document and Its Views Document Templates Document Template Classes
641 642 642 643
645 647
649 650 650 650 651 652 652 653
Your Application and MFC
653
Creating MFC Applications
655
Creating an SDI Application The Output from the MFC Application Wizard Viewing Project Files Viewing Classes The Class Definitions Creating an Executable Module
xxiv
657 660 662 663 664 667
Contents Running the Program How the Program Works
668 669
Creating an MDI Application
671
Running the Program
Summary Exercises
Chapter 13: Working with Menus and Toolbars Communicating with Windows
672
674 674
677 677
Understanding Message Maps
678
Message Handler Definitions
679
Message Categories Handling Messages in Your Program How Command Messages Are Processed
Extending the Sketcher Program Elements of a Menu
681 682 682
683 684
Creating and Editing Menu Resources
684
Adding a Menu Item to the Menu Bar Adding Items to the Element Menu Modifying Existing Menu Items Completing the Menu
684 686 687 687
Adding Handlers for Menu Messages Choosing a Class to Handle Menu Messages Creating Menu Message Functions Coding Menu Message Functions Adding Members to Store Color and Element Mode Initializing the New Class Data Members Running the Extended Example
Adding Message Handlers to Update the User Interface Coding a Command Update Handler Exercising the Update Handlers
Adding Toolbar Buttons Editing Toolbar Button Properties Exercising the Toolbar Buttons Adding Tooltips
Summary Exercises
688 690 690 692 692 694 696
697 697 699
700 701 703 703
704 705
xxv
Contents Chapter 14: Drawing in a Window
707
Basics of Drawing in a Window
707
The Window Client Area The Windows Graphical Device Interface What Is a Device Context? Mapping Modes
The Drawing Mechanism in Visual C++ The View Class in Your Application The OnDraw() Member Function
The CDC Class Displaying Graphics Drawing in Color
708 709 709 709
711 711 711
712 713 717
Drawing Graphics in Practice Programming the Mouse
721 725
Messages from the Mouse
725
WM_LBUTTONDOWN WM_MOUSEMOVE WM_LBUTTONUP
Mouse Message Handlers Drawing Using the Mouse Getting the Client Area Redrawn Defining Classes for Elements The CElement Class The CLine Class Calculating the Enclosing Rectangle for a Line The CRectangle Class The CCircle Class The CCurve Class Completing the Mouse Message Handlers
Exercising Sketcher Running the Example Capturing Mouse Messages
Summary Exercises
Chapter 15: Creating the Document and Improving the View What Are Collection Classes? Types of Collection The Type-Safe Collection Classes
xxvi
726 726 727
727 729 731 732 736 737 742 742 744 746 747
753 754 755
756 757
759 759 760 761
Contents Collections of Objects
761
The CArray Template Class Helper Functions The CList Template Class The CMap Template Class
761 763 763 768
The Typed Pointer Collections
771
The CTypedPtrList Template Class CTypePtrList Operations
771 771
Using the CList Template Class
773
Drawing a Curve Defining the CCurve Class Implementing the CCurve Class Exercising the CCurve Class
Creating the Document Using a CTypedPtrList Template Implementing the Document Destructor Drawing the Document Adding an Element to the Document Exercising the Document
Improving the View Updating Multiple Views Scrolling Views Logical Coordinates and Client Coordinates Dealing with Client Coordinates
Using MM_LOENGLISH Mapping Mode
Deleting and Moving Shapes Implementing a Context Menu Associating a Menu with a Class Choosing a Context Menu Identifying a Selected Element Exercising the Pop-Ups Checking the Context Menu Items
Highlighting Elements Drawing Highlighted Elements Exercising the Highlights
Servicing the Menu Messages Deleting an Element Moving an Element Getting the Elements to Move Themselves Exercising the Application
Dealing with Masked Elements Summary Exercises
774 775 777 778
779 779 780 781 783 784
785 785 787 789 790
792
793 794 795 797 798 800 800
802 806 807
807 807 808 811 814
814 815 816
xxvii
Contents Using a List Box Removing the Scale Dialog Creating a List Box Control Creating the Dialog Class Displaying the Dialog
Using an Edit Box Control Creating an Edit Box Resource Creating the Dialog Class The CString Class
Adding the Text Menu Item Defining a Text Element Implementing the CText Class The CText Constructor Drawing a CText Object Moving a CText Object
Creating a Text Element
Summary Exercises
Chapter 17: Storing and Printing Documents Understanding Serialization Serializing a Document Serialization in the Document Class Definition Serialization in the Document Class Implementation The Serialize() Function The CArchive Class
Functionality of CObject-Based Classes The Macros Adding Serialization to a Class
How Serialization Works How to Implement Serialization for a Class
Applying Serialization Recording Document Changes Serializing the Document Serializing the Element Classes The Serialize() Functions for the Shape Classes
852 852 853 854 855
856 856 858 858
859 860 861 861 862 862
863
864 865
867 867 868 868 869 870 870
872 872
873 874
874 874 876 877 879
Exercising Serialization Moving Text Printing a Document
881 882 884
The Printing Process
885
The CPrintInfo Class
886
xxix
Contents Chapter 16: Working with Dialogs and Controls Understanding Dialogs Understanding Controls Common Controls
Creating a Dialog Resource Adding Controls to a Dialog Box Testing the Dialog
Programming for a Dialog
817 817 818 820
820 820 822
822
Adding a Dialog Class Modal and Modeless Dialogs Displaying a Dialog
823 824 824
Code to Display the Dialog Code to Close the Dialog
826 827
Supporting the Dialog Controls
828
Initializing the Controls Handling Radio Button Messages
Completing Dialog Operations Adding Pen Widths to the Document Adding Pen Widths to the Elements Creating Elements in the View Exercising the Dialog
Using a Spin Button Control Adding the Scale Menu Item and Toolbar Button Creating the Spin Button The Controls’ Tab Sequence
Generating the Scale Dialog Class Dialog Data Exchange and Validation Initializing the Dialog
Displaying the Spin Button
Using the Scale Factor Scaleable Mapping Modes Setting the Document Size Setting the Mapping Mode Implementing Scrolling with Scaling Setting Up the Scrollbars
Working with Status Bars
828 830
831 832 832 833 834
835 835 835 838
838 840 840
841
842 842 844 844 846 847
848
Adding a Status Bar to a Frame
848
Defining the Status Bar Parts Updating the Status Bar
850 851
xxviii
Contents Implementing Multipage Printing
888
Getting the Overall Document Size Storing Print Data Preparing to Print Cleaning Up After Printing Preparing the Device Context Printing the Document Getting a Printout of the Document
889 890 891 892 893 894 898
Summary Exercises
Chapter 18: Writing Your Own DLLs Understanding DLLs How DLLs Work Run-Time Dynamic Linking
Contents of a DLL The DLL Interface The DllMain() Function
DLL Varieties MFC Extension DLL Regular DLL — Statically Linked to MFC Regular DLL — Dynamically Linked to MFC
Deciding What to Put in a DLL Writing DLLs Writing and Using an Extension DLL Understanding DllMain() Adding Classes to the Extension DLL Exporting Classes from the Extension DLL Building a DLL Using the Extension DLL in Sketcher Files Required to Use a DLL
Exporting Variables and Functions from a DLL Importing Symbols into a Program Implementing the Export of Symbols from a DLL Using Exported Symbols
Summary Exercises
xxx
898 899
901 901 903 904
906 906 906
906 906 907 907
907 908 908 910 911 912 913 914 915
916 917 917 918
920 920
Contents Chapter 19: Connecting to Data Sources Database Basics A Little SQL Retrieving Data Using SQL Choosing Records
921 921 924 924 925
Joining Tables Using SQL Sorting Records
926 929
Database Support in MFC
929
MFC Classes Supporting ODBC
930
Creating a Database Application
931
Registering an ODBC Database Generating an MFC ODBC Program
931 933
Snapshot versus Dynaset Recordsets
935
Understanding the Program Structure
936
Understanding Recordsets Understanding the Record View Creating the View Dialog Linking the Controls to the Recordset
Exercising the Example
Sorting a Recordset Modifying the Window Caption
Using a Second Recordset Object Adding a Recordset Class Adding a View Class for the Recordset Creating the Dialog Resource Creating the Record View Class
Customizing the Recordset
937 941 943 946
948
948 949
950 950 954 954 955
957
Adding a Filter to the Recordset Defining the Filter Parameter Initializing the Record View
958 958 960
Accessing Multiple Table Views
961
Switching Views Enabling the Switching Operation Handling View Activation
Viewing Orders for a Product
Viewing Customer Details Adding the Customer Recordset Creating the Customer Dialog Resource Creating the Customer View Class Adding a Filter Implementing the Filter Parameter
961 963 965
966
967 967 968 968 970 972
xxxi
Contents Linking the Order Dialog to the Customer Dialog Exercising the Database Viewer
Summary Exercises
Chapter 20: Updating Data Sources Update Operations CRecordset Update Operations Checking that Operations are Legal Record Locking
Transactions CDatabase Transaction Operations
A Simple Update Example
973 976
976 977
979 979 980 981 982
982 983
984
Customizing the Application
986
Managing the Update Process
988
Implementing Update Mode
990
Enabling and Disabling Edit Controls Changing the Button Label Controlling the Visibility of the Cancel Button Disabling the Record Menu Expediting the Update Implementing the Cancel Operation
Adding Rows to a Table The Order Entry Process Creating the Resources Creating the Recordsets Creating the Recordset Views Adding Controls to the Dialog Resources Implementing Dialog Switching Creating an Order ID Storing the New Order ID Creating the New Order ID Initiating ID Creation
Storing the Order Data Setting Dates
Selecting Products for an Order Adding a New Order
Summary Exercises
xxxii
991 992 993 994 996 997
999 1000 1001 1002 1002 1006 1010 1014 1014 1015 1017
1019 1020
1021 1023
1028 1029
Contents Chapter 21: Applications Using Windows Forms Understanding Windows Forms Understanding Windows Forms Applications Modifying the Properties of a Form How the Application Starts
Customizing the Application GUI Adding Controls to a Form Adding Menus Adding Submenus
Adding a Tab Control Using GroupBox Controls Using Button Controls Using the WebBrowser Control Operation of the Winning Application Adding a Context Menu Creating Event Handlers Event Handlers for Menu Items Adding Members to the Form1 Class Handling the Play Menu Event
Handling Events for the Limits Menu Creating a Dialog Box Adding a List to a ListBox Handling the Dialog Button Events Controlling the State of the ListBox Objects Creating the Dialog Object
Using the Dialog Box Validating the Input Handler the Reset Menu Item Event
Adding the Second Dialog
1031 1031 1032 1034 1035
1035 1036 1037 1038
1040 1042 1044 1047 1048 1049 1049 1050 1050 1052
1056 1056 1058 1060 1061 1061
1062 1063 1067
1068
Getting the Data from the Dialog Controls Disabling Input Controls Updating the Limits Menu Item Handlers
1070 1073 1074
Implementing the Help | About Menu Item Handling a Button Click Responding to the Context Menu
1075 1076 1079
The Logic for Dealing with the Choose Menu Item Creating the Dialog Form Developing the Dialog Class Handling the Click Event for the ChooseMenu
Summary Exercises
1080 1080 1081 1083
1086 1087
xxxiii
Contents Chapter 22: Accessing Data Sources in a Windows Forms Application Working with Data Sources Accessing and Displaying Data Using a DataGridView Control Using a DataGridView Control in Unbound Mode Customizing a DataGridView Control Customizing Header Cells Customizing Non-Header Cells Setting Up the Data Setting Up the Control Setting Up the Column Headers Formatting a Column Customizing Alternate Rows
Dynamically Setting Cell Styles
Using Bound Mode The BindingSource Component Using the BindingNavigator Control Binding to Individual Controls Working with Multiple Tables Summary Exercises
1089 1089 1090 1091 1093 1099 1101 1101 1102 1103 1105 1106 1108
1108
1114 1115 1120 1123 1127 1129 1129
Appendix A: C++ Keywords
1131
Appendix B: ASCII Codes
1133
Index
xxxiv
1139
Introduction Welcome to Beginning Visual C++ 2005. With this book you can become an effective C++ programmer. The latest development system from Microsoft, Visual Studio 2005, supports two distinct but closely related flavors of the C++ language; it fully supports the original ISO/ANSI standard C++, and you also get support for a new version of C++ called C++/CLI that was developed by Microsoft but is now an ECMA standard. These two versions of C++ are complementary and fulfill different roles. ISO/ANSI C++ is there for the development of high-performance applications that run natively on your computer whereas C++/CLI has been developed specifically for the .NET Framework. This book will teach you the essentials of programming applications in both versions of C++. You get quite a lot of assistance from automatically generated code when writing ISO/ANSI C++ programs, but you still need to write a lot of C++ yourself. You need a solid understanding of object-oriented programming techniques, as well as a good appreciation of what’s involved in programming for Windows. Although C++/CLI targets the .NET Framework, it also is the vehicle for the development of Windows Forms applications that you can develop with little or in some cases no, explicit code writing. Of course, when you do have to add code to a Windows Forms application, even though it may be a very small proportion of the total, you still need an in-depth knowledge of the C++/CLI language. ISO/ANSI C++ remains the language of choice for many professionals, but the speed of development that C++/CLI and Windows Forms applications bring to the table make that essential, too. For this reason I decided to cover the essentials of both flavors of C++ in this book.
Who This Book Is For This book is aimed at teaching you how to write C++ applications for the Microsoft Windows operating system using Visual C++ 2005 or any edition of Visual Studio 2005. I make no assumptions about prior knowledge of any particular programming language. This tutorial is for you if: ❑
You have a little experience of programming in some other language, such as BASIC or Pascal, for example, and you are keen to learn C++ and develop practical Microsoft Windows programming skills.
❑
You have some experience in C or C++, but not in a Microsoft Windows context and want to extend your skills to program for the Windows environment using the latest tools and technologies.
❑
You are a newcomer to programming and sufficiently keen to jump in and the deep end with C++. To be successful you need to have at least a rough idea of how your computer works, including the way in which the memory is organized and how data and instructions are stored.
Introduction
What This Book Covers My objective with this book is to teach you the essentials of C++ programming using both of the technologies supported by Visual C++ 2005. The book provides a detailed tutorial on both flavors of the C++ language, on native ISO/ANSI C++ Windows application development using the Microsoft Foundation Classes (MFC) and on the development of C++/CLI Windows applications using Windows Forms. Because of the importance and pervasiveness of database technology today, the book also includes introductions to the techniques you can use for accessing data sources in both MFC and Windows Forms applications. MFC applications are relatively coding-intensive compared to Windows Forms applications. This is because you create the latter using a highly developed design capability in Visual C++ 2005 that enables you to assemble the entire graphical user interface (GUI) for an application graphically and have all the code generated automatically. For this reason, there are more pages in the book devoted to MFC programming than to Windows Forms programming.
How This Book Is Structured The contents of the book are structured as follows:
xxxvi
❑
Chapter 1 introduces you to the basic concepts you need to understand for programming in C++ for native applications and for .NET Framework applications, together with the main ideas embodied in the Visual C++ 2005 development environment. It describes how you use the capabilities of Visual C++ 2005 for creating the various kinds of C++ applications you learn about in the rest of the book.
❑
Chapters 2 to 10 are dedicated to teaching you both versions of the C++ language, plus the basic ideas and techniques involved in debugging. The content of each of the Chapters 2 to 10 is structured in a similar way; the first half of each chapter deals with ISO/ANSI C++ topics, and the second half deals with C++/CLI.
❑
Chapter 11 discusses how Microsoft Windows applications are structured and describes and demonstrates the essential elements that are present in every Windows application. The chapter explains elementary examples of Windows applications using ISO/ANSI C++ and the Windows API and the MFC, as well as an example of a basic Windows Forms application in C++/CLI.
❑
Chapters 12 to 17 describe in detail the capabilities provided by the MFC for building a GUI. You learn how you create and use common controls to build the graphical user interface for your application and how you handle the events that result from user interactions with your program. In the process, you create a substantial working application. In addition to the techniques you learn for building a GUI, the application that you develop also shows you how you use MFC to print documents and to save them on disk.
❑
Chapter 18 teaches you the essentials you need to know for creating your own libraries using MFC. You learn about the different kinds of libraries you can create, and you develop working examples of these that work with the application that you have evolved over the preceding six chapters.
❑
In Chapters 19 and 20, you learn about accessing data sources in an MFC application. You gain experience in accessing a database in read-only mode; then you learn the fundamental programming techniques for updating a database using MFC. The examples use the Northwind database that can be downloaded from the Web, but you can also apply the techniques described to your own data source.
Introduction ❑
In Chapter 21 you work with Windows Forms and C++/CLI to build an example that teaches you how to create, customize, and use Windows Forms controls in an application. You gain practical experience by building an application incrementally throughout the chapter.
❑
Chapter 22 builds on the knowledge you gain in Chapter 21 and shows how the controls available for accessing data sources work, and how you customize them. You also learn how you can create an application for accessing a database with virtually no coding at all on your part.
All chapters include numerous working examples that demonstrate the programming techniques that are discussed. Every chapter concludes with a summary of the key points that were covered, and most chapters include a set of exercises at the end that you can attempt to apply what you have learned. Solutions to the exercises together with all the code from the book are available for download from the publisher’s Web site (see the “Source Code” section later in this Introduction for more details). The tutorial on the C++ language uses examples that are console programs with simple command-line input and output. This approach enables you to learn the various capabilities of C++ without getting bogged down in the complexities of Windows GUI programming. Programming for Windows is really only practicable after you have a thorough understanding of the programming language. If you want to keep things as simple as possible, you can just learn ISO/ANSI C++ programming in the first instance. Each of the chapters that cover the C++ language (Chapters 2 to 10) first discusses particular aspects of the capabilities of ISO/ANSI C++ followed by the new features introduced by C++/CLI in the same context. The reason for organizing things this way is that C++/CLI is defined as an extension to the ISO/ANSI standard language, so an understanding of C++/CLI is predicated on knowledge of ISO/ANSI C++. Thus, you can just read the ISO/ANSI topics in each of Chapters 2 to 20 and ignore the C++/CLI sections that follow. You then can to progress to Windows application development with ISO/ANSI C++ without having to keep the two versions of the language in mind. You can return to C++/CLI when you are comfortable with ISO/ANSI C++. Of course, you can also work straight through and add to your knowledge of both versions of the C++ language incrementally.
What You Need to Use This Book To use this book you need any of Visual Studio 2005 Standard Edition, Visual Studio 2005 Professional Edition, or Visual Studio 2005 Team System. Note that Visual C++ Express 2005 is not sufficient because the MFC is not included. Visual Studio 2005 requires Windows XP Service Pack 2 or Windows 2000 Service Pack 4.To install any of the three Visual Studio 2005 editions identified you need to have a 1 GHz processor with at least 256MB of memory and at least 1GB of space available on your system drive and 2GB available on the installation drive. To install the full MSDN documentation that comes with the product you’ll need an additional 1.8GB available on the installation drive. The database examples in the book use the Northwind Traders database. You can find the download for this database by searching for “Northwind Traders” on http://msdn.microsoft.com. Of course, you can also adapt the examples to work with a database of your choice. Most importantly, to get the most out of this book you need a willingness to learn, and a determination to master the most powerful programming tool for Windows applications presently available. You need the dedication to type in and work through all the examples and try out the exercises in the book. This sounds more difficult than it is, and I think you’ll be surprised how much you can achieve in a relatively
xxxvii
Introduction short period of time. Keep in mind that everybody who learns programming gets bogged down from time to time, but if you keep at it, things become clearer and you’ll get there eventually. This book helps you to start experimenting on your own and, from there, to become a successful C++ programmer.
Conventions To help you get the most from the text and keep track of what’s happening, a number of conventions are used throughout the book.
Try It Out The Try It Out is an exercise you should work through, following the text in the book.
How It Works After many Try It Outs, a How It Works section explains the code you’ve typed in detail.
Boxes like this one hold important, not-to-be forgotten information that is directly relevant to the surrounding text.
Tips, hints, tricks, and asides to the current discussion are offset and placed in italics like this. As for styles in the text: ❑
New terms and important words appear bold when first introduced.
❑
Keyboard strokes are shown like this: Ctrl+A.
❑
Filenames, URLs, and code within the text appear like so: persistence.properties.
❑
Code is presented in two different ways:
In code examples I highlight new and important code with a gray background. The gray highlighting is used for code that’s less important in the present context, or has been shown before.
Source Code As you work through the examples in this book, you may choose either to type in all the code manually or to use the source code files that accompany the book. All of the source code used in this book is available for download at http://www.wrox.com. At the site, simply locate the book’s title (either by using the Search box or by using one of the title lists) and click the Download Code link on the book’s detail page to obtain all the source code for the book.
xxxviii
Introduction Because many books have similar titles, you may find it easiest to search by ISBN; this book’s ISBN is 0-7645-7197-4 (changing to 978-0-7645-7197-8 as the new industry-wide 13-digit ISBN numbering system is phased in by January 2007). After you download the code, just decompress it with your favorite compression tool. Alternatively, you can go to the main Wrox code download page at http://www.wrox.com/dynamic/books/ download.aspx to see the code available for this book and all other Wrox books.
Errata We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you find an error in one of our books, like a spelling mistake or faulty piece of code, we would be very grateful for your feedback. By sending in errata you may save another reader hours of frustration and at the same time you will be helping us provide even higher quality information. To find the errata page for this book, go to http://www.wrox.com and locate the title using the Search box or one of the title lists. Then, on the book details page, click the Book Errata link. On this page you can view all errata that has been submitted for this book and posted by Wrox editors. A complete book list including links to each book’s errata is also available at www.wrox.com/misc-pages/booklist .shtml. If you don’t spot “your” error on the Book Errata page, go to www.wrox.com/contact/techsupport .shtml and complete the form there to send us the error you have found. We’ll check the information and, if appropriate, post a message to the book’s errata page and fix the problem in subsequent editions of the book.
p2p.wrox.com For author and peer discussion, join the P2P forums at p2p.wrox.com. The forums are a Web-based system for you to post messages relating to Wrox books and related technologies and interact with other readers and technology users. The forums offer a subscription feature to e-mail you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums. At http://p2p.wrox.com you will find a number of different forums that will help you not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps:
1. 2. 3.
Go to p2p.wrox.com and click the Register link.
4.
You will receive an e-mail with information describing how to verify your account and complete the joining process.
Read the terms of use and click Agree. Complete the required information to join as well as any optional information you wish to provide and click Submit.
xxxix
1 Programming with Visual C++ 2005 Windows programming isn’t difficult. In fact, Microsoft Visual C++ 2005 makes it remarkably easy, as you’ll see throughout the course of this book. There’s just one obstacle in your path: Before you get to the specifics of Windows programming, you have to be thoroughly familiar with the capabilities of the C++ programming language, particularly the object-oriented aspects of the language. Object-oriented techniques are central to the effectiveness of all the tools that are provided by Visual C++ 2005 for Windows programming, so it’s essential that you gain a good understanding of them. That’s exactly what this book provides. This chapter gives you an overview of the essential concepts involved in programming applications in C++. You’ll take a rapid tour of the Integrated Development Environment (IDE) that comes with Visual C++ 2005. The IDE is straightforward and generally intuitive in its operation, so you’ll be able to pick up most of it as you go along. The best approach to getting familiar with it is to work through the process of creating, compiling, and executing a simple program. By the end of this chapter, you will have learned: ❑
What the principal components of Visual C++ 2005 are
❑
What the .NET Framework consists of and the advantages it offers
❑
What solutions and projects are and how you create them
❑
About console programs
❑
How to create and edit a program
❑
How to compile, link, and execute C++ console programs
❑
How to create and execute basic Windows programs
So power up your PC, start Windows, load the mighty Visual C++ 2005, and begin your journey.
Introduction You can read messages in the forums without joining P2P but in order to post your own messages, you must join. After you join, you can post new messages and respond to messages other users post. You can read messages at any time on the Web. If you would like to have new messages from a particular forum e-mailed to you, click the Subscribe to this Forum icon by the forum name in the forum listing. For more information about how to use the Wrox P2P, be sure to read the P2P FAQs for answers to questions about how the forum software works as well as many common questions specific to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page.
xl
Chapter 1
The .NET Framework The .NET Framework is a central concept in Visual C++ 2005 as well as in all the other .NET development products from Microsoft. The .NET Framework consists of two elements: the Common Language Runtime (CLR) in which your application executes, and a set of libraries called the .NET Framework class libraries. The .NET Framework class libraries provide the functional support your code will need when executing with the CLR, regardless of the programming language used, so .NET programs written in C++, C#, or any of the other languages that support the .NET Framework all use the same .NET libraries. There are two fundamentally different kinds of C++ applications you can develop with Visual C++ 2005. You can write applications that natively execute on your computer. These applications will be referred to as native C++ programs. You write native C++ programs in the version of C++ that is defined by the ISO/ANSI language standard. You can also write applications to run under the control of the CLR in an extended version of C++ called C++/CLI. These programs will be referred to as CLR programs, or C++/CLI programs. The .NET Framework is not strictly part of Visual C++ 2005 but rather a component of the Windows operating system that makes it easier to build software applications and Web services. The .NET Framework offers substantial advantages in code reliability and security, as well as the ability to integrate your C++ code with code written in over 20 other programming languages that target the .NET Framework. A slight disadvantage of targeting the .NET Framework is that there is a small performance penalty, but you won’t notice this in the majority of circumstances.
The Common Language Runtime (CLR) The CLR is a standardized environment for the execution of programs written in a wide range of highlevel languages including Visual Basic, C#, and of course C++. The specification of the CLR is now embodied in the European Computer Manufacturers (ECMA) standard for the Common Language Infrastructure (CLI), ECMA-335, and also in the equivalent ISO standard, ISO/IEC 23271, so the CLR is an implementation of this standard. You can see why C++ for the CLR is referred to as C++/CLI — it’s C++ for the Common Language Infrastructure, so you are likely to see C++/CLI compilers on other operating systems that implement the CLI. Note that information on all ECMA standards is available from http://www.ecma-international. org and ECMA-335 is currently available as a free download.
The CLI is essentially a specification for a virtual machine environment that enables applications written in diverse high-level programming languages to be executed in different system environments without changing or recompiling the original source code. The CLI specifies a standard intermediate language for the virtual machine to which the high-level language source code is compiled. With the .NET Framework, this intermediate language is referred to as Microsoft Intermediate Language (MSIL). Code in the intermediate language is ultimately mapped to machine code by a just-in-time (JIT) compiler when you execute a program. Of course, code in the CLI intermediate language can be executed within any other environment that has a CLI implementation.
2
Programming with Visual C++ 2005 The CLI also defines a common set of data types called the Common Type System (CTS) that should be used for programs written in any programming language targeting a CLI implementation. The CTS specifies how data types are used within the CLR and includes a set of predefined types. You may also define your own data types, and these must be defined in a particular way to be consistent with the CLR, as you’ll see. Having a standardized type system for representing data allows components written in different programming languages to handle data in a uniform way and makes it possible to integrate components written in different languages to be integrated into a single application. Data security and program reliability is greatly enhanced by the CLR, in part because dynamic memory allocation and release for data is fully automatic but also because the MSIL code for a program is comprehensively checked and validated before the program executes. The CLR is just one implementation of the CLI specification that executes under Microsoft Windows on a PC; there will undoubtedly be other implementations of the CLI for other operating system environments and hardware platforms. You’ll sometimes find that the terms CLI and CLR used interchangeably, although it should be evident that they are not the same things. The CLI is a standard specification; the CLR is Microsoft’s implementation of the CLI.
Writing C++ Applications You have tremendous flexibility in the types of applications and program components that you can develop with Visual C++ 2005. As noted earlier in this chapter, you have two basic options for Windows applications: you can write code that executes with the CLR, and you can also write code that compiles directly to machine code and thus executes natively. For window-based applications targeting the CLR, you use Windows Forms as the base for the GUI provided by the .NET Framework libraries. Using Windows Forms enables rapid GUI development because you assemble the GUI graphically from standard components and have the code generated completely automatically. You then just need to customize the code that has been generated to provide the functionality you require. For natively executing code, you have several ways to go. One possibility is to use the Microsoft Foundation Classes (MFC) for programming the graphical user interface for your Windows application. The MFC encapsulates the Windows operating system Application Programming Interface (API) for GUI creation and control and greatly eases the process of program development. The Windows API originated long before the C++ language arrived on the scene so it has none of the object-oriented characteristics that would be expected if it were written today; however, you are not obliged to use the MFC. If you want the ultimate in performance, you can write your C++ code to access the Windows API directly. C++ code that executes with the CLR is described as managed C++ because data and code is managed by the CLR. In CLR programs, the release of memory that you have allocated dynamically for storing data is taken care of automatically, thus eliminating a common source of error in native C++ applications. C++ code that executes outside of the CLR is sometimes described by Microsoft as unmanaged C++ because the CLR is not involved in its execution. With unmanaged C++ you must take care of all aspects allocating and releasing memory during execution of your program yourself, and you also forego the enhanced security provided by the CLR. You’ll also see unmanaged C++ referred to as native C++ because it compiles directly to native machine code. Figure 1-1 shows the basic options you have for developing C++ applications.
3
Chapter 1
Managed C++
Native C++
Native C++
Framework Classes
MFC
Common Language Runtime
Operating System
Hardware
Figure 1-1
Figure 1-1 is not the whole story. An application can consist partly of managed C++ and partly of native C++, so you are not obliged to stick to one environment or the other. Of course, you do lose out somewhat by mixing the code, so you would choose to follow this approach only when necessary, such as when you want to convert an existing native C++ application to run with the CLR. You obviously won’t get the benefits inherent in managed C++ in the native C++ code, and there can also be appreciable overhead involved in communications between the managed and unmanaged code components. The ability to mix managed and unmanaged code can be invaluable, however, when you need to develop or extend existing unmanaged code but also want to obtain the advantages of using the CLR. Of course, for new applications you should decide whether you want to create it as a managed C++ application at the outset.
Learning Windows Programming There are always two basic aspects to interactive applications executing under Windows: you need code to create the Graphical User Interface (the GUI) with which the user interacts, and you need code to process these interactions to provide the functionality of the application. Visual C++ 2005 provides you with a great deal of assistance in both aspects of Windows application development. As you’ll see later in this chapter, you can create a working Windows program with a GUI without writing any code yourself at all. All the basic code to create the GUI can be generated automatically by Visual C++ 2005; however, it’s essential to understand how this automatically generated code works because you need to extend and modify it to make it do what you want, and to do that you need a comprehensive understanding of C++.
4
Programming with Visual C++ 2005 For this reason, you’ll first learn C++ — both the native C++ and C++/CLI versions of the language — without getting involved in Windows programming considerations. After you’re comfortable with C++, you’ll learn how you develop fully-fledged Windows applications using native C++ and C++/CLI. This means that while you are learning C++, you’ll be working with programs that just involved command line input and output. By sticking to this rather limited input and output capability, you’ll be able to concentrate of the specifics of how the C++ language works and avoid the inevitable complications involved in GUI building and control. After you become comfortable with C++, you’ll find that it’s an easy and natural progression to applying C++ to the development of Windows application programs.
Learning C++ Visual C++ 2005 fully supports two versions of C++ defined by two separate standards: ❑
The ISO/ANSI C++ standard is for implementing native applications — unmanaged C++. This version of C++ is supported on the majority of computer platforms.
❑
The C++/CLI standard is designed specifically for writing programs that target the CLR and is an extension to the ISO/ANSI C++.
Chapters 2 through 10 of this book teach you the C++ language. Because C++/CLI is an extension of ISO/ANSI C++, the first part of each chapter introduces elements of the ISO/ANSI C++ language; the second part explains the additional features that C++/CLI introduces. Writing programs in C++/CLI allows you to take full advantage of the capabilities of the .NET Framework, something that is not possible with programs written in ISO/ANSI C++. Although C++/CLI is an extension of ANSI/ISO C++, to be able to execute your program fully with the CLR means that it must conform to the requirements of the CLR. This implies that there are some features of ANSI/ISO C++ that you cannot use in your CLR programs. One example of this that you might deduce from what I have said up to now is that the dynamic memory allocation and release facilities offered by ISO/ANSI C++ are not compatible with the CLR; you must use the CLR mechanism for memory management and this implies that you must use C++/CLI classes, not native C++ classes.
The C++ Standards The ISO/ANSI standard is defined by the document ISO/IEC 14882 that is published by the American National Standards Institute (ANSI). ISO/ANSI standard C++ is the well-established version of C++ that has been around since 1998 and is supported by compilers on the majority of computer hardware platforms and operating systems. Programs that you write in ISO/ANSI C++ can be ported from one system environment to another reasonably easily, although the library functions that a program uses — particularly those related to building a graphical user interface — are a major determinant of how easy or difficult it will be. ISO/ANSI standard C++ has been the first choice of many professional program developers because it is so widely supported, and because is one of the most powerful programming languages available today. The ISO/ANSI standard for C++ can be purchased from http://www.iso.org. C++/CLI is a version of C++ that extends the ISO/ANSI standard for C++ to better support the Common Language Infrastructure (CLI) that is defined by the standard ECMA-355. The first draft of this standard appeared in 2003 and was developed from an initial technical specification that was produced by Microsoft to support the execution of C++ programs with the .NET Framework. Thus both the CLI and C++/CLI were originated by Microsoft in support of the .NET Framework. Of course, standardizing
5
Chapter 1 the CLI and C++/CLI greatly increases the likelihood of implementations in environments other than Windows. It’s important to appreciate that although C++/CLI is an extension of ISO/ANSI C++, there are features of ISO/ANSI C++ that you must not use when you want your program to execute fully under the control of the CLR. You’ll learn what these are as you progress through the book. The CLR offers substantial advantages over the native environment. By targeting your C++ programs at the CLR, your programs will be more secure and not prone to the potential errors you can make when using the full power of ISO/ANSI C++. The CLR also removes the incompatibilities introduced by various high-level languages by standardizing the target environment to which they are compiled and thus permit modules written in C++ to be combined with modules written in other languages such as C# or Visual Basic.
Console Applications As well as developing Windows applications, Visual C++ 2005 also allows you to write, compile, and test C++ programs that have none of the baggage required for Windows programs — that is, applications that are essentially character-based, command-line programs. These programs are called console applications in Visual C++ 2005 because you communicate with them through the keyboard and the screen in character mode. Writing console applications might seem as though you are being sidetracked from the main objective of Windows programming, but when it comes to learning C++ (which you do need to do before embarking on Windows-specific programming), it’s the best way to proceed. There’s a lot of code in even a simple Windows program, and it’s very important not to be distracted by the complexities of Windows when learning the ins and outs of C++. Therefore, in the early chapters of the book where you are concerned with how C++ works, you’ll spend time walking with a few lightweight console applications before you get to run with the heavyweight sacks of code in the world of Windows. While you’re learning C++, you’ll be able to concentrate on the language features without worrying about the environment in which you’re operating. With the console applications that you’ll write, you have only a text interface, but this will be quite sufficient for understanding all of C++ because there’s no graphical capability within the definition of the language. Naturally, I will provide extensive coverage of graphical user interface programming when you come to write programs specifically for Windows using Microsoft Foundation Classes (MFC) in native C++ applications and Windows Forms with the CLR. There are two distinct kinds of console applications and you’ll be using both. Win32 console applications compile to native code, and you’ll be using these to try out the capabilities of ISO/ANSI C++. CLR console applications target the CLR so you’ll be using these when you are working with the features of C++/CLI.
Windows Programming Concepts Our approach to Windows programming is to use all the tools that Visual C++ 2005 provides. The project creation facilities that are provided with Visual C++ 2005 can generate skeleton code for a wide variety of application programs automatically, including basic Windows programs. Creating a project is the starting point for all applications and components that you develop with Visual C++ 2005, and to get a
6
Programming with Visual C++ 2005 flavor of how this works, you’ll look at the mechanics of creating some examples, including an outline Windows program, later in this chapter. A Windows program has a different structure from that of the typical console program you execute from the command line, and it’s more complicated. In a console program, you can get input from the keyboard and write output back to the command line directly, whereas a Windows program can access the input and output facilities of the computer only by way of functions supplied by the Windows operating system; no direct access to the hardware resources is permitted. Because several programs can be active at one time under Windows, Windows has to determine which application a given raw input such as a mouse click or the pressing of a key on the keyboard is destined for and signal the program concerned accordingly. Thus the Windows operating system has primary control of all communications with the user. Also, the nature of the interface between a user and a Windows application is such that a wide range of different inputs is usually possible at any given time. A user may select any of a number of menu options, click a toolbar button, or click the mouse somewhere in the application window. A welldesigned Windows application has to be prepared to deal with any of the possible types of input at any time because there is no way of knowing in advance which type of input is going to occur. These user actions are received by the operating system in the first instance and are all regarded by Windows as events. An event that originates with the user interface for your application will typically result in a particular piece of your program code being executed. How program execution proceeds is therefore determined by the sequence of user actions. Programs that operate in this way are referred to as event-driven programs and are different from traditional procedural programs that have a single order of execution. Input to a procedural program is controlled by the program code and can occur only when the program permits it; therefore, a Windows program consists primarily of pieces of code that respond to events caused by the action of the user, or by Windows itself. This sort of program structure is illustrated in Figure 1-2. Each square block in Figure 1-2 represents a piece of code written specifically to deal with a particular event. The program may appear to be somewhat fragmented because of the number of disjointed blocks of code, but the primary factor welding the program into a whole is the Windows operating system itself. You can think of your program as customizing Windows to provide a particular set of capabilities. Of course, the modules servicing various external events, such as selecting a menu or clicking the mouse, all typically have access to a common set of application-specific data in a particular program. This application data contains information that relates to what the program is about — for example, blocks of text in an editor or player scoring records in a program aimed at tracking how your baseball team is doing — as well as information about some of the events that have occurred during execution of the program. This shared collection of data allows various parts of the program that look independent to communicate and operate in a coordinated and integrated fashion. I will go into this in much more detail later in the book. Even an elementary Windows program involves several lines of code, and with Windows programs that are generated by the application wizards that come with Visual C++ 2005, “several” turns out to be “many.” To simplify process of understanding how C++ works, you need a context that is as uncomplicated as possible. Fortunately, Visual C++ 2005 comes with an environment that is ready-made for the purpose.
7
Chapter 1
Events:
Keyboard Input
Press Left Mouse Button
Press Right Mouse Button
WINDOWS
Process Keyboard Input
Process Left Mouse Button
Process Right Mouse Button
Program Data Your Program
Figure 1-2
What Is the Integrated Development Environment? The Integrated Development Environment (IDE) that comes with Visual C++ 2005 is a completely selfcontained environment for creating, compiling, linking, and testing your C++ programs. It also happens to be a great environment in which to learn C++ (particularly when combined with a great book). Visual C++ 2005 incorporates a range of fully integrated tools designed to make the whole process of writing C++ programs easy. You will see something of these in this chapter, but rather than grind through a boring litany of features and options in the abstract, first take a look at the basics to get a view of how the IDE works and then pick up the rest in context as you go along.
8
Programming with Visual C++ 2005
Components of the System The fundamental parts of Visual C++ 2005, provided as part of the IDE, are the editor, the compiler, the linker, and the libraries. These are the basic tools that are essential to writing and executing a C++ program. Their functions are as follows.
The Editor The editor provides an interactive environment for you to create and edit C++ source code. As well as the usual facilities, such as cut and paste, which you are certainly already familiar with, the editor also provides color cues to differentiate between various language elements. The editor automatically recognizes fundamental words in the C++ language and assigns a color to them according to what they are. This not only helps to make your code more readable but also provides a clear indicator of when you make errors in keying such words.
The Compiler The compiler converts your source code into object code, and detects and reports errors in the compilation process. The compiler can detect a wide range of errors that are due to invalid or unrecognized program code, as well as structural errors, where, for example, part of a program can never be executed. The object code output from the compiler is stored in files called object files. There are two types of object code that the compiler produces. These object codes usually have names with the extension .obj.
The Linker The linker combines the various modules generated by the compiler from source code files, adds required code modules from program libraries supplied as part of C++, and welds everything into an executable whole. The linker can also detect and report errors — for example, if part of your program is missing or a non-existent library component is referenced.
The Libraries A library is simply a collection of pre-written routines that supports and extends the C++ language by providing standard professionally produced code units that you can incorporate into your programs to carry out common operations. The operations that are implemented by routines in the various libraries provided by Visual C++ 2005 greatly enhance productivity by saving you the effort of writing and testing the code for such operations yourself. I have already mentioned the .NET Framework library, and there are a number of others — too many to enumerate here — but I’ll mention the most important ones. The Standard C++ Library defines a basic set of routines common to all ISO/ANSI C++ compilers. It contains a wide range of routines including numerical functions such as calculating square roots and evaluating trigonometrical functions, character and string processing routines such as classifying characters and comparing character strings, and many others. You’ll get to know quite a number of these as you develop your knowledge of ISO/ANSI C++. There are also libraries that support the C++/CLI extensions to ISO/ANSI C++. Native window-based applications are supported by a library called the Microsoft Foundation Classes (MFC). The MFC greatly reduces the effort needed to build the graphical user interface for an application. You’ll see a lot more of the MFC when you finish exploring the nuances of the C++ language. Another library contains a set of facilities called Windows Forms that are roughly the equivalent of the MFC for window-based applications that executed with the .NET Framework. You’ll be seeing how you make use of Windows Forms to develop applications, too.
9
Chapter 1
Using the IDE All program development and execution in this book is performed from within the IDE. When you start Visual C++ 2005, notice an application window similar to that shown in Figure 1-3.
Figure 1-3
The window to the left in Figure 1-3 is the Solution Explorer window, the top-right window presently showing the Start page is the Editor window, and the window at the bottom is the Output window. The Solution Explorer window enables you to navigate through your program files and display their contents in the Editor window and to add new files to your program. The Solution Explorer window has up to three additional tabs (only two are shown in Figure 1-3) that display Class View, Resource View, and Property Manager for your application, and you can select which tabs are to be displayed from the View menu. The Editor window is where you enter and modify source code and other components of your application. The Output window displays messages that result from compiling and linking your program.
Toolbar Options You can choose which toolbars are displayed in your Visual C++ window by right-clicking in the toolbar area. A pop-up menu with a list of toolbars (Figure 1-4) appears, and the toolbars that are currently displayed have check marks alongside.
10
Programming with Visual C++ 2005
Figure 1-4
This is where you decide which toolbars are visible at any one time. You can make your set of toolbars the same as those shown in Figure 1-3 by making sure the Build, Class Designer, Debug, Standard, and View Designer menu items are checked. Clicking in the gray area to the left of a toolbar checks it if it unchecked and results in it being displayed; clicking a check mark hides the corresponding toolbar. You don’t need to clutter up the application window with all the toolbars you think you might need at some time. Some toolbars appear automatically when required, so you’ll probably find that the default toolbar selections are perfectly adequate most of the time. As you develop your applications, from time to time you might think it would be more convenient to have access to toolbars that aren’t displayed. You can change the set of toolbars that are visible whenever it suits you by right-clicking in the toolbar area and choosing from the context menu.
11
Chapter 1 Similar to many other Windows applications, the toolbars that make up Visual C++ 2005 come complete with tooltips. Just let the mouse pointer linger over a toolbar button for a second or two and a white label displays the function of that button.
Dockable Toolbars A dockable toolbar is one that you can drag around with the mouse to position at a convenient place in the window. When it is placed in any of the four borders of the application, it is said to be docked and looks similar to the toolbars you see at the top of the application window. The toolbar on the upper line of toolbar buttons that contains the disk icons and the text box to the right of a pair of binoculars is the Standard toolbar. You can drag this away from the toolbar by placing the cursor on it and dragging it with the mouse while you hold down the left mouse button. It then appears as a separate window you can position anywhere. If you drag any dockable toolbar away from its docked position, it looks like the Standard toolbar you see in Figure 1-5, enclosed in a little window — with a different caption. In this state, it is called a floating toolbar. All the toolbars that you see in Figure 1-3 are dockable and can be floating, so you can experiment with dragging any of them around. You can position them in docked positions where they revert to their normal toolbar appearance. You can dock a dockable toolbar at any side of the main window.
Figure 1-5
You’ll become familiar with many of the toolbar icons that Visual C++ 2005 uses from other Windows applications, but you may not appreciate exactly what these icons do in the context of Visual C++, so I’ll describe them as we use them. Because you’ll use a new project for every program you develop, looking at what exactly a project is and understanding how the mechanism for defining a project works is a good place to start finding out about Visual C++ 2005.
Documentation There will be plenty of occasions when you’ll want to find out more information about Visual C++ 2005. The Microsoft Development Network (MSDN) Library provides comprehensive reference material on all the capabilities on Visual C++ 2005 and more besides. When you install Visual C++ 2005 onto your machine, there is an option to install part or all of the MSDN documentation. If you have the disk space available I strongly recommend that you install the MSDN Library.
12
Programming with Visual C++ 2005 Press the F1 function to browse the MSDN Library. The Help menu also provides various routes into the documentation. As well as offering reference documentation, the MSDN Library is a useful tool when dealing with errors in your code, as you’ll see later in this chapter.
Projects and Solutions A project is a container for all the things that make up a program of some kind — it might be a console program, a window-based program, or some other kind of program, and it usually consists of one or more source files containing your code plus possibly other files containing auxiliary data. All the files for a project are stored in the project folder and detailed information about the project is stored in an XML file with the extension .vcproj that is also in the project folder. The project folder also contains other folders that are used to store the output from compiling and linking your project. The idea of a solution is expressed by its name, in that it is a mechanism for bringing together all the programs and other resources that represent a solution to a particular data processing problem. For example, a distributed order entry system for a business operation might be composed of several different programs that could each be developed as a project within a single solution; therefore, a solution is a folder in which all the information relating to one or more projects is stored, so one or more project folders are subfolders of the solution folder. Information about the projects in a solution is stored in two files with the extensions .sln and .suo. When you create a project, a new solution is created automatically unless you elect to add the project to an existing solution. When you create a project along with a solution, you can add further projects to the same solution. You can add any kind of project to an existing solution, but you would usually add only a project that was related in some way to the existing project or projects in the solution. Generally, unless you have a good reason to do otherwise, each of your projects should have its own solution. Each example you create with this book will be a single project within its own solution.
Defining a Project The first step in writing a Visual C++ 2005 program is to create a project for it using the File > New > Project menu option from the main menu or you can press Ctrl+Shift+N. As well as containing files that define all the code and any other data that goes to make up your program, the project XML file in the project folder also records the Visual C++ 2005 options you’re using. Although you don’t need to concern yourself with the project file — it is entirely maintained by the IDE — you can browse it if you want to see what the contents are, but take care not to modify it accidentally. That’s enough introductory stuff for the moment. It’s time to get your hands dirty.
Try It Out
Creating a Project for a Win32 Console Application
You’ll now take a look at creating a project for a console application. First select File > New > Project to bring up the New Project dialog box, shown in Figure 1-6.
13
Chapter 1
Figure 1-6
The left pane in the New Project dialog box displays the types of projects you can create; in this case, click Win32. This also identifies an application wizard that creates the initial contents for the project. The right pane displays a list of templates available for the project type you have selected in the left pane. The template you select is used by the application wizard when creating the files that make up the project. In the next dialog box, you have an opportunity to customize the files that are created when you click the OK button in this dialog box. For most of the type/template options, a basic set of program source modules are created automatically. You can now enter a suitable name for your project by typing into the Name: edit box — for example, you could call this one Ex1_01, or you can choose your own project name. Visual C++ 2005 supports long file names, so you have a lot of flexibility. The name of the solution folder appears in the bottom edit box and, by default, the solution folder has the came name as the project. You can change this if you want. The dialog box also allows you to modify the location for the solution that contains your project — this appears in the Location: edit box. If you simply enter a name for your project, the solution folder is automatically set to a folder with that name, with the path shown in the Location: edit box. By default the solution folder is created for you if it doesn’t already exist. If you want to specify a different path for the solution folder, just enter it in the Location: edit box. Alternatively, you can use the Browse button to select another path for your solution. Clicking the OK button displays the Win32 Application Wizard dialog box shown in Figure 1-7. This dialog box explains the settings currently in effect. If you click the Finish button, the wizard creates all the project files based on this. In this case you can click Applications Settings on the left to display the Application Settings page of the wizard shown in Figure 1-8.
14
Programming with Visual C++ 2005
Figure 1-7
Figure 1-8
The Application Settings page allows you to choose options that you want to apply to the project. For most of the projects you’ll be creating when you are learning the C++ language, you select the Empty project checkbox, but here you can leave things as they are and click the Finish button. The application wizard then creates the project with all the default files.
15
Chapter 1 The project folder will have the name that you supplied as the project name and will hold all the files making up the project definition. If you didn’t change it, the solution folder has the same name as the project folder and contains the project folder plus the files defining the contents of the solution. If you use Windows Explorer to inspect the contents of the solution folder, you’ll see that it contains three files: ❑
A file with the extension .sln that records information about the projects in the solution.
❑
A file with the extension .suo in which user options that apply to the solution will be recorded.
❑
A file with the extension .ncb that records data about Intellisense for the solution. Intellisense is the facility that provides auto-completion and prompting for code in the Editor window as you enter it.
If you use Windows Explorer to look in the project folder, notice there are six files initially, including a file with the name ReadMe.txt that contains a summary of the contents of the files that have been created for the project. The one file that ReadMe.txt may not mention is a file with a compound name of the form Ex1_01.vcproj.ComputerName.UserName.user used to store options you set for the project. The project you have created will automatically open in Visual C++ 2005 with the left pane as in Figure 1-9. I have increased the width of this pane so that you can see the complete names on the tabs.
Figure 1-9
The Solution Explorer tab presents a view of all the projects in the current solution and the files they contains — here there is just one project of course. You can display the contents of any file as an additional tab in the Editor pane just by double-clicking in name in the Solution Explorer tab. In the edit pane you can switch instantly between any of the files that have been displayed just by clicking on the appropriate tab.
16
Programming with Visual C++ 2005 The Class View tab displays the classes defined in your project and also shows the contents of each class. You don’t have any classes in this application, so the view is empty. When we discuss classes, you will see that you can use the Class View tab to move around the code relating to the definition and implementation of all your application classes quickly and easily. The Property Manager tab shows the properties that have been set for the Debug and Release versions of your project. I’ll explain these versions a little later in this chapter. You can change any of the properties shown by right-clicking a property and selecting Properties from the context menu; this displays a dialog box where you can set the project property. You can also press Alt+F7 to display the properties dialog box at any time; I’ll also discuss this in more detail when we go into the Debug and Release versions of a program. The Resource View shows the dialog boxes, icons, menus toolbars, and other resources that are used by the program. Because this is a console program, no resources are used; however, when you start writing Windows applications, you’ll see a lot of things here. Through this tab you can edit or add to the resources available to the project. Like most elements of the Visual C++ 2005 IDE, the Solution Explorer and other tabs provide contextsensitive pop-up menus when you right-click items displayed in the tab and in some cases in the empty space in the tab, too. If you find that the Solution Explorer pane gets in your way when writing code, you can hide it by clicking the Autohide icon. To redisplay it, click the name tab on the left of the IDE window.
Modifying the Source Code The Application wizard generates a complete Win32 console program that you can compile and execute. Unfortunately, the program doesn’t do anything as it stands, so to make it a little more interesting you need to change it. If it is not already visible in the Editor pane, double-click Ex1_01.cpp in the Solution Explorer pane. This file is the main source file for the program that the Application wizard generated and it looks like that shown in Figure 1-10.
Figure 1-10
17
Chapter 1 If the line numbers are not displayed on your system, select Tools > Options from the main menu to display the Options dialog box. If you extend the C/C++ option in the right pane and select General from the extended tree, you can select Line Numbers in the right pane of the dialog box. I’ll first give you a rough guide to what this code in Figure 1-10 does, and you’ll see more on all of these later. The first two lines are just comments. Anything following “//”in a line is ignored by the compiler. When you want to add descriptive comments in a line, precede your text by “//”. Line 4 is an #include directive that adds the contents of the file stdafx.h to this file in place of this #include directive. This is the standard way of adding the contents of .h source files to a .cpp source file a in a C++ program. Line 7 is the first line of the executable code in this file and the beginning of the function _tmain(). A function is simply a named unit of executable code in a C++ program; every C++ program consists of at least one — and usually many more — functions. Lines 8 and 10 contain left and right braces, respectively, that enclose all the executable code in the function _tmain(). The executable code is, therefore, just the single line 10 and all this does is end the program. Now you can add the following two lines of code in the Editor window: // Ex1_01.cpp : Defines the entry point for the console application. // #include “stdafx.h” #include int _tmain(int argc, _TCHAR* argv[]) { std::cout Build Solution menu item. Alternatively, you can click the toolbar button corresponding to this menu item. The toolbar buttons for the Build menu may not display, but you can easily fix this by right-clicking in the toolbar area and selecting the Build
18
Programming with Visual C++ 2005 toolbar from those in the list. The program should then compile successfully. If there are errors, ensure you didn’t make an error while entering the new code, so check the two new lines very carefully.
Files Created by Building a Console Application After the example has been built without error, take a look in the project folder by using Windows Explorer to see a new subfolder called Debug. This folder contains the output of the build you just performed on the project. Notice that this folder contains several files. Other than the .exe file, which is your program in executable form, you don’t need to know much about what’s in these files. In case you’re curious, however, let’s do a quick run-through of what the more interesting ones are for. File Extension
Description
.exe
This is the executable file for the program. You get this file only if both the compile and link steps are successful.
.obj
The compiler produces these object files containing machine code from your program source files. These are used by the linker, along with files from the libraries, to produce your .exe file.
.ilk
This file is used by the linker when you rebuild your project. It enables the linker to incrementally link the object files produced from the modified source code into the existing .exe file. This avoids the need to re-link everything each time you change your program.
.pch
This is a pre-compiled header file. With pre-compiled headers, large tracts of code that are not subject to modification (particularly code supplied by C++ libraries) can be processed once and stored in the .pch file. Using the .pch file substantially reduces the time needed to rebuild your program.
.pdb
This file contains debugging information that is used when you execute the program in debug mode. In this mode, you can dynamically inspect information that is generated during program execution.
.idb
Contains information used when you rebuild the solution.
Debug and Release Versions of Your Program You can set a range of options for a project through the Project > Ex1_01 Properties menu item. These options determine how your source code is processed during the compile and link stages. The set of options that produces a particular executable version of your program is called a configuration. When you create a new project workspace, Visual C++ 2005 automatically creates configurations for producing two versions of your application. One version, called the Debug version, includes information that helps you debug the program. With the Debug version of your program you can step through the code when things go wrong, checking on the data values in the program. The other, called the Release version, has no debug information included and has the code optimization options for the compiler turned on to provide you with the most efficient executable module. These two configurations are sufficient for your needs throughout this book, but when you need to add other configurations for an application, you can do so through the Build > Configuration Manager menu. Note that this menu item won’t appear if you haven’t got a project loaded. This is obviously not a problem, but might be confusing if you’re just browsing through the menus to see what’s there.
19
Chapter 1 You can choose which configuration of your program to work with by selecting the configuration from the Active solution configuration drop-down list in the Configuration Manager dialog box, as shown in Figure 1-11.
Figure 1-11
Select the configuration you want to work with from the list and then click the Close button. While you’re developing an application, you’ll work with the debug configuration. After your application has been tested using the debug configuration and appears to be working correctly, you typically rebuild the program as a release version; this produces optimized code without the debug and trace capability, so the program runs faster and occupies less memory.
Executing the Program After you have successfully compiled the solution, you can execute your program by pressing Ctrl+F5. You should see the window shown in Figure 1-12.
Figure 1-12
20
Programming with Visual C++ 2005 As you see, you get the text that was between the double quotes written to the command line. The “\n” that appeared at the end of the text string is a special sequence called an escape sequence that denotes a newline character. Escape sequences are used to represent characters in a text string that you cannot enter directly from the keyboard.
Try It Out
Creating an Empty Console Project
The previous project contained a certain amount of excess baggage that you don’t need when working with simple C++ language examples. The precompiled headers option chosen by default resulted in the stdafx.h file being created in the project. This is a mechanism for making the compilation process more efficient when there are a lot of files in a program but this won’t be necessary for many of our examples. In these instances you start with an empty project to which you can add your own source files. You can see how this works by creating a new project in a new solution for a Win32 console program with the name Ex1_02. After you have entered the project name and clicked the OK button, click on Applications Settings on the right side of the dialog box that follows. You can then select Empty project from the additional options, as Figure 1-13 shows.
Figure 1-13
When you click the Finish button, the project is created as before, but this time without any source files. Next you add a new source file to the project. Right-click the Solution Explorer pane and then select Add > New Item from the context menu. A dialog box displays; click Code in the right pane, and C++ File(.cpp) in the left pane. Enter the file name as Ex1_02, as shown in Figure 1-14.
21
Chapter 1
Figure 1-14
When you click the Add button, the new file is added to the project and is displayed in the Editor window. Of course, the file is empty so nothing will be displayed; enter the following code in the Editor window: // Ex1_02.cpp A simple console program #include // Basic input and output library int main() { std::cout Upper menu item is clicked, you want to prevent the input for a lower limit being entered, and when the Limits > Lower menu item is selected, you want to prevent input for an upper limit value. You can add a couple of member functions to the EuroLimitsDialog class to make this possible:
1073
Chapter 21 public: // Disables controls for selecting upper limits void SetLowerEnabled(void) { upperValuesLimits->Enabled = false; upperStarsLimits->Enabled = false; lowerValuesLimits->Enabled = true; lowerStarsLimits->Enabled = true; } // Disables controls for selecting lower limits void SetUpperEnabled(void) { upperValuesLimits->Enabled = true; upperStarsLimits->Enabled = true; lowerValuesLimits->Enabled = false; lowerStarsLimits->Enabled = false; }
The value of the Enabled property for a control determines whether it is enabled. A true value enables the control, and a value of false disables it so the user cannot interact with it. The SetLowerEnabled() function disables the controls used to enter upper limits and enables those for entry of lower limits. The SetUpperEnabled() function does the reverse.
Updating the Limits Menu Item Handlers The last step to complete the support for entering limits for the Euromillions lottery is to update the Click event handlers in the Form1 class for the items in the Limits menu. The handler for the Upper menu item should be modified as follows: System::Void upperMenuItem_Click(System::Object^ sender, System::EventArgs^ { ::DialogResult result; if(lottoTab->Visible) { lottoLimitsDialog->SetUpperEnabled(); result = lottoLimitsDialog->ShowDialog(this); if(result == ::DialogResult::OK) { lottoUserMaximum = lottoLimitsDialog->UpperLimit; lottoUserMinimum = lottoLimitsDialog->LowerLimit; } } else if(euroTab->Visible) { euroLimitsDialog->SetUpperEnabled(); result = euroLimitsDialog->ShowDialog(this); if(result == ::DialogResult::OK) { euroUserMaximum = euroLimitsDialog->UpperValuesLimit; euroUserMinimum = euroLimitsDialog->LowerValuesLimit; euroStarsUserMaximum = euroLimitsDialog->UpperStarsLimit;
1074
e)
Applications Using Windows Forms euroStarsUserMinimum = euroLimitsDialog->LowerStarsLimit; } } }
The local variable result is used in both if statements, so it is now declared at the beginning of the function. After enabling the controls in the dialog box appropriately by calling the SetUpperEnabled() function for the dialog object, you display the dialog box as modal. If the user closes the dialog box by clicking the OK button, you store the results available through the properties of the dialog object. The changes to the handler for the Click event for the Lower menu item are very similar: System::Void lowerMenuItem_Click(System::Object^ sender, System::EventArgs^ { ::DialogResult result; if(lottoTab->Visible) { lottoLimitsDialog->SetLowerEnabled(); result = lottoLimitsDialog->ShowDialog(this); if(result == ::DialogResult::OK) { lottoUserMaximum = lottoLimitsDialog->UpperLimit; lottoUserMinimum = lottoLimitsDialog->LowerLimit; } } else if(euroTab->Visible) { euroLimitsDialog->SetLowerEnabled(); result = euroLimitsDialog->ShowDialog(this); if(result == ::DialogResult::OK) { euroUserMaximum = euroLimitsDialog->UpperValuesLimit; euroUserMinimum = euroLimitsDialog->LowerValuesLimit; euroStarsUserMaximum = euroLimitsDialog->UpperStarsLimit; euroStarsUserMinimum = euroLimitsDialog->LowerStarsLimit; } } }
e)
The logic here is the same as in the previous handler function.
Implementing the Help | About Menu Item This is easy now that you know about the MessageBox class. You can just show a message box when the Help > About menu item is clicked: System::Void aboutToolStripMenuItem_Click(System::Object^
sender, System::EventArgs^
e)
{ MessageBox::Show(L”(c) Copyright Ivor Horton”, L”About A Winning Application”, MessageBoxButtons::OK, MessageBoxIcon::Exclamation); }
1075
Chapter 21 When the the menu item is clicked, the handler function displays the message box shown in Figure 21-28.
Figure 21-28
Handling a Button Click Clicking a button should change the value on the button to a new random value. Of course, the value must be different from values on the other buttons as well as being different from the value for the button that was clicked. It would be a good idea to present the whole set in sorted order; this may result in the new value being on a different button, but that’s likely to be better that not having the values in sequence. The process for handling a button click is going to be the same for all the buttons, so you’ll be able to economize on code by creating a generalized function to do the work. You can define a private function member of the Form1 class that generates a new value for a given Button object from an array of buttons: // Generates a new value for button different from current button values void SetNewValue(Button^ button, array<Button^>^ buttons, int lowerLimit, int upperLimit) { int index = 0; // Index of button in buttons // Array to store button values array^ values = gcnew array(buttons->Length); // Get values from buttons and find index for button for(int i = 0 ; i < values->Length ; i++) { values[i] = Int32::Parse(buttons[i]->Text); // Get current button value // If current handle is same as button, save the index value
1076
Applications Using Windows Forms if(button == buttons[i]) index = i; } int newValue = 0; // Store the new button value // Check if it is different from the other button values for(;;) // Loop until we get a good one { newValue = random->Next(lowerLimit, upperLimit); // Generate a value if(IsValid(newValue, values, values->Length)) // If it’s OK... break; // ...end the loop } values[index] = newValue; // Store the new value at index Array::Sort(values); for(int i = 0 ; i < values->Length ; i++) buttons[i]->Text = values[i].ToString();
// Sort the value // and set the values // as text on the buttons
}
The first two function parameters are the button that is to have a new number and the array of buttons in the group to which the first button belongs. The next two parameters specify the lower and upper limits for the values. The current values of the buttons in the array are stored in the values array in the first loop. This loop also finds the index value in the buttons array for the Button^ handle that is the first argument. You need this so you know which element of the values array is to be replaced by a new value. The new value is created in the indefinite for loop. This is the same mechanism that you used to create the values for the button in the first instance. After you have a valid new value, you store it in the values array. You then sort the elements in the values array before storing them as the values for the Text properties for the buttons in the buttons array. You’ll be able to use this function for dealing with the Click events for all of the buttons. If you have not already done so, double-click the first button on the Lotto tab to generate a Click event handler function for it. You can edit the name of the handler function by opening the Properties tab for the button, selecting the Events button, and changing the value for the Click event. When you press Enter, the code is updated with the new name. I changed the value to lottoValue_Click. You can amend the Click event handler to call the SetNewValue() function you have just added to the Form1 class: System::Void lottoValue_Click(System::Object^ sender, System::EventArgs^ { Button^ button = safe_cast<Button^>(sender);
e)
// Create the array of button handles array<Button^>^ buttons = {lottoValue1, lottoValue2, lottoValue3, lottoValue4, lottoValue5, lottoValue6}; // Replace the value on button SetNewValue(button, buttons, lottoUserMinimum, lottoUserMaximum); }
1077
Chapter 21 The availability of the SetNewValue() function makes this handler function very simple. The first statement stores the handle to the button that was clicked. The first parameter to the event handler is a handle to the object that originated the event, so all that’s necessary is to cast it to the appropriate type. You then just assemble the handles for the buttons in an array and call the new function — job done! You still have to deal with the Click event for the other buttons on the Lotto tab, but this doesn’t require any more code. Open the Properties window for the second button and then click the Events button. If you click the Click event value, you’ll see a list of the existing event handlers as shown in Figure 21-29; if you select lottoValue_Click from the list, the event handler for the first button will be registered as the event handler for the second button, too.
Figure 21-29
You can repeat the process for the remaining four buttons on the Lotto tab so that the one event handler is called in response to the Click event for any of the buttons on the Lotto tab. The Click event handlers for the buttons on the Euromillions tab are going to be very easy. Double-click the first of the five buttons in the Values group to create the event handler. Open the Properties window for the button and change the value for the Click event to euroValue_Click. You can then modify the code for the handler like this:
1078
Applications Using Windows Forms System::Void euroValue_Click(System::Object^ sender, System::EventArgs^ { Button^ button = safe_cast<Button^>(sender); array<Button^>^ buttons = {euroValue1, euroValue2, euroValue3, euroValue4, euroValue5 }; SetNewValue(button, buttons, euroUserMinimum, euroUserMaximum); }
e)
This works exactly the same as the handler for the Lotto buttons. The array contains the handles to the five buttons in the values group, and the SetNewValue() function does the rest. If you open the Properties window for each of the remaining four buttons in the group, you can select this function to respond to the Click event for each of them. Be sure you select euroValue_Click and not lottoValue_Click! Follow the same procedure for the Stars buttons on the Euromillions tab. You can implement the handler as: System::Void euroStar_Click(System::Object^ sender, System::EventArgs^ e) { Button^ button = safe_cast<Button^>(sender); array<Button^>^ buttons = { euroStar1, euroStar2 }; SetNewValue(button, buttons, euroStarsUserMinimum, euroStarsUserMaximum); }
Set the handler for the Click event for the second button to be euro_StarClick and you are done. If you recompile the example, you should be able to generate a new value for any button on either tab just by clicking it. The last piece to complete the example is to allow the user to enter a value for a button.
Responding to the Context Menu Right-clicking a button brings up a context menu with a single menu item, Choose. When the user clicks this item, the program should display a dialog box that allowed a suitable value to be entered. Click the name of the context menu in the Design tab for Form1 and then double-click the menu item to create the Click event handler. The first problem is to determine which group of buttons was clicked to cause the event. Each group on buttons is in its own GroupBox control, and the GroupBox class has a Controls property that returns a reference to an object of type Control::ControlCollection that represents the collection of controls in the group box. The Control::ControlCollection class defines the Contains() function that returns true if the control that you pass as the argument is within the collection and false otherwise. Thus you have a way to determine to which group of buttons the button causing the Click event belongs. An outline implementation of the event handler looks like this: System::Void chooseValue_Click(System::Object^ sender, System::EventArgs^ { // Get the button that was clicked for the context menu, then...
e)
if(lottoValues->Controls->Contains(theButton)) { // the button is from the lotto group... } else if(euroValues->Controls->Contains(theButton)) {
1079
Chapter 21 // The button is in the Values group... } else if(euroStars->Controls->Contains(theButton)) { // The button is in the Stars group... } }
That sorts out which group of buttons is involved, at least in principle. But there’s still a bit of a problem — how do you find out which button was right-clicked to open the context menu? The chooseValue_Click() handler is called when the Choose menu item is clicked, so the sender parameter for the handler identifies the menu item, not the button. You need a handler that responds to the original click on the button and you can create this by double-clicking buttonContextMenu in the Design pane for Form1. You can complete the code for the handler function that is created like this: System::Void buttonContextMenu_Opening(System::Object^ sender, System::ComponentModel::CancelEventArgs^ { contextButton = safe_cast<Button^>(buttonContextMenu->SourceControl); }
e)
This casts the sender handle to type Button^ and stores it in the contextButton member of the Form1 class. Because in this case the event is for the context menu, the sender parameter identifies the component that was clicked to display it. Of course, you have yet to add the contextButton variable as a private member of the Form1 class: private: Button^ contextButton;
// Button that was right-clicked for context menu
All you need to do now is figure out what to do next.
The Logic for Dealing with the Choose Menu Item The process for responding to the Choose item being clicked can be the same whichever group of buttons is involved, and it could work something like the following:
1. 2. 3.
Display a dialog box to allow a value to be entered.
4.
If the value is valid, update the button that was right-clicked with the new value.
Check that the value is valid — that is, within range and different from the other buttons. Display a message box if the value is not valid and allow the entry to be retired or the dialog operation to be cancelled.
The first step in implementing this process is to create a new dialog form.
Creating the Dialog Form Press Ctrl+Shift+A to display the Add New Item dialog box; then select UI as the category and Windows Form as the template. Enter the name as UserValueDialog and click the Add button. You can
1080
Applications Using Windows Forms now open the Properties window for the form by pressing F4 and setting the property values to make it a dialog box. Set the ControlBox, MinimizeBox, and MaximizeBox property values to False, and set the Text property to “User Value Input.” Add OK and Cancel buttons to the dialog form as well as a Label control and a TextBox control, as shown in Figure 21-30.
Figure 21-30
Set the Text and (Name) property values for the OK button to OK, and the value for the DialogResult property should be set to OK. The values for the Text, (Name), and DialogResult properties for the Cancel button should be Cancel. Set the value of the (Name) property for the TextBox control to be textBox and the value for the TextAlign property as Center. The (Name) property for the Label control can be label, and the Text property can be anything you like because you’ll change this in the code to suit the circumstances. You can now display the properties for the dialog form once again and set the values for the AcceptButton and CancelButton properties to OK and Cancel, respectively.
Developing the Dialog Class The value entered in the TextBox control must be available to the Form1 object, so add a property to the UserValueDialog class to store it: public: property int Value;
This is an example of a trivial scalar property so get() and set() functions are supplied by default. The dialog object needs to know what the limits are for the value because the handler for the OK button in the dialog class is verifying that the value is legal. For the same reason, the dialog object needs to know what the current values on the buttons are to ensure they are not duplicated. You could add three further property members to the UserValueDialog class to store the data:
1081
Chapter 21 public: property int LowerLimit; property int UpperLimit; property array^ Values;
// Current button values
The Form1 object needs to be able to change the value of the Text property for the label control, depending on the limits in effect for button values when the dialog box is displayed; you can add a public member function to the UserValidDialog class to do this: public: void SetLabelText(int lower, int upper) { label->Text = L”Enter your value between “ + lower +L” and “ + upper; }
You could conceivably pick up the limits from the properties in the dialog object, but this would require that the properties were always set first. By using parameters for the limits you remove this dependency. You can create the dialog object in the Form1 class constructor, but you’ll need to add a private Form1 class member to store the handle: private: UserValueDialog^ userValueDialog;
You’ll also need an #include directive for UserValueDialog.h in the Form1.h header file. Adding the following line to the constructor creates the dialog object: userValueDialog = gcnew UserValueDialog;
If you double-click the OK button in the UserValueDialog form, you’ll create the Click event handler for the button. This function retrieves the value entered in the TextBox control, and checks that the value is within the limits and is different from the current set of values. If the value is not valid for any reason, the function displays a message box. Here’s how you implement that: System::Void OK_Click(System::Object^ sender, System::EventArgs^ e) { ::DialogResult result; // Stores return value from Show() if(String::IsNullOrEmpty(textBox->Text)) // Chheck for null or empty string { result = MessageBox::Show(this, L”No input - enter a value.”, L”Input Error”, MessageBoxButtons::RetryCancel, MessageBoxIcon::Error); if(result == ::DialogResult::Retry) // If Retry button clicked DialogResult = ::DialogResult::None; // ...prevent dialog from closing... else // ...otherwise... DialogResult = ::DialogResult::Cancel;// ...close the dialog. return; } int value = Int32::Parse(textBox->Text);
1082
// Get text box value
Applications Using Windows Forms bool valid = true;
// Indicator for valid entry
for each(int n in Values) if(value == n) { valid = false; break; }
// Check input against current values // If it’s the same... // ...it is invalid. // Exit the loop
// Check limits and result of previous validity check if(!valid || value < LowerLimit || value > UpperLimit) { result = MessageBox::Show(this, L”Input not valid.” + L”Value must be from “ + LowerLimit + L” to “ + UpperLimit + L”\nand must be different from existing values.”, L”Input Error”, MessageBoxButtons::RetryCancel, MessageBoxIcon::Error); if(result == ::DialogResult::Retry) DialogResult = ::DialogResult::None; else DialogResult = ::DialogResult::Cancel; } else Value = value; // Store the input in the property }
A message box is displayed if the Text property for the text box is null or an empty string. The message box shows an error message and has Retry and Cancel buttons instead of OK and Cancel for a change. If Retry is clicked, the user wants another go at input so you prevent the dialog box from closing by setting its DialogResult property to ::DialogResult::None. The only other possibility is that the user clicked Cancel in the message box, in which case you set the DialogResult property for the dialog object to ::DialogResult::Cancel, which has the same effect as clicking the Cancel button for the dialog box. The Text property for the TextBox control returns a handle of type String^. You convert this to an integer by passing the handle to the static Parse() function in the Int32 class. You compare the value from the text box with the elements from the values array that represent the current set of button values. The new value should be different from all of these, so if you find one that is the same, you set valid to false and exit the loop. The condition for the if statement following the for each loop checks the value against the limits and the current value of valid by ORing the conditions together. If any of the three expressions are false, the condition is false, and you display a message box. This works in the same way as the previous message box and displays an error message and Retry and Cancel buttons. If the value does indeed turn out to be valid you store it in the Value property for the dialog object ready for retrieval by the event handler in the Form1 object that started the whole process off.
Handling the Click Event for the ChooseMenu You are now going to complete the skeleton of the chooseValue_Click() handler function using the capabilities that you have added to the UserValueDialog class. The handle for the button that was
1083
Chapter 21 right-clicked is already stored in the contextButton member because the buttonContextMenu_ Opening() handler that you added earlier is executed first. System::Void chooseValue_Click(System::Object^ sender, System::EventArgs^ e) { array^ values; // Array to store current button values array<Button^>^ theButtons; // Handle to aray of buttons // Check if the button is in the lottoValues group box if(lottoValues->Controls->Contains(contextButton)) { // the button is from the lotto group... array<Button^>^ buttons = {lottoValue1, lottoValue2, lottoValue3, lottoValue4, lottoValue5, lottoValue6}; theButtons = buttons; // Store array handle at outer scope values = GetButtonValues(buttons); // Get array of button values // Set up the dialog ready to be shown userValueDialog->Values = values = GetButtonValues(buttons); userValueDialog->LowerLimit = lottoUserMinimum; userValueDialog->UpperLimit = lottoUserMaximum; userValueDialog->SetLabelText(lottoUserMinimum, lottoUserMaximum); } // Check if the button is in the euroValues group box else if(euroValues->Controls->Contains(contextButton)) { // The button is in the Values group... array<Button^>^ buttons = {euroValue1, euroValue2, euroValue3, euroValue4, euroValue5}; theButtons = buttons; // Store array handle at outer scope values = GetButtonValues(buttons); // Get array of button values // Set up the dialog ready to be shown userValueDialog->Values = values; userValueDialog->LowerLimit = euroUserMinimum; userValueDialog->UpperLimit = euroUserMaximum; userValueDialog->SetLabelText(euroUserMinimum, euroUserMaximum); } // Check if the button is in the euroStars group box else if(euroStars->Controls->Contains(contextButton)) { // The button is in the Stars group... array<Button^>^ buttons = { euroStar1, euroStar2 }; theButtons = buttons; // Store array handle at outer scope values = GetButtonValues(buttons); // Get array of button values // Set up the dialog ready to be shown userValueDialog->Values = values; userValueDialog->LowerLimit = euroStarsUserMinimum; userValueDialog->UpperLimit = euroStarsUserMaximum; userValueDialog->SetLabelText(euroStarsUserMinimum, euroStarsUserMaximum); }
1084
Applications Using Windows Forms // Display the dialog if(userValueDialog->ShowDialog(this) == ::DialogResult::OK) { // Determine which button value should be replaced for(int i = 0 ; iLength ; i++) if(contextButton == theButtons[i]) { values[i] = userValueDialog->Value; break; } Array::Sort(values); // Sort the values // Set all the button values for(int i = 0 ; iLength ; i++) theButtons[i]->Text = values[i].ToString(); } }
You first define two array variables, one to hold the buttons, the other to hold the button values. You need to declare these here because these arrays are created within one or other of the if statement blocks and you’ll want to access them outside the if blocks. The first three if statements determine which group box contains the button that was right-clicked to open the context menu. The processes within the three if blocks are essentially the same, but the arrays created will be different. The array of buttons is created from the variables holding the handles to whichever set of buttons the contextButton belongs. The array handle is then stored in theButtons to make it accessible in the outer scope. You then call a function you have yet to add, GetButtonValues(), that returns an array containing the integer values from the buttons. Finally, in the if block you set the three properties for the dialog box object and call its SetLabelText() function to set the label text according to the applicable limits. The contextButton has to belong to one of the three group boxes as these are the only buttons that have the context menu available. When one or other of the if blocks has executed, you display the dialog box by calling its ShowDialog() function in the condition for the fourth if statement. If the ShowDialog() function returns ::DialogResult::OK, you execute the code in the if block. This first determines which button should have its value replaced by comparing contextButton handle with the handles in the theButtons array. As soon as you find a match, you replace the corresponding element in the values array with the new value and exit the loop. After sorting the values, you update the Text property for each of the buttons in the theButtons array and you are done. The implementation of the GetButtonValues() function in the Form1 class looks like this: // Creates an array of button values from an array of buttons array^ GetButtonValues(array<Button^>^ buttons) { array^ values = gcnew array(buttons->Length); for(int i = 0 ; iLength ; i++) values[i] = Int32::Parse(buttons[i]->Text); return values; }
1085
Chapter 21 Here you create an array of integer values the same length as the array of button handles that is passed as the argument. You then populate the values array with the int equivalents of the string returned by the Text properties of the buttons, and return the handle to the values array. After compiling the project once more, you should have a fully functional application. You can generate lottery entries for a variety of lotteries with the range of values constrained or not. You can also elect to generate new random individual values in an entry or choose your own. It has always worked but never won for me; of course, working is a measure of success.
Summar y In this chapter, you assembled a Windows Form application that uses the controls that you are most likely to need in the majority of programs. It should be apparent that Windows Forms programs are geared exclusively to using the Design capability. All the code for a class goes into the class definition, so with a very complex form the class is many lines of code. With a production application the code consists of a number of large classes that are rather unstructured, and difficult to modify and maintain at the code level. You should therefore always use the Design capability and the Properties window to expedite changes wherever you can and whenever you need to access the code, use Class View to find your way around. The key points to keep in mind from this chapter include: ❑
An application window is a form, and a form is defined by a class derived from the System::Form class.
❑
A dialog window is a form that has its FormBorderStyle property value set to FixedDialog.
❑
A dialog box can be created as a modal dialog by calling its ShowDialog() function or as a modeless dialog by calling its Show() function.
❑
You can control whether or not a dialog box closes by setting the DialogResult property value for the dialog object.
❑
A ComboBox control combines the capabilities of a ListBox and a TextBox and allows selection of an item from a list or a new item to be entered from the keyboard.
❑
A NumericUpDown control allows the entry of numeric data by stepping through values within a given range with a given step increment.
❑
You can add the definition of a Click event handler for a control by double-clicking the control in the Form Design tab.
❑
You can specify an existing function to be a handler for a given event for a control through the Properties window. Clicking the Events button in the Properties window displays the list of events for a control.
❑
You should only change the names of automatically generated class members through the Properties window — not directly using the Code editor.
1086
Applications Using Windows Forms
Exercises You can download the source code for the examples in the book and the solutions to the following exercises from http://www.wrox.com.
1.
Modify Ex21_01 so that it displays a dialog box that you created as a dialog form when the Help | About menu item is clicked.
2.
Modify Ex21_01 so that the dialog box that displays for the Choose context menu item uses a ListBox control instead of the text box and displays the complete set of legal values that can be chosen.
3.
Investigate the properties and functions available for the WebBrowser control and modify Ex21_01 to allow a URL to be entered through a TextBox so that the WebBrowser control displays the page at the URL that was entered.
1087
22 Accessing Data Sources in a Windows Forms Application In this chapter, you’ll investigate how you can develop form-based applications that will display data from a variety of sources and specifically how you can create form-based programs to access an existing database. In this chapter, you will learn about: ❑
What kind of classes are involved in encapsulating a data source
❑
How you can use the DataGridView control to display your own data
❑
How you can customize the appearance of a DataGridView control
❑
What the function of the BindingSource component is and how you use it with a DataGridView control
❑ ❑
How you use a BindingNavigator control to navigate data from a source managed by a BindingSource control How you expedite updating of a database using a BindingNavigator control and a BindingSource component
Visual C++ 2005 provides a high degree of automation for creating Forms-based applications that access data sources but you will start by ignoring the automation and get a feel for how you can work with components programmatically. With this approach, you’ll not only get a good insight into how things work; you’ll also appreciate how much the automation is doing for you.
Working with Data Sources A data source is any source of data for your application; relational databases, Web services that access data, and objects can all be data sources. When you are developing an application that will work with an existing data source, you will usually need to identify the data source within your project. You’ll do this through the Data Sources window that is displayed when you select Data > Show Data Sources item from the main menu or when you press Shift+Alt+D.
Chapter 22 A data source is represented by a class object, so inevitably adding a data source to your project adds definitions for a number of classes. Take a brief look at what they are. Data Source
A data source is defined by a class that is derived from the DataSet class that is defined in the System::Data namespace. This class encapsulates an inmemory cache of all the data from the database that is accessible in your project.
Database Tables
Each table in the database is defined by a nested class in the DataSet class that represents the database, and the class that defines a table is derived from the System::Data::DataTable class. The classes representing tables also define events that signal changes to the data in the table and propertie, making each of the values of the current database record available. Each table in a data source is identified by a member in the DataSet class that is a handle to the corresponding DataTable object.
Table Columns
Each column in a given database table is identified by a member of the Data Table class that defines the table. The members representing columns are of type System::Data::DataColumn and define the characteristics of the column, such as the column name and the type of data in the column. These characteristics are collectively referred to as the schema for the column.
Table Rows
A row in a table is represented by an object of type System::Data::DataRow. A DataRow object contains the data in a row and has as many data items as there are columns in the DataTable object.
Clearly, with a database that involves several tables that each have a number of columns, you are going to see quite a lot of code generated to represent a data source; certainly, tens of thousands of lines of code are not uncommon in a practical context. The classes I have identified in the previous table are solely to encapsulate data from a data source; they do not provide the mechanism for connecting to a data source such as a database and accessing the data within it. That capability is provided by a component class called a table adapter that will be generated automatically. A table adapter establishes a connection to a database and executes the commands or SQL statements that operate on the database. There is one table adapter class for each DataTable member in the DataSet object, so if your application is going to work with three tables from a database, there are three table adapter classes defined. A table adapter object populates a DataTable member of a DataSet object with data and can update the table in the database when required.
Accessing and Displaying Data There are three components defined in the System::Windows::Forms namespace that are designed to be used together for accessing and displaying data in a Windows Forms application:
1090
Accessing Data Sources in a Windows Forms Application Component
Description
DataGridView
This control can display virtually any kind of data in a rectangular grid. You can use this control quite independently of the other two components.
BindingSource
This component is used to encapsulate data from a data source. The component can manage accessing and updating the data source, and can be used as the vehicle for displaying data in a DataGridView control.
BindingNavigator
This control provides a toolbar containing controls for navigating and manipulating data from a data source, typically a data source encapsulated in a BindingSource control.
The BindingSource component is not a control as it has no graphical representation that a user can interact with, but it’s designed to complement and work with the DataGridView control and the BindingNavigator in database applications. The BindingSource component provides the communications with the data source necessary to execute queries and update commands, the DataGridView controls provides the user interface for viewing and entering the data and the BindingNavigator control provides a toolbar that simplifies data navigation. Using the BindingNavigator control is optional. If you prefer, you can change records programmatically yourself. Although these three components are designed to work as a team, the DataGridView control is a particularly useful tool in its own right, as you can use it quite independently from the other two. It provides an astonishing range of capabilities for changing the visual appearance of the grid that displays the data. You’ll explore some of the ways in which you can customize the DataGridView control before going into how you can use it combined with the BindingSource and BindingNavigator components. Note that you can also use the SqlConnection, SqlDataAdapter, and DataSet controls for accessing a data source. If you want to use these controls, then you may need to add them to the ToolBox yourself. You do this by selecting Tools > Choose ToolBox Items from the main menu and checking the controls in the list that you want to have added to the ToolBox.
Using a DataGridView Control The DataGridView control enables you to display and modify a rectangular array of data from a wide range of data sources. You can also use the DataGridView control to display almost any kind of data that originates directly in a program. Under the covers it is a complex control that provides an enormous amount of flexibility, and you can take advantage of its many features through its many properties, functions, and events. At the same time, the DataGridView control can be remarkably easy to use. You can ignore the complexity of the internals and use it through the Form Design capability that takes care of all the basic detail for you. You’ll see later in this chapter how you can produce a complete working program example to access the Northwind database with no programming at all on your part; the whole program will be generated through the Form Design capability and by setting properties for components used in the project.
1091
Chapter 22 The data in a DataGridView control is displayed in a rectangular array of cells that you can envisage as a collection of rows or as a collection of columns. Each column of cells has a header cell at the top that typically contains text that identifies it, and each row has a row header cell at the beginning, as shown in Figure 22-1. DataGridView^ gridCntrl = gcnew DataGridView; // Creates the control
There are the row headers
gridCntrl->Columns[3] refers to a single column gridCntrl->ColumnCount is the number of columns
Column0 gridCntrl->RowCount is the number of rows
Column1
Column2
Column3
Column4
Row0 Row1
gridCntrl->Rows[2] refers to a single row
These are the column headers
gridCntrl->Rows references the collection of rows
Row2 Row3
gridCntrl->Columns references the collection of columns
gridCntrl->Rows[2]>Cells[3] references the 4th cell in the 3rd row
Figure 22-1
You reference rows and columns of cells through properties of the DataGridView control object. The Rows property returns a value of type DataGridRowCollection that is a collection of all the rows, and you refer to a particular row using an index, as illustrated in Figure 22-1. Similarly, the Columns property for the control returns a value of type DataGridViewColumnCollection that you can also index to reference a particular column. Rows and columns are indexed from zero. The Cells property for a DataGridRowCollection object represents a collection containing the cells in the row, and you can index the Cells property to access a specific cell in a row. Figure 22-1 shows an example of how you reference the fourth cell in the third row. The number of rows is available as the value of the RowCount property for the control, and the ColumnCount property returns the number of columns. Initially, when the control is not bound to a data source, it will have no columns or rows. You can set the number of columns and or the number of rows by setting property values for the control, but when you use the control to display data from a data source, this is taken care of automatically. You can use the DataGridView control in three different modes:
1092
Accessing Data Sources in a Windows Forms Application unbound mode
In unbound mode you transfer the data to the control yourself, typically using the Add() function for the Rows property for the control. You would use this mode for displaying relatively small amounts of data.
bound mode
In this mode you identify a source for the data that is to be displayed by setting a value for the DataSource property of the control.
virtual mode
In virtual mode you connect the control to a data cache in memory that you fill with data from a separate data source. You would use this mode to display data from a source where you want to manage data access in order to optimize performance.
In unbound mode, you can use the DataGridView control to display any data in your application that can be displayed in a grid. This makes it a very convenient tool for displaying data in many different kinds of applications. The next section looks into using the control in unbound mode in a little more depth.
Using a DataGridView Control in Unbound Mode The data in DataGridView control is stored in a rectangular arrangement that is identified by the Rows and Columns properties for the control. In unbound mode you’ll add the data to the control using the Add() function for the Rows property, but before you can add rows to the control, the columns need to be defined, at least to establish how many items are in a row. Setting the ColumnCount property for the control programmatically sets how many columns there are and determine that the control is to work in unbound mode. The following statements create a control that you reference using the handle dataGridView and then set the number of columns to 3: DataGridView^ dataGridView = gcnew DataGridView; dataGridView->ColumnCount = 3; // Set number of columns
You can optionally label the columns in the control by specifying headers to identify the data in each column by setting the Name property for each column. Here’s how that could be done: dataGridView->Columns[0]->Name = L”Name”; dataGridView->Columns[1]->Name = L”Phone Number”; dataGridView->Columns[2]->Name = L”Address”;
The Columns property for the control is an indexed property so you access individual columns using index values starting from 0. Thus these statements label the three columns in the dataGridView control. You can also set the column headers through the Properties window for the control, as you’ll see in the next working example. The value returned by the Rows property is a collection of type DataGridViewRowCollection, and this type is defined in the System::Windows::Forms namespace. The Count property for the collection returns the number of rows and there is also a default indexed property to return the row at a given index position. The collection of rows has a large number of functions; I won’t go through them all here, but here are a few of the most useful ones for adding and deleting rows:
1093
Chapter 22 Add()
Adds one or more rows to the collection.
Insert()
Inserts one or more rows in the collection.
Clear()
Deletes all rows in the collection.
AddCopy()
Adds a copy of the row specified by the argument.
InsertCopy()
Inserts a copy of the row specified by the first argument at the position specified by the second argument.
Remove()
Removes the row specified by the argument, which is of type DataGridViewRow^.
RemoveAt()
Removes the row specified by the index value you supply as the argument.
The Add() function for the value returned by the Rows property comes in four overloaded versions that enable you to add a row of data to the control in a variety of ways. Add()
Adds one new row to the collection.
Add(int rowCount)
Adds rowCount new rows to the collection. An exception of type System::ArgumentOutOfRangeException is thrown if rowCount is zero or negative.
Add(DataGridViewRow^ row)
Adds the row specified by the argument. A DataGrid ViewRow object contains the collection of cells in a row as well as the parameters that determine the appearance of the cells in the row.
Add(... Object^ object)
Adds a new row and populates the cells in the row with the objects specified by the arguments.
All versions of the Add() function return a value of type int that is the index of the last row that was added to the collection. If the DataSource property for the DataGridView control is not null, or the control has no columns, all versions of the Add() function throw an exception of type System::InvalidOperationException. You could add rows to the dataGridView control that has three columns with the following statements: dataGridView->Rows->Add(L”Fred Able”, L”914 696 1200”, L”1235 First Street, AnyTown”); dataGridView->Rows->Add(L”May East”, L”914 696 1399”, L”1246 First Street, AnyTown”);
Each of these statements adds a new row to the collection and the three arguments to the Add() function correspond to the three columns in the control. The control must have sufficient columns to accommodate the number of items you add in a row. If you attempt to add more data items to a row than there are columns in the control, the excess items are ignored. You will first try unbound mode in a working example where you set up the DataGridView control by setting its properties from the Form Design tab.
1094
Accessing Data Sources in a Windows Forms Application Try It Out
The DataGridView Control in Unbound Mode
This example displays a list of books where each book is specified by the ISBN, the title, the author, and the publisher. Create a new Windows Form project with the name Ex22_01. Add a DataGridView control to the form and click the arrow at top-right of the control to displays the pop-up menu show in Figure 22-2.
Figure 22-2
If you click the bottom menu item, Dock in parent container, the control fills the client area of the form. The top menu item is for selecting a data source, but you are not going to specify a data source this time. If you click the AddColumn menu item, the dialog box shown in Figure 22-3 for entering columns to the control is displayed. The Unbound column radio button is checked because there is no data source identified for the control, which is the way it should be for this example. The Name: entry is the value of the Name property for the column, and the Header Text: entry is the value of the HeaderText property, which corresponds to the text that is shown in the control as the column heading. If you extend the list box that is for selecting the Type: value, you’ll see you have a range of choices for the type of column. Here you should leave it as the default choice — a TextBox column — because you’ll be adding strings as the data to be displayed. The other column types in the list deal with provide for various controls in the cells representing the data: DataGridViewButtonColumn
This type is used to display a button in each cell in the column.
DataGridViewCheckBoxColumn
This type is used when you want to store bool values (System::Boolean objects) or System::Windows::Forms::CheckState objects as checkboxes in the cells in the column. Table continued on following page
1095
Chapter 22 DataGridViewComboBoxColumn
This type is used when you want to display a drop-down list in each cell in the column.
DataGridViewImageColumn
You select this type when each cell in the column is to display and image in each cell in the column.
DataGridViewLinkColumn
You use this type when each cell in the column is to display a link.
To add a column to the control, you enter values for the Name: and Header Text:, select the Type: from the list if you want other than the default type, and click the Add button. In this example, you can add columns with the names ISBN, Title, Author, and Publisher. The Header Text: entry can be the same as the name in each case. When you have entered the columns, click the Close button to close the dialog (the Close button is visible after you have added at least one column). You can edit the columns at any time by clicking the Edit Columns item in the pop-up menu; it displays the dialog box shown in Figure 22-4.
Figure 22-3
The Edit Columns dialog box enables you to resequence existing columns, to add new columns, or to delete columns; you can also edit any of the properties for a column.
1096
Accessing Data Sources in a Windows Forms Application
Figure 22-4
Return to the Design tab and change the Text property for the form to My Book List. If you display the code for the form, you can modify the constructor to add data to the DataGridView control using the Add() function for the Rows property, like this: Form1(void) { InitializeComponent(); // //TODO: Add the constructor code here // Create book data, one book per array array<String^>^ book1 = {L”0-09-174271-4”, L”Wonderful Life”, L”Stephen Jay Gould”, L”Hutchinson Radius”}; array<String^>^ book2 = {L”0-09-977170-5”, L”The Emperor’s New Mind”, L”Roger Penrose”, L”Vintage”}; array<String^>^ book3 = {L”0-14-017996-8”,L”Metamagical Themas”, L”Douglas R. Hofstadter”, L”Penguin”}; array<String^>^ book4 = {L”0-201-36080-2”, L”The Meaning Of It All”, L”Richard P. Feynman”, L”Addison-Wesley”}; array<String^>^ book5 = {L”0-593-03449-X”, L”The Walpole Orange”, L”Frank Muir”, L”Bantam Press”}; array<String^>^ book6 = {L”0-439-99358-X”, L”The Amber Spyglass”, L”Philip Pullman”, L”Scholastic Children’s Books”}; array<String^>^ book7 = {L”0-552-13461-9”, L”Pyramids”, L”Terry Pratchett”, L”Corgi Books”}; array<String^>^ book8 = {L”0-7493-9739-X”, L”Made In America”, L”Bill Bryson”, L”Minerva”}; // Create Array of books array<array<String^>^>^ books ={book1, book2, book3, book4, book5, book6, book7, book8};
1097
Chapter 22 // Add all the books to the control for each(array<String^>^ book in books ) dataGridView1->Rows->Add(book); // }
There’s an array of type array<String^> created for each book, and the handle to each array is stored in a variable of type array<array<String^>^>^. Each of the arrays of strings has four elements that contain data items that correspond to the columns in the DataGridView control, so each array defines a book. For convenience, you assemble the handles to the arrays of strings into the books array. The type for books looks a little messy because of the ^ repetitions, but it is simply a handle to an array of elements where each element is of type array<String^>^. The books array enables you to set up all the data in the control in a single for each loop. The Rows property for the DataGridView object returns a handle of type DataGridViewRowCollection^ that references the collection of rows in the control. Calling the Add() function for the object returned by the Rows property adds a complete row to the collection. Each element in the array that is passed as the argument corresponds to a column in the control, and the type of data element must correspond with the type you selected for the column. Here all the columns have the same type, so all the cells in a row can be passed in an array. If the columns were of different types, you could specify the item for each column by a separate argument to the Add() function, or you could use an array of elements of type Object^. If you compile and execute the example by pressing Ctrl+F5, you should see the application window shown in Figure 22-5.
Figure 22-5
You get the scrollbars automatically because the DataGridView control extends beyond the boundaries of the client area of the form. If you resize the window, eventually the scrollbars disappear. It would be nice if the columns were wide enough to accommodate the maximum length of text they contain. Changing the value of the AutoSizeColumnsMode property in the Layout group fixes that. Open the Properties window for the DataGridView control from the Form1[Design] tab in the Editor pane and change the AutoSizeColumnsMode property value to AllCells. If you recompile the program and run it again, you’ll see that the application window is now as shown in Figure 22-6.
1098
Accessing Data Sources in a Windows Forms Application
Figure 22-6
Each column has its width set so that it accommodates the longest string that the column contains. Overall, the resultant application window is not too bad, but you can do a lot more programmatically to personalize how it looks.
Customizing a DataGridView Control As I said earlier in the chapter, the appearance of a DataGridView control is highly customizable. You will explore aspects of this using the control in unbound mode, but everything you’ll learn in this context applies equally well to using the control in bound mode. The appearance of each of the cells in a DataGridView control is determined by an object of type DataGridViewCellStyle that has the following properties: Property
Description
BackColor
The value is a System::Drawing::Color object that determines the background color of a cell. The Color class defines a range of standard colors as static members. The default value is Color::Empty.
ForeColor
The value is a Color object that determines the foreground color of a cell. The default value is Color::Empty.
SelectionBackColor
The value is a Color object that determines the background color of a cell when it is selected. The default value is Color::Empty.
SelectionForeColor
The value is a Color object that determines the foreground color of a cell when it is selected. The default value is Color::Empty.
Font
The value is a System::Drawing::Font object that determines the font to be used to display text in the cell. The default value is null. Table continued on following page
1099
Chapter 22 Property
Description
Alignment
The value determines the alignment of the contents of the cell. The values are defined by the DataGridViewAlignment enumeration so the value can be any of the following constants: BottomCenter, BottomLeft, BottomRight, MiddleCenter, MiddleLeft, MiddleRight, TopCenter, TopLeft, TopRight, NotSet The default value is NotSet.
WrapMode
The value determines whether the text in the cell is wrapped when it is too long to fit in the cell. The value is one of the constants defined by the DataGridViewTriState enumeration and can be: True, False, NotSet The default value is NotSet.
Padding
The value is an object of type System::Windows::Forms::Padding that determines the space between the cell contents and the edge of the cell. The Padding class constructor requires an argument of type int that is the padding measured in pixels. The default corresponds to no padding in the cell.
Format
The value is a format string that determines how the content of the string is formatted. This is the same kind of formatting as you have been using in the Console::WriteLine() function. The default value is an empty string.
This is not an exhaustive list of the properties of a DataGridViewCellStyle object, just those that relate to the appearance of a cell. The way in which the appearance of a particular cell is determined is quite complicated because you have a number of different properties that you can set in a DataGridView control that all determine how a given cell or group of cells is displayed, and several of these can be in effect at any given time. For example, you can set property values that specify the appearance of a row of cells, or a column of cells, or all the cells in the control, and these can all be in effect concurrently. Clearly, because a row and column always intersect, all three of these possibilities apply to any given cell, so you have an apparent conflict. Each cell in a DataGridView control is represented by a System::Windows::Forms::DataGridViewCell object, and the appearance of any given cell, including header cells, is determined by the value of its InheritedStyle property. The value of the InheritedStyle property for a cell is arrived at by looking at all the possible properties that return a value that is a DataGridViewCellStyle object that applies to the cell and then considering these properties in a priority sequence; the first property in the sequence that is found to be set is the one that takes effect. The determination of the value of the InheritedStyle property for header cells for rows and columns is handled differently from the InheritedStyle property for other cells, so I’ll discuss them separately, starting with header cells.
1100
Accessing Data Sources in a Windows Forms Application
Customizing Header Cells The InheritedStyle property value for each header cell in the control is determined by considering the values of following properties in sequence: ❑
The Style property for the DataGridViewCell object that represents the cell.
❑
The ColumnHeadersDefaultCellStyle property or the RowHeadersDefaultCellStyle property for the control object.
❑
The DefaultCellStyle property for the control object.
So if the Style property value for the cell object has been set, the InheritedStyle property for the cell takes this value and determines the appearance of the cell. If not, the next candidate takes effect if the value for that has been set. If the second choice has not been set, the DefaultCellStyle property for the control is applied. Don’t forget that the value of the InheritedStyle property is an object of type DataGridViewCellStyle, which itself has properties that determine various aspects of the appearance of the cell. The process of going through the priority sequence applies to each of the properties of the DataGridViewCellStyle object, so overall there may be contributions from more than one of the properties in the priority sequence.
Customizing Non-Header Cells The InheritedStyle property value for each non-header cell in the control (the non-header cells being the cells containing data) is determined from the following properties in the DataGridView object in sequence: ❑
The Style property for the DataGridViewCell object that represents the cell.
❑
The DefaultCellStyle property for the DataGridViewRow object that represents the row containing the cell. You would typically reference the DataGridViewRow object by indexing the Rows property for the control object.
❑
The AlternatingRowsDefaultCellStyle property for the control object; this applies only to cells in rows with odd index numbers.
❑
The RowsDefaultCellStyle property for the control object.
❑
The DefaultCellStyle property for the DataGridViewColumn object that contains the cell. You would typically access a DataGridViewColumn object by indexing the Columns property for the control object.
❑
The DefaultCellStyle property for the control object.
Potentially you could have a different DataGridViewCellStyle object for each cell, but for efficiency you need to keep the number of such objects to a minimum. The next Try It Out explores some of these possibilities in an example where you set up the DataGridView object yourself.
1101
Chapter 22 Try It Out
Setting the Appearance of the Control
Create a new CLR project using the Windows Forms template with the name Ex22_02. Add a DataGridView control to the form in the Design tab and change its (Name) property to dataGridView. This is the name of the handle in the class that references the control object. You can also change the Text property for the form to “My Other Book List.” For the rest of the example, you are going to be working with the code in the constructor. The data that you display is similar to that in the previous example, but to extend the possibilities a little, you’ll add a date entry at the beginning of each row specifying a book, so the cells in the first column will contain references to objects of type System::DateTime, and the remaining columns will be strings. The DateTime class defines an instant in time that you typically specify as a date plus the time of day. In the example, only the date is of interest, so you’ll use a constructor that accepts only three arguments: the year, the month, and the day.
Setting Up the Data The first step is to create the data to be displayed. Add the following code to the Form1 constructor, after the call to InitializeComponent(): // Create book data, one book per array array^ book1 = {gcnew DateTime(1999,11,5), L”0-09-174271-4”, L”Wonderful Life”, L”Stephen Jay Gould”, L”Hutchinson Radius”}; array^ book2 = {gcnew DateTime(2001,10,25), L”0-09-977170-5”, L”The Emperor’s New Mind”, L”Roger Penrose”, L”Vintage”}; array^ book3 = {gcnew DateTime(1993,1,15), L”0-14-017996-8”, L”Metamagical Themas”, “Douglas R. Hofstadter”, L”Penguin”}; array^ book4 = {gcnew DateTime(1994,2,7), L”0-201-36080-2”, L”The Meaning Of It All”, L”Richard P. Feynman”, L”Addison-Wesley”}; array^ book5 = {gcnew DateTime(1995,11,6), L”0-593-03449-X”, L”The Walpole Orange”, “Frank Muir”, L”Bantam Press”}; array^ book6 = {gcnew DateTime(2004,7,16), L”0-439-99358-X”, L”The Amber Spyglass”, L”Philip Pullman”, L”Scholastic Children’s Books”}; array^ book7 = {gcnew DateTime(2002,9,18), L”0-552-13461-9”, L”Pyramids”, L”Terry Pratchett”, L”Corgi Books”}; array^ book8 = {gcnew DateTime(1998,2,27), L”0-7493-9739-X”, L”Made In America”, L”Bill Bryson”, L”Minerva”}; // Create Array of books array<array^>^ books = {book1, book2, book3, book4, book5, book6, book7, book8};
The basic mechanics of this is the same as in the previous example. The differences here are due to each book having an extra item of type DateTime in the specification, so the array elements are of type Object^. You’ll recall that the Object class is a base class for every C++/CLI class so you can store a handle to an object of any class type in an element of type Object^. You can add the following statement to the constructor next: array<String^>^ headers = {L”Date”, L”ISBN”, L”Title”, L”Author”, L”Publisher”};
1102
Accessing Data Sources in a Windows Forms Application This creates an array containing the text that is to appear as column headers in the control. You can add these headers to the control by adding the following code to the constructor: dataGridView->ColumnCount = headers->Length; for(int i = 0 ; iLength ; i++) dataGridView->Columns[i]->Name = headers[i];
// Set number of columns
The first statement specifies the number of columns in the control by setting the value of the ColumnCount property; this also establishes the control in unbound mode. The for loop sets the Name property for each column object to the corresponding string in the headers array. The Columns property for the control returns a reference to the collection of columns, and you just index this to reference a particular column. You can add the rows to the control in another loop: for each(array^ book in books) dataGridView->Rows->Add(book);
The for each loop selects each of the elements from the books array in turn add passes it to the Add() method for the reference returned by the Rows property for the control. Each element in the books array is an array of strings, and there are as many strings in the array as there are columns in the control. The control has now been loaded with the data, so the number of rows and columns is determined and the contents of the column headers have been specified. You can now set about customizing the appearance of the control.
Setting Up the Control You want the control to be docked in the client area of the form, and you can do this by setting the value of the Dock property: dataGridView->Dock = DockStyle::Fill;
The Dock property must be set to one of the constants defined by the DockStyle enumeration; other possible values are Top, Bottom, Left, Right, or None, and these specify the sides of the control that are docked. You can also relate the position of the control to the client area of the form by setting the Anchor property for the control.The value of Anchor property specifies the edges of the control that are to be attached to the client area of the form. The value is a bitwise combination of the constants defined by the AnchorStyles enumeration and can be any or all of Top, Bottom, Left, and Right. For example to anchor the top and left sides of the control, you would specify the value as AnchorStyles::Top & AnchorStyles::Left. Setting the Anchor property fixes the position of the control plus its scrollbars within the container at a given size, so when you resize the application, window the control and its scrollbars remain at a fixed size. If you set the Dock property as in the previous statement, resizing the application window exposes more or less of the control and the scrollbars adjust accordingly, so that is much better in this case. You want the width of the columns to be adjusted to accommodate the data in the cells, and you can put this into effect by calling the AutoResizeColumns() function: dataGridView->AutoResizeColumns();
1103
Chapter 22 This statement adjusts the width of all columns to accommodate the current contents, and this includes header cells. Note that this is effective at the time the function is called, so the contents need to be there when you call it. If the contents are changed subsequently, the column width is not adjusted. If you want the column widths to be adjusted whenever the contents of the cells change, you should also set the AutoSizeColumnsMode property for the control, like this: dataGridView->AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode::AllCells;
The value must be one of the constants defined by the DataGridViewAutoSizeColumnsMode enumeration, and the other possible values are ColumnHeader, AllCellsExceptHeader, DisplayedCells, DisplayedCellsExceptHeader, Fill, and None. Of course, these are also the property values in the list for this property that displays on the Properties page for the DataGridView control. It may be that you want to allow only the columns width for specific columns to be automatically adjusted when the contents change; in this case, you set a value for the AutoSizeMode property for the column object. There are two further overloaded versions of the AutoResizeColumns() function. One accepts an argument of type DataGridViewAutoSizeColumnsMode, and the cells affected are determined by the value of the argument. The other overload is protected and, therefore, for use in functions in a derived class; it accepts an additional argument of type bool that indicates whether the cell height is to be considered in calculating a new width. You can set the default background color of all cells in the control like this: dataGridView->DefaultCellStyle->BackColor = Color::Pink;
This sets the background color as the standard color Pink that is defined as a static member of the Color class. The properties of the DefaultCellStyle property for the control object only determine what applies to a cell in the absence of any higher priority cell style being in effect. You could also set the default foreground color for all cells: dataGridView->DefaultCellStyle->ForeColor = Color::DarkBlue;
To identify when cells have been selected, you can specify selection colors for the foreground and background. Here’s how you could define the background color when a cell is selected: dataGridView->DefaultCellStyle->SelectionBackColor = Color::Green;
Of course, the point of setting property values programmatically is that it happens at run-time so you can set values depending on conditions and data values that you find when the application is running. Property values that you set through the Properties pane in the IDE are set once and for all — unless you have code that changes them subsequently. That’s enough for the control for now. You’ll personalize the column headers next.
1104
Accessing Data Sources in a Windows Forms Application Setting Up the Column Headers If you want to determine the appearance of the column headers yourself, you need to set the value of the EnableHeadersVisualStyles property for the control to false: dataGridView->EnableHeadersVisualStyles = false;
The controls in a WindowsForms application are usually drawn according to the visual styles theme that is in effect, and this theme determines the appearance of the controls. If you are running the application under Windows XP, the controls are drawn according to the Windows XP theme. When the EnableHeadersVisualStyles property value is true, the visual styles for the column headers will be set according to the visual styles theme in effect for the application, and the styles you set are ignored. You’ll be setting several properties for the appearance of the headers and an easy way to do this is to create a DataGridViewCellStyle object for which you can set the properties as you want them, and then make this object the one that determines the styles for the headers. You can create the DataGridViewCellStyle object like this: DataGridViewCellStyle^ headerStyle = gcnew DataGridViewCellStyle;
It would be nice to have the header text in a larger font, and you can set the font by setting a value for the Font property: headerStyle->Font = gcnew System::Drawing::Font(“Times New Roman”, 12, FontStyle::Bold);
The header text is now in 12-point bold characters in the Times New Roman font. You can also set the background and foreground colors for the header cells: headerStyle->BackColor = Color::AliceBlue; headerStyle->ForeColor = Color::BurlyWood;
The text is now drawn in the color BurlyWood against an AliceBlue background. If you prefer something different, the Color class offers you a lot of choices, and Intellisense should show the list as you complete typing the scope resolution operator. To set the appearance of the header cells to correspond with the properties that you’ve set for the headerStyle object, you need to add the following statement: dataGridView->ColumnHeadersDefaultCellStyle = headerStyle;
This sets the value of the ColumnHeadersDefaultCellStyle property for the control to be the headerStyle handle. This replaces the existing DataGridViewCellStyle object that was in effect for the headers. There is one other thing you should do in relation to the column headers. The larger font requires the height of the cells to be adjusted to accommodate it. Calling the AutoResizeColumnHeadersHeight() function for the control adjusts the heights of the header cells to accommodate their current contents: dataGridView->AutoResizeColumnHeadersHeight();
1105
Chapter 22 The heights of all header cells is adjusted to fit the largest cell contents. If you just want the height of a particular column header to be adjusted, you can use the overloaded version of the function that accepts an argument specifying the index of the column to be adjusted. If you don’t want the row or column headers to be visible you can make them disappear by setting the value of the RowHeadersVisible property and/or ColumnHeadersVisible property for the control to false.
Formatting a Column The first column contains handles to a DateTime object. As it is, the application simply calls the ToString() function for the objects to get something to display, but you can do better than that. You can set the Format property for the DefaultCellStyle property for the column, and this format specification is then used to display the contents of the cells: dataGridView->Columns[0]->DefaultCellStyle->Format = L”y”;
This sets the Format property to the string containing the y format specification for a DateTime object that presents the object in the short date form as month plus year. There are several other format specifiers for DateTime objects that you could use. For example, D displays the day as well as the month and year, and f and F displays the time as well as the date. If you have added all that code to the Form1 class constructor, it’s time to don the sunglasses and give the example a whirl. If you compile and run it, you should see something like the application window shown in Figure 22-7.
Figure 22-7
I have resized the width of the window in Figure 22-7 to show more of the columns. Unfortunately, in the book the application window appears in shades of grey but you should see it on your screen in glorious Technicolor. If you click one of the row headers on the left of the control, you should see the row highlighted as shown in Figure 22-8.
1106
Accessing Data Sources in a Windows Forms Application
Figure 22-8
The background color in the cells in the row is the one you set for the SelectionBackColor property of the DefaultCellStyle property for the control. You can also select an individual cell by clicking it, and the background color of the cell changes to green. The ability to sort the rows based on any given column is built into the DataGridView control. You could try clicking a column header and see the rows sorted by the column you select. If you click the column header a second time, the rows are ordered in the opposite sense. You could add a tooltip to each of the columns to explain the sort possibility. Adding this loop to the Form1 class constructor does this: for each(DataGridViewColumn^ column in dataGridView->Columns) column->ToolTipText = L”Click to\nsort rows”;
The Columns property value is a collection of columns where each column is an object of type DataGridViewColumn. The loop iterates over each of the columns and sets the value of the ToolTipText property. Figure 22-9 shows the tooltip for one of the column headers.
Figure 22-9
1107
Chapter 22 These tooltips display only when the mouse cursor is over a column header cell. You can set a tooltip for any of the cells that display the data by setting the ToolTipText property for the cell object.
Customizing Alternate Rows When you are displaying many rows that are similar in appearance, it can be difficult to see which row you are looking at. You can color alternate rows differently to help overcome the problem by setting a different color as the BackColor property for the AlternatingRowsDefaultCellStyle property for the control object: dataGridView->AlternatingRowsDefaultCellStyle->BackColor = Color::Blue;
You will probably want to change the ForeColor property for the AlternatingRowsDefaultCellStyle property to get a reasonable contrast between the text and the background: dataGridView->AlternatingRowsDefaultCellStyle->ForeColor = Color::White;
Now rows are displayed with colors alternating between pink and blue, as shown in Figure 22-10 (in shades of grey, of course, as there is no color in the book).
Figure 22-10
Now it’s easy to separate the rows and the white text against a blue background is clear. You can still select a row by clicking a row header and see the selected row in green. Clicking in the cell at the left end of the column headers selects all the rows.
Dynamically Setting Cell Styles You have several possibilities for changing the appearance of cells by handling events for the DataGridView control. The CellFormatting event for a DataGridView control fires when the contents of a cell need to be formatted ready to be displayed, so by adding a handler for this event you can adjust the appearance of any cell depending on what the contents are. I want now to explore how you could extend Ex22_02 to do this.
1108
Accessing Data Sources in a Windows Forms Application Suppose, for example, that in Ex22_02 you wanted to set the background color of cells in the Date column to red if the date is before the year 2000. Recall from the discussion of events in Chapter 9 that to register a handler for an event you add an instance of the delegate to the event. The delegate for the CellFormatting event is of type DataGridViewCellFormattingEventHandler, and it expects two parameters: the first parameter is of type Object^ and identifies the source of the event and the second parameter is a handle to an object of type DataGridViewCellFormattingEventArgs. The second argument passed to a handler for the CellFormatting event provides additional information about the event through the following properties: Property
Description
Value
The value is a handle to the contents of the cell that is being formatted.
DesiredType
The value is handle to an object of type Type that identifies the type of the contents off the cell being formatted.
CellStyle
Gets or sets the cell style of the cell that is associated with the formatting event so the value is a handle to an object of type DataGrid ViewCellStyle.
ColumnIndex
The value is the column index for the cell that is being formatted.
RowIndex
The value is the row index for the cell that is being formatted.
FormattingApplied
The value, true or false, indicates whether formatting of the cell contents has been applied.
These properties enable you to find out all you need to know about the cell being formatted — the row and column for the cell, the current style in effect, and the contents of the cell. The first step in handling the CellFormatting event is to define a handler function for it. The handler code needs to be as short and efficient as possible because the function is called for every cell in the control whenever the cell needs to be formatted. You could add the following function to the Form1 class that is a handler function for the CellFormatting event: private: void OnCellFormatting(Object^ sender, DataGridViewCellFormattingEventArgs^ e) { // Check if it’s the date column if(dataGridView->Columns[e->ColumnIndex]->Name == L”Date”) { // If the cell content is not null and the year is less than 2000 // Set the background to red if(e->Value != nullptr && safe_cast(e->Value)->Year < 2000) { e->CellStyle->BackColor = Color::Red; e->FormattingApplied = false; // We did not format the data } } }
1109
Chapter 22 You first check whether the current column is the Date column because you are interested only in modifying cells in that column. For cells in the Date column you check if the cell contents actually exist, and if there is a DateTime object present, that the year is less than 2000. In this case you set the BackColor property for the object returned by the CellStyle property to Color::Red. You set the FormattingApplied property to false to indicate that you have not formatted the contents. This is not strictly necessary because the value starts out as false. You would set it to true if you were taking care of formatting the contents in the handler and this would prevent subsequent formatting using the value of the Format property. To register this function as a handler for the CellFormatting event, add the following statement to the end of the Form1 class constructor: dataGridView->CellFormatting += gcnew DataGridViewCellFormattingEventHandler(this, &Form1::OnCellFormatting);
The first argument to the delegate is the handle to the object containing the handler function and is the current Form1 object. The second argument is the address of the function that is the new handler for the event. If you recompile the example and execute it once again, you should see that all the cells in the Date column that contain a date prior to the year 2000 have the background color red. The DataGridView control defines CellMouseEnter and CellMouseLeave events that fire when the mouse cursor enters or leaves a cell. You could implement handlers for these events to highlight the cell that the mouse cursor is over by changing its background color. You could set new background and foreground colors in the handler for the CellMouseEnter event and restore the original colors in the handler for the CellMouseLeave event. There are a few tricky aspects to this, so it’s worth looking into specifically.
Try It Out
Highlighting the Cell under the Mouse Cursor
This will be an extension to Ex22_02 including the latest addition of the CellFormatting event handler rather than a new example from scratch. You’ll need to store the old background and foreground colors somewhere, so add the following private data members to the Form1 class: // Stores for old cell colors in mouse enter event handler // for restoring later in mouse leave event handler private: Color oldCellBackColor; private: Color oldCellForeColor;
You should initialize both of these to Color::Empty in the Form1 class constructor. The first parameter to the delegate for either the CellMouseEnter or CellMouseLeave events is a handle to the object originating the event, which is the DataGridView control. The second parameter to both delegates is a handle to an object of type DataGridViewCellEventsArg that provides additional information about the event. This object has RowIndex and ColumnIndex properties, and the values of these properties enable you to locate the cell the mouse is entering or leaving; you can use the former to index the Rows property to select the row that contains the cell and the latter to index the Cells property to select the cell itself within the row. There’s one thing to note — the value of the RowIndex property is -1 when the mouse cursor is in the column header row and the ColumnIndex property value is -1 when the mouse cursor is over one of the row headers. You’ll need to check for these possibilities because attempting to use a negative index with the Rows property value causes an exception to be thrown, as does indexing the Cells property for a row with a negative value.
1110
Accessing Data Sources in a Windows Forms Application You can now define a private handler function in the Form1 class for the CellMouseEnter event like this: private: void OnCellMouseEnter(Object^ sender, DataGridViewCellEventArgs^ e) { if(e->ColumnIndex >= 0 && e->RowIndex >= 0) // Verify indexes non-negative { // Identify the cell we have entered DataGridViewCell^ cell = dataGridView->Rows[e->RowIndex]->Cells[e->ColumnIndex]; // Save any old colors that are set oldCellBackColor = cell->Style->BackColor; oldCellForeColor = cell->Style->ForeColor; // Set highlight colors cell->Style->BackColor = Color::White; cell->Style->ForeColor = Color::Black; } }
After establishing that both index values are non-negative, you obtain the handle for the cell that the mouse cursor entered. You do this by first selecting the row by indexing the value of the Rows property for the control with the RowIndex property value for the parameter e; you then index the Cells property of the row using the ColumnIndex property of e to select the cell within the row. After you have the cell handle, it’s easy to save the values of the BackColor and ForeColor properties from the Style property of the cell and set new colors to display the cell as black text on a white background. The Style property may not have been set, in which case accessing the property value creates a new DataGridViewCellStyle object as the value that has BackColor and ForeColor property values as Color::Empty. If the Style property for the cell has been set, you’ll get the object containing whatever properties have been set for it. The handler function for the CellMouseEnter event has to restore the color back to what is was. You can implement this handler function like this: private: void OnCellMouseLeave(Object^ sender, DataGridViewCellEventArgs^ e) { if(e->ColumnIndex >=0 && e->RowIndex >=0) { // Identify the cell we are leaving DataGridViewCell^ cell = dataGridView->Rows[e->RowIndex]->Cells[e->ColumnIndex]; // Restore the saved color values cell->Style->BackColor = oldCellBackColor; cell->Style->ForeColor = oldCellForeColor; // Reset save stores to no color oldCellForeColor = oldCellBackColor = Color::Empty; } }
1111
Chapter 22 Again you check that the index values are non-negative before doing anything. After identifying the cell as in the previous handler, you restore the saved colors in the Style property for the cell. The way in which the foreground and background colors for a cell are determined is by the priority list you saw earlier. If the Style property had not been set for the cell, the values you restore are Color::Empty and this is ignored when the colors for the cells are determined. Thus, the original color applies. If the Style property had been defined with ForeColor and BackColor properties set, these are the values you restore, and they determine the cell formatting colors. To register the function handlers, add the following statements to the end of the Form1 class constructor: dataGridView->CellMouseEnter += gcnew DataGridViewCellEventHandler(this, &Form1::OnCellMouseEnter); dataGridView->CellMouseLeave += gcnew DataGridViewCellEventHandler(this, &Form1::OnCellMouseLeave);
The same delegate applies to all cell events, so you register both handlers using the DataGridViewCellEventHandler delegate. If you recompile the program a run it once again, you should see highlighting of cells in action, as illustrated in Figure 22-11.
Figure 22-11
Well, it certainly works — at least most of the time. However, the red cells in the Date column aren’t highlighted, so what’s going on? The sequence of events is at the root of the problem. The CellFormatting event is triggered after the CellMouseEnter event, so the handler function that sets the background color to red has the last word and overrides the effect of the handler for the CellMouseEnter event. What you want to happen is that the CellFormatting event handler should recognize that the cell is highlighted and do nothing when this is the case. You could provide for this by adding another member to the Form1 class that stores the handle to the cell that is currently highlighted: private: DataGridViewCell^ highlightedCell;
// The currently highlighted cell
You should also initialize this new member to nullptr in the Form1 class constructor.
1112
Accessing Data Sources in a Windows Forms Application You now need to amend the handler for the CellMouseEnter event to store the handle for the highlighted cell in the new member: void OnCellMouseEnter(Object^ sender, DataGridViewCellEventArgs^ e) { if(e->ColumnIndex >= 0 && e->RowIndex >= 0) // Verify indexes non-negative { // Identify the cell we have entered highlightedCell = dataGridView->Rows[e->RowIndex]->Cells[e->ColumnIndex]; // Save any old colors that are set oldCellBackColor = highlightedCell->Style->BackColor; oldCellForeColor = highlightedCell->Style->ForeColor; // Set highlight colors hightLightedCell->Style->BackColor = Color::White; highlightedCell->Style->ForeColor = Color::Black; } }
You can change the implementation of the handler for the CellMouseLeave event to the following: void OnCellMouseLeave(Object^ sender, DataGridViewCellEventArgs^ e) { if(e->ColumnIndex >=0 && e->RowIndex >=0) { // Restore the saved color values highlightedCell->Style->BackColor = oldCellBackColor; highlightedCell->Style->ForeColor = oldCellForeColor; // Reset save stores to no color oldCellForeColor = oldCellBackColor = Color::Empty; highlightedCell = nullptr;
// Reset highlighted cell handle
} }
You no longer need to determine the cell handle, as it’s available in the highlightedCell member of the Form1 class. You don’t even have to check it, because a CellMouseLeave event must always be preceded by a CellMouseEnter event. You reset the handle of the highlighted cell to null because it’s good practice to do so. You can now amend the handler for the CellFormatting event: void OnCellFormatting(Object^ sender, DataGridViewCellFormattingEventArgs^ e) { // Check whether the cell is highlighted if(dataGridView->Rows[e->RowIndex]->Cells[e->ColumnIndex] == highlightedCell) return; // Check if it’s the date column if(dataGridView->Columns[e->ColumnIndex]->Name == L”Date”) {
1113
Chapter 22 // If the cell content is not null and the year is less than 2000 // Set the background to red if(e->Value != nullptr && safe_cast(e->Value)->Year < 2000) { e->CellStyle->BackColor = Color::Red; e->FormattingApplied = false; // We did not format the data } } }
If you rebuild the example, you should now see all the cells highlighted. You should now have a good idea of how you can implement event handler for a DataGridView control. There are a multitude of other events, so you have huge scope for doing many more things dynamically to customize the control to your application needs.
Using Bound Mode In bound mode, the source of the data that a DataGridView control displays is specified by the value of its DataSource property, which in general you can set to be any ref class object of a type that implements any of the following interfaces: Interface
Description
System::Collections::Ilist
A class that implements this interface represents a collection of objects that can be accessed through a single index. All C++/CLI onedimensional arrays implement this interface, so a DataGridView object can use any onedimensional array as the source of the data that is displayed. The IList interface inherits the members of the ICollection and IEnumerable interface classes that are defined in the System::Collections namespace.
System::ComponentModel::IListSource
A class that implements this interface makes the data available as a list that is an IList object. The list can contain objects that also implement the IList interface.
System::ComponentModel::IBindingList
This interface class extends the IList interface class to allow more complex data binding situations to be accommodated.
System::ComponentModel:: IBindingListView
Adds sorting and filtering capabilities to the IBindingList interface. The BindingSource class that you’ll meet a lit-
tle later in this chapter defines a control that implements this interface.
1114
Accessing Data Sources in a Windows Forms Application You can obviously design your own classes so that that implement one or other of these interfaces, and then you’ll be able to use them as a data source for a DataGridView control in bound mode. Most of the time, though, you’ll want to access an existing data source without having to go to the trouble of creating your own classes to access the data in which case the BindingSource component is likely to be your first choice.
The BindingSource Component You use the BindingSource component as an intermediary between controls on a form and a table in a data source. You have the option of binding the component to a DataGridView control that displays the contents of the table, or to a set of individual controls where each displays a column from the table. You can also add data programmatically to a BindingSource component, in which case it acts as the data source and behaves essentially as a list. You’ll first look at how you use a BindingSource component as the data source for a DataGridView control. There is a high degree of automation possible in creating a program that uses a BindingSource component, but to get an idea of how the component hooks up with the control, you’ll assemble the components on the form manually in the first instance. To make a BindingSource component the data source for a DataGridView control, you set the value of the DataSource property for the control to be the handle that references the BindingSource component.
Try It Out
Using a BindingSource Component
Here you’ll put together a simple program to view a database table. I’ll describe the process assuming you are using the Northwind database that you used back when you were working with the MFC, but you can use any database you have available on your system. Create a new Windows Forms project with the name Ex22_03 and change the Text property for the form to something helpful such as “Using a Binding Source Component.” Add a DataGridView control to the client area of the form and change its Name property to dataGridView. You can also set the Dock property value for the control to FILL. At the moment, the DataGridView control is unbound, so you need to add a data source to the project that you can bind to the control, and this process will create the BindingSource component along the way. Click the small arrow at the top right of the control to display its menu, click the arrow for the list box adjacent to the Choose Data Source menu item, and click the Add Project Data Source link. This displays the dialog box shown in Figure 22-12. The same dialog box is displayed if you select the Data→ Add New Data Source menu item from the main menu, but this only adds the data source to the project — it does not associate it with a control. As you see, you have a choice of two locations for the data source, but here you want to click the Database option. The second option allows you to specify an object that provides the data source defined either within the project or within some other assembly that you have created. After selecting the Database option and clicking the Next button, you’ll see the dialog box shown in Figure 22-13.
1115
Chapter 22
Figure 22-12
Figure 22-13
The existing data connections that you have set up appear in the drop-down list, and you can choose one of those. You can also click the New Connection button to set up a new connection to a data source. This displays the Add Connection dialog box shown in Figure 22-14.
1116
Accessing Data Sources in a Windows Forms Application
Figure 22-14
Here you can enter the data source specification as a name, or you can enter a connection string for the data source by clicking the second radio button. After you have entered any necessary login information, you can test that the connection really does work by clicking the Test Connection button. On my system, the ODBC source is preselected, but if you don’t want the default that you see displayed, you can click the Change button to display the Change Data Source dialog box shown in Figure 22-15.
Figure 22-15
1117
Chapter 22 The dialog box displays the types of data sources that you have available, and you choose the type of data source that you want to work with and click the OK button. You’ll then return to the dialog box shown in Figure 22-14 where you can complete the identification and verification of the data source before clicking the OK button to return to the dialog shown in Figure 22-13. When you click the Next button, you are likely to see a message box asking if you want to add the data source to the project; clicking the Yes button then displays the dialog box shown in Figure 22-16 where you can choose the objects in the database that you want to work with.
Figure 22-16
Here you can choose which database objects you want added to the project. You do this by expanding the tree so you can select the individual tables you want to work with, or even individual fields within a table. For this example, you can keep it simple and choose just the Customers table. You can also change the name of the dataset — I changed it to Customers. When you click the Finish button, the wizard creates the code that you need to access the database. The database is encapsulated in a class derived from the DataSet class. Each database table that you select results in a class derived from the DataTable class being defined as an inner class to the DataSet class. There is also a table adapter class for each DataTable in the DataSet class that has the job of establishing the connection to the database and loading the data from the database table into the corresponding DataTable member of the DataSet object. This results in a considerable amount of code being generated; with just the Customers table in the Northwind database selected you get nearly 2000 lines of code. It also adds a BindingSource component to the project that provides the interface between the Customers table in the Northwind database and the DataGridView control. The Design tab in the editing window should look like Figure 22-17.
1118
Accessing Data Sources in a Windows Forms Application
Figure 22-17
You can see that three objects have been added to the project as a result of adding the data source: the NorthWindDataSet object that encapsulates the database, the CustomersTableAdapter object that accesses the data in the Customers table in the database, and the CustomersBindingSource object that manages the communications between the database and the DataGridView control. The application is now complete, and so far you have not written a single line of code. That’s quite remarkable considering the amount of function you have in the program; however, when I ran the program, the column headers look a little cramped. I prefer the column widths to be set to accommodate the text in the rows, so I couldn’t resist adding the following two lines of code to the Form1 class constructor: dataGridView->AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode::AllCells; dataGridView->AutoResizeColumnHeadersHeight();
The application window now looks as shown in Figure 22-18.
1119
Chapter 22
Figure 22-18
You can use the scrollbars to navigate the data and your mouse wheel should scroll the rows. The BindingNavigator control could improve things a bit, so next you’ll see how to use that.
Using the BindingNavigator Control The BindingNavigator control has been specifically designed to work with a BindingSource component. To use a BindingNavigator control to navigate the data from a data source could not be simpler; you just add the control to the form and set the value of the BindingSource property for the control to the variable encapsulating the BindingSource component. The next Try It Out extends Ex22_03 to do that.
Try It Out
Using a BindingNavigator Control
Click the BindingNavigator control in the Toolbox window and then click in the client area of the form to add it to the project. If you open the Properties window for the control, you are able to set the value for the BindingSource property to customersBindingSource, which is the name of the handle to the BindingSource control that encapsulates the Customers table. That’s it; you’re done. If you recompile and rerun the application, you see that the application window now has a toolbar for navigating the data, as shown in Figure 22-19. You can click the button arrows to progress forwards and backwards through the data records, and there are also buttons to go to the first or last records. If you type a record sequence number in the text box on the toolbar and press Enter, you’ll go directly to that record. The ability to navigate through the records works in whatever sequence they are in. You could sort the records in country order by clicking the header for the Country column to sort the records, and you’ll then be able to navigate through them in that sequence. The BindingNavigator control also provides buttons for adding a new record and deleting a record. Each of the buttons provided by the BindingNavigator control connects to a member of the BindingSource object being navigated:
1120
Accessing Data Sources in a Windows Forms Application
Figure 22-19
Toolbar Control
Action
Move First
Calls the MoveFirst() function for the BindingSource control object, which changes the current record for the underlying data source to be the first record.
Move Previous
Calls the MovePrevious() function for the BindingSource control object, which changes the current record for the underlying data source to be the previous record if there is one.
Current Position
Corresponds to the value of the Current property for the BindingSource object, which is the current record in the underlying data source.
Total Number of Items
Corresponds to the value of the Count property value for the BindingSource object, which corresponds to the number of records in the underlying data source.
Move Next
Calls the MoveNext() function for the BindingSource control object, which changes the current record for the underlying data source to be the next record if there is one.
Move Last
Calls the MoveLast() function for the BindingSource control object, which changes the current record for the underlying data source to be the last record.
Add New
Calls the AddNew() function for the BindingSource object. This has the effect of calling EndEdit() to execute any pending edit operations for the underlying data source and creates a new record in the list maintained by the BindingSource object. This does not update the underlying data source.
Delete
Calls the RemoveCurrent() function for the BindingSource object to remove the current record from the list. This does not modify the underlying data source.
1121
Chapter 22 Thus clicking a button on the navigator toolbar initiates an action in the BindingSource object that is managing the data source, but none of the default operations change the database that the BindingSource component is managing. To do that you must write some code.
Try It Out
Updating a Database
You are going to have to do something extra when the user clicks a button in the BindingNavigator control to add a new record or to delete a record. The way to do this is to implement a handler function to deal with a Click event for the buttons. As you already know, you can add a Click event handler for a button by double-clicking the button in the Design tab, so add handler functions for the Add New and Delete buttons on the toolbar. When you click either button at the moment, everything has been put in place in the BindingSource component to allow the database to be updated. All you have to do is call the Update() function for the table adapter object for the table that is to be updated. This function throws an exception if things go wrong, so you must put the call in a try block and catch any exception that may be thrown. Here’s how you can implement the handler function for the Add New button Click event: System::Void bindingNavigatorAddNewItem_Click(System::Object^
sender, System::EventArgs^
e)
{ try { CustomersTableAdapter->Update(Customers->_Customers); } catch (Exception^ ex) { MessageBox::Show(L”Update Failed!\n”+ex, L”Database Record Update Error”, MessageBoxButtons::OK, MessageBoxIcon::Error); } }
The argument to the Update() function must be the name of the data table that contains the values that are to be written to the database, so in this case it’s the _Customers member of the Customers object in the Form1 class. If things don’t go as well as expected, you display a message box explaining the problem. The message box shows the text from the Exception object that was thrown, and this explains the cause of the problem. The implementation of the Click event handler for the Delete button is almost identical: private: System::Void bindingNavigatorDeleteItem_Click(System::Object^ sender, System::EventArgs^ { try { CustomersTableAdapter->Update(Customers->_Customers); } catch (Exception^ ex) {
1122
e)
Accessing Data Sources in a Windows Forms Application MessageBox::Show(L”Delete Failed!\n”+ex, L”Database Record Delete Error”, MessageBoxButtons::OK, MessageBoxIcon::Error); } }
The only difference is in the text in the message box. With these two handler functions in place, you should be able to add new customer records and delete existing records.
Binding to Individual Controls You can also create a Windows Forms application that binds each column on a database table to a separate control; what’s more, you’ll find this easier and quicker than the previous example. Start by creating a new CLR project using the Windows Forms Application template with the name Ex22_04. The next step is to add a data source to the project, and again you will be working with a single table. Press Shift+Alt+D to display the Data Sources window and click Add New Data Source. You can use the Northwind database or a database of your choice, but keep in mind that you have a separate control on the form for each column in the table that you choose. To keep the number of controls manageable, for the Northwind database I suggest you select the Order Details table, as shown in Figure 22-20, because it has only five columns.
Figure 22-20
When you click the Finish button, the Data Sources window shows the Northwind database as the data source with just the Order Details table available. Click the Order Details table name to select it and then click the down arrow to the right to display the menu shown in Figure 22-21.
1123
Chapter 22
Figure 22-21
The top three menu items enable you to choose the controls to be used with the table when you add the data source to the form. If you click the DataGridView item from the menu, you are selecting that control as the one to be for displaying the table, whereas clicking on the Details item indicates you want one control per table column. If you click the [None] item, you are indicating you want no controls to be created when you add the data source to the form. The last menu item opens a dialog box for changing the default control for the table from the current default of DataGridView and for customizing the choice of controls. In this instance, you should just click Details because you want one control for each table column. You now have to decide which control you want to use for each table column. You can extend the tree that shows the column names in the Order Details table name by clicking the + symbol to the left of the table name. If you then click the first column name to select it, you’ll see that you can display a menu for that, too, by clicking the down arrow. The menu is shown in Figure 22-22. You can choose any of the controls shown in the menu, but I suggest a TextBox control is most appropriate for the OrderID column. You need to repeat the process for each table column; you can choose a NumericUpDown control for the Quantity column and select a TextBox control for each of the others. Note that selecting the Customize menu option in the Data Sources pane shown in Figure 22-22 displays the Options dialog box in which you can change the selection of controls available for displaying different types of data. You can also change the control to be selected by default when you drag an item from the Data Sources pane to a form. Figure 22-23 shows the Options dialog box.
1124
Accessing Data Sources in a Windows Forms Application
Figure 22-22
Figure 22-23
Figure 22-23 shows the controls associated with displaying a list, and there is a separate list of associated controls for each of the data types you can select. I have checked the ComboBox and ListBox controls in addition to the DataGridView default, so all three controls are options for displaying a list of data items. You can choose other data types in the drop-down list box at the top of the dialog box for which you want to modify the choice of controls available.
1125
Chapter 22 The final step to create the program is to drag the Order Details table from the Data Sources window to the client area of the form window. The Design tab in the Editor pane will then look similar to that shown in Figure 22-24.
Figure 22-24
I have changed the Text property for the form to make the text in the title bar a little more relevant, and I repositioned the controls slightly so they are better located within the client area. I also rearranged the items in the grey area at the bottom to make them all visible in the Design pane. You can see that five controls corresponding to the five table columns have been added automatically to the form as well as label controls to indicate which is which. There’s a BindingNavigator control at the top of the client area for navigating the table data. Below the form you can see that the application has a BindingSource component that links the database to the controls, and the DataSet and table adapter classes are also identified. If you press Ctrl+F5 to build and execute the program, you’ll have a complete working program for viewing and editing the Order Details table in the Northwind database. There is a Save button that has been added to the BindingNavigator toolbar that you click to store any changes you make back in the database table. Figure 22-25 shows the application window. You could create a program that uses the DataGridView control to display a table in essentially the same way. If you want to try it, just create another project and add the data source as in the previous example. If you then immediately drag the table from the Data Sources window to the form, the application is complete. You need only set Text property for the form for the title bar text and set the value of the Dock property for the DataGridView control before compiling and running the program.
1126
Accessing Data Sources in a Windows Forms Application
Figure 22-25
Working with Multiple Tables Creating an application that works with multiple tables is almost as easy as the previous example. In this example, you’ll use a tab control to allow three different tables in the Northwind to be accessed. Create a new Forms project with the name Ex22_05, and press Shift+Alt+D to open the Data Sources window. Add the Northwind database to the project with the Customers, Products, and Employees tables checked. Add a TabControl control from the Containers group in the Toolbox window to the form and set the Dock property value for the tab control to Fill. If you click the arrow at the top right of the control, you’ll be able to add a third tab page to the control. You can move between the tabs on the TabControl control using the Tab key, or by clicking the tab page label twice; take care not to double-click the control or you’ll generate handler functions for it. Move to the first tab page and set its Text property value to Employees. You can then set the Text property value for the other two tabs to Customers and Products. You should also add a Panel control to each tab page with its Dock property value set to Fill. This is necessary to locate the BindingNavigator and DataGridView controls properly on the tab page. If you add them directly to the tab, setting the DataGridView Dock property to Fill with the BindingNavigator control docked to the top of the tab page, the column headers for the DataGridView control are hidden by the BindingNavigator control. This won’t happen Within a Panel container. You might also want to change the Text property value for the form to something relevant — I made it “Accessing Multiple Tables.”
You can now drag the Customer table from the Data Sources window to the panel on the tab page labeled Customers. A DataGridView control IS added to the panel, and a BindingNavigator control appears at the top of the form. You’ll want each tab page to have its own BindingNavigator control, so having it placed on the form is not convenient. You’ll need to move it to the panel on the tab page. You can do this by first setting the Dock property value for the BindingNavigator control to None and then dragging the control on to panel on the Customers tab page.
1127
Chapter 22 After you have added the table to the Customers tab page, switch to the next tab before dragging the next table on to its panel from the Data Sources window. When you have added the appropriate table to the panels on the other two tab pages, they each contain a DataGridView control, but no BindingNavigator control — this was not added because you have one already from adding the Customers table. You could add BindingNavigator controls to these tab pages from the Toolbox window, but there’s a shortcut you can use. Click the BindingNavigator control on the Customers tab page and press Ctrl+C to copy it to the Clipboard. Switch to one of the other tab pages, select its panel, and press Ctrl+V to copy the control from the Clipboard to the panel on the tab page. Switch to the third tab page, select its panel, and then press Ctrl+V once more to add a BindingNavigator control to the panel on that tab page. You can then set the Dock property value for each of the three BindingNavigator controls to Top and the Dock property value for each of the DataGridView controls to Fill. The two BindingNavigator controls that are copies have their BindingSource property values set incorrectly, so select the value field for the property for each of these controls and select the correct BindingSource component from the drop-down list. You should select EmployeesBindingSource for the control on the Employees tab page, and ProductsBindingSource for the control on the Products tab page. If you press Ctrl+F5 to build and execute the example, you should see the application window shown in Figure 22-26.
Figure 22-26
This all works with no coding at all. I think you’ll agree that this is an amazing capability for generating applications to access data sources.
1128
Accessing Data Sources in a Windows Forms Application
Summar y This has been a brief introduction to the capabilities you have for accessing data sources in a Windows Forms application. There’s a great deal more you can do, but you should find that as you now have a good idea of how you use the design capability to assemble controls on a form and how the controls involved in data access work together. You’ll have few problems getting into other areas by yourself. The key points you have learned about in this chapter include: ❑
A data source can be a relational database, a Web service, or an object.
❑
A class derived from the System::Data::DataSet class is used to encapsulate a data source, and a class derived from the System::Data::DataTable class table encapsulates a table in a data source.
❑
A row of data in a DataTable object is represented by an object of type System::Data::DataRow, and the schema for a column is described by an object of type System::Data::DataColumn.
❑
A connection to a data source and the commands to access the data are encapsulated in a component called a table adapter.
❑
You use a DataGridView control on a form to display data in the form of a rectangular grid.
❑
You can bind a DataGridView control to a data source to display the contents of a table. You can also use a DataGridView control in unbound mode to display data originating in your program.
❑
You can customize a DataGridView control to modify how rows, columns, headers and individual cells are displayed.
❑
A BindingSource component provides an interface between a data source and controls on a form. A BindingSource component can link the columns in a table to individual controls on a form, or it can link the contents of a table to a DataGridView control.
❑
A BindingNavigator control provides a toolbar for navigating data that you access via a BindingSource component.
Exercises You can download the source code for the examples in the book and the solutions to the following exercises from http://www.wrox.com.
1. 2. 3. 4.
Modify Ex22_04 so that the column headers are displayed in a 12-point italic font. Modify Ex22_05 so the columns are wide enough to accommodate the text in each cell. Modify Ex22_05 so that alternate rows of data on each tab page appear shaded. Create a Windows Forms application that displays the Suppliers table from the Northwind database.
1129
A C++ Keywords Keywords have been assigned special significance within the C++ language, so you must not use them as names within your programs. The Visual C++ 2005 compiler compiles programs written in ISO/ANSI C++ and programs written for the CLR that conform to the C++/CLI specification, so the compiler recognizes the set of keywords defined by ISO/ANSI C++ as well as the additional set of keywords defined by C++/CLI. Although programming in native C++, you need be concerned only with the ISO/ANSI C++ keywords. When writing programs for the CLR, you need to be aware of both sets of keywords.
ISO/ANSI C++ Keywords The ISO/ANSI C++ language specification defines the following keywords: asm
false
sizeof
auto
float
static
bool
for
static_cast
break
friend
struct
case
goto
switch
catch
if
template
char
inline
this
class
int
throw
const
long
true
const_cast
mutable
try
continue
namespace
typedef Table continued on following page
Appendix A default
new
typeid
delete
operator
typename
do
private
union
double
protected
unsigned
dynamic_cast
public
using
else
register
virtual
enum
reinterpret_cast
void
explicit
return
volatile
export
short
wchar_t
extern
signed
while
C++/CLI Keywords The C++/CLI language specification defines the following keywords in addition to those defined for ISO/ANSI C++: enum class
enum struct
for each
gcnew
interface class
interface struct
nullptr
ref class
ref struct
value class
value struct
Note that the word pairs are keywords, not necessarily the individual words; for example, for each is a keyword, but each is not. The C++/CLI language also defines a number of identifiers that are not keywords but have a contextsensitive meaning in some circumstances. These are: abstract
delegate
event
finally
generic
in
initonly
internal
literal
override
property
sealed
where In principle you can still use these identifiers as names in your code because the context determines when they have special significance, but I recommend that you treat them as keywords and do not use them for other purposes. In that way you avoid any possibility for confusion on the part of someone else who may be reading your code.
1132
B ASCII Codes The first 32 ASCII (American Standard Code for Information Interchange) characters provide control functions. In the following table, only the first 128 ASCII characters have been included. The remaining 128 characters include further special symbols and letters for national character sets, so there are many varieties of these to suit a wide range of language contexts. Decimal
Hexadecimal
Character
Control
000
00
null
NUL
001
01
J
SOH
002
02
•
STX
003
03
♥
ETX
004
04
♦
EOT
005
05
♣
ENQ
006
06
♠
ACK
007
07
•
BEL (Audible bell)
008
08
Backspace
009
09
HT
010
0A
LF (Line feed)
011
0B
VT (Vertical tab)
012
0C
FF (Form feed)
013
0D
CR (Carriage return)
014
0E
SO
015
0F
¤
SI Table continued on following page
Appendix B Decimal
Hexadecimal
016
10
DLE
017
11
DC1
018
12
DC2
019
13
DC3
020
14
DC4
021
15
NAK
022
16
SYN
023
17
ETB
024
18
CAN
025
19
EM
026
1A
➔
SUB
027
1B
➔
ESC (Escape)
028
1C
\
FS
029
1D
GS
030
1E
RS
031
1F
US
032
20
space
033
21
!
034
22
“
035
23
#
036
24
$
037
25
%
038
26
&
039
27
‘
040
28
(
041
29
)
042
2A
*
043
2B
+
044
2C
,
045
2D
-
046
2E
.
1134
Character
Control
ASCII Codes Decimal
Hexadecimal
Character
047
2F
/
048
30
0
049
31
1
050
32
2
051
33
3
052
34
4
053
35
5
054
36
6
055
37
7
056
38
8
057
39
9
058
3A
:
059
3B
;
060
3C
063
3F
?
064
40
@
065
41
A
066
42
B
067
43
C
068
44
D
069
45
E
070
46
F
071
47
G
072
48
H
073
49
I
074
4A
J
075
4B
K
076
4C
L
077
4D
M
Control
Table continued on following page
1135
Appendix B Decimal
Hexadecimal
Character
078
4E
N
079
4F
O
080
50
P
081
51
Q
082
52
R
083
53
S
084
54
T
085
55
U
086
56
V
087
57
W
088
58
X
089
59
Y
090
5A
Z
091
5B
[
092
5C
\
093
5D
]
094
5E
^
095
5F
_
096
60
‘
097
61
a
098
62
b
099
63
c
100
64
d
101
65
e
102
66
f
103
67
g
104
68
h
105
69
i
106
6A
j
107
6B
k
108
6C
l
1136
Control
ASCII Codes Decimal
Hexadecimal
Character
109
6D
m
110
6E
n
111
6F
o
112
70
p
113
71
q
114
72
r
115
73
s
116
74
t
117
75
u
118
76
v
119
77
w
120
78
x
121
79
y
122
7A
z
123
7B
{
124
7C
|
125
7D
}
126
7E
~
127
7F
delete
Control
The Unicode codes that have the same numerical code values as the ASCII codes in the table represent the same characters. You’ll find comprehensive information on the Unicode character coding system at http://www.unicode.org.
1137
Index
Index
Index
Index
SYMBOLS :: (colons), scope resolution operator classes, 341–342 definition, 26 example, 93–94 , (comma), expression separator, 76–77 . (period) member access operator, 325 member selection operator, 325 ; (semicolon), end of statement indicator, 47 & (ampersand) AND, 82–83 address-of operator, 173–174 && (ampersands), logical AND, 125 >> (angle brackets), extraction operator, 62–63 -> (arrow) indirect member access operator, 332 indirect member selection operator, 332 * (asterisk), indirection operator, 174 ^ (caret), exclusive OR, 85 “...” (double quotes), special character indicator, 65 = (equal sign), assignment operator, overloading, 418–422 == (equal signs), relational operator, 115–116 ! (exclamation mark), logical NOT, 126 != (exclamation mark, equal sign), relational operator, 115–116 > (greater than) operator overloading, 415–417 OR, 84–85 relational operator, 115–116
>= (greater than, equal sign), relational operator, 115–116 (right angle bracket), OR, 84–85 >> (right angle brackets), shift right, 86–87 // (slashes), comment indicator, 44 || (vertical bars), logical OR, 125–126 { } (curly braces), function syntax, 46 ~ (tilde), NOT, 86
A abstract classes, inheritance, 505–508 access control classes, 336 inheritance, 479–482, 489–490
access specifiers access specifiers, 531–532 Add() function, 1094 AddCopy() function, 1094 AddHead() function, 764–766, 772 AddNew() function, 980–982, 1121 addresses, returning values from, 256–257 AddTail() function, 764–766, 772 AFX_EXT_CLASS keyword, 912–913, 916 aliases. See references; tracking references. alignment, cells, 1100 Alignment property, 1100 allocating memory. See dynamic memory allocation. AlternatingRowsDefaultCellStyle property, 1101 ampersand (&) AND, 82–83 address-of operator, 173–174 ampersands (&&), logical AND, 125 angle brackets (>>), extraction operator, 62–63 anonymous unions, 409–410 API (application programming interface), 617–618 application class, 653 application programming interface (API), 617–618 Application wizard. See MFC Application wizard. Arc() function, 716–717 arguments, to functions arrays as, 243–247 arrays of function pointers as, 277 definition, 232 function pointers as, 275–277 passing to main(), 250–252, 267–268 passing-by-pointer, 241–243 passing-by-reference, 247–249 passing-by-value, 240–241 pointer notation, 244–245 variable number of, 252–254, 266–267 arithmetic operations , (comma), expression separator, 76–77 -- (minus signs), decrement operator, 74–76 ++ (plus signs), increment operator, 74–76 assignment statements, 67–68 basic operators, 68 bitwise operators & (ampersand), AND, 82–83 ^ (caret), exclusive OR, 85 (right angle bracket), OR, 84–85 >> (right angle brackets), shift right, 86–87 ~ (tilde), NOT, 86 description, 81 inclusive OR, 84–85 casting types
1142
in assignment statements, 79–80 C++/CLI, 108–109 definition, 78 explicit casts, 80–81 old-style casts, 81 rules for, 78–79 safe_cast operation, 108–109 const modifier, 70–71 example, 69–73 expressions, separating, 76–77 Lvalues, 68 memory addresses, 68 modifying variables, 73–74 operator precedence, 77–78 with pointers, 185–187 remainders, calculating, 69–73 Rvalues, 68 arrays of arrays, 213–216 character, 166–169 CLR, 200–205 collection classes CArray template class, 761–763 collections of objects, 761–763 definition, 760 collections of objects, 761–763 elements, 160 entering data, 163 as function arguments, 243–247 indexing, 160–161 multidimensional basic structure of, 169–170 initializing, 170–172 passing to functions, 245–247 pointer notation, 191–192 string handling, 171–172 names, as pointers, 187–189 null character, 166 of objects, 363–364 one-dimensional basic structure of, 160–161 declaring, 161–164 initializing, 164–165 string handling, 166–169 string termination character, 166 and pointers, 185–192 of pointers, 179–181 size of, determining, 181–183 sizeof operator, 181–183
arrow (->) indirect member access operator, 332 indirect member selection operator, 332 ASCII codes, table of, 1133–1137 assemblies, 25 Assert() function, 578–580, 607–608 assertions, 578–580, 607–608 assignment statements, 47, 67–68, 79–80 asterisk (*), indirection operator, 174 automatic variables, 88–91
B b prefix, 619–620 BackColor property, 1099–1100 background color, cells, 1099–1100 base classes accessing private members, 480–482 definition, 475–476 deriving classes from, 476–479 direct, 475–476 indirect, 475–476, 508–511 pointers to, 501–503 BeginTrans() function, 983–984 binding controls to columns, 1123–1127 data sources, 1115–1120 BindingNavigator control, 1120–1123 BindingSource component, 1115–1120 bitwise operators & (ampersand), AND, 82–83 ^ (caret), exclusive OR, 85 (right angle bracket), OR, 84–85 >> (right angle brackets), shift right, 86–87 ~ (tilde), NOT, 86 description, 81 inclusive OR, 84–85 black-and-white drawing, 747 block scope, 88 body, function, 234–235 bool data type, 57 BOOLEAN data type, 618 Boolean variables, 57 borders, windows, 615 bound mode, 1093, 1114–1115 bounding rectangles, 739–741 boxing data types, 101
branching, unconditional, 132 breakpoints, 570–572 Browser style toolbar option, 659 brushes, 719–721 bugs. See also debugging. common examples, 567–568 definition, 565 semantic errors, 567 syntactic errors, 567 Button control, 1044–1046 buttons cells, 1095 in cells, 1095 clicks, handling, 1076–1079, 1083–1086 definition, 819 illustration, 819 labels, changing, 992–993 movement, detecting, 725 by prefix, 619–620 BYTE data type, 618
C c prefix, 619–620 C++ programs. See also C++/CLI programs; program structure. basic development options, 3–4 managed C++, 3 native C++, 2, 3 simple example, 39–44 standards, 5–6 unmanaged C++, 3 C++/CLI programs. See also specific topics. definition, 5–6 overview, 150–156 calculations. See arithmetic operations. calculator example analyzing a number, 299–302, 318–319 C++/CLI, 315–320 expressions, evaluating, 295–298, 316–317 extending the program, 304–305 project description, 291–294 returning values from terms, 298–299, 318 running the program, 307–308 source code, 302–303 strings extracting substrings, 305–307, 319–320 removing blanks, 294–295, 316
1143
Index
calculator example
call stack, debugging call stack, debugging, 585–587 calling functions counting calls, 260 process description, 235–239 recursively, 262–265 Cancel button, visibility, 993–994 canceling database update, 980–982, 982–984, 997–998 CancelUpdate() function, 980–982 CArchive class, serialization, 870–871 caret (^), exclusive OR, 85 CArray template class, 761–763 case labels, 130 casting types in assignment statements, 79–80 C++/CLI, 108–109 definition, 78 explicit casts, 80–81 old-style casts, 81 rules for, 78–79 safe_cast operation, 108–109 variables in assignment statements, 79–80 definition, 78 explicit casts, 80–81 old-style casts, 81 rules for, 78–79 catch blocks, 281–282 catching exceptions C++/CLI, 308–309 example, 280–281 CBox class analyzing objects, 441–445 class implementation, 444 combining objects, 439–441 comparing objects, 438–439 defining the constructor, 447–448 data members, 446–447 function members, 448–453 global functions, 453–455 source code, 437–438 using, 455–458 CCircle class, 744–746 CCurve class defining, 775–777 drawing curves, 746 exercising, 778–779 implementing, 777––778
1144
CDatabase class, 930–931, 983–984 CDBException class, 930–931 C D C class, 712–720 CEditView class, 660 CElement class, 736–737 cells, database tables alignment, 1100 background color, 1099–1100 buttons, 1095 CellStyle property, 1109 ColumnIndex property, 1109 default styles, 1101–1108 DesiredType property, 1109 dynamic styles, 1108–1114 fonts, 1099–1100 foreground color, 1099–1100 formatting, 1100 FormattingApplied property, 1109 header, customizing, 1101 highlighting on mouseover, 1110–1114 images, 1096 non-header, customizing, 1101–1108 padding, 1100 properties, 1109 RowIndex property, 1109 selection color, 1099–1100 Value property, 1109 wrapping text, 1100 CellStyle property, 1109 CFieldExchange class, 930–931 CFormView class, 660 CFrameWnd class, 642 CHAR data type, 618 character arrays, 166–169 character data type, 55–56 check boxes, in cells, 1095 child windows, 615 CHtmlEditView class, 660 CHtmlView class, 660 circles, drawing Arc() function, 715–717 CCircle class, 744–746 Ellipse() function, 715–717 with the mouse, 722–723, 744–746 class constructors adding to a class, 343–345 copy, 356–358 copy constructors, 356–358, 405–407, 490–495 default, 345–347 default parameter values, assigning, 347–349
defining, example, 447–448 definition, 343 derived classes, 482–486 initialization lists, 350 no-arg, 345–347 reference class, 549–551 class destructors calling the wrong one, 511–516 default, 400 definition, 399–400 dynamic memory allocation, 402–405 example, 400–402 virtual, 511–516 class interface, 436 class libraries, creating, 532–535 class objects. See also class constructors; class destructors. arrays of, 363–364 declaring, 336–337 definition, 335 pointers to, 368–371 protecting, 360–361 references to, 371–372 class templates creating objects from, 431–433 defining, 428–431 definition, 427 instantiating, 427–428 with multiple parameters, 434–436 template member functions, 430–431 Class View, 10, 17 classes. See also CBox class; class constructors; class destructors; collection classes; inheritance. :: (colons), scope resolution operator, 341–342 abstract, 505–508 access control, 336, 479–482, 489–490 application, 653 base accessing private members, 480–482 definition, 475–476 deriving classes from, 476–479 direct, 475–476 indirect, 475–476, 508–511 pointers to, 501–503 CArray template, 761–763 CBox analyzing objects, 441–445 class implementation, 444
combining objects, 439–441 comparing objects, 438–439 defining the constructor, 447–448 data members, 446–447 function members, 448–453 global functions, 453–455 source code, 437–438 using, 455–458 CCircle, 744–746 CCurve defining, 775–777 drawing curves, 746 exercising, 778–779 implementing, 777––778 CDatabase, 930–931, 983–984 CDBException, 930–931 CDC, 712–720 CEditView, 660 CElement, 736–737 CFieldExchange, 930–931 CFormView, 660 CFrameWnd, 642 CHtmlEditView, 660 CHtmlView, 660 CLine, 737–741 CList template, 774–775. See also curves, drawing. arguments, 773–774 CCurve class, 775–779 description, 763–768 CListView, 660 CMap template, 768–771 CMyApp, 653–654 CMyDoc, 653–654 CMyView, 653–654 CMyWnd, 653–654 copying, 356–358 CPrintInfo, 886 CRecordset, 930–931 CRecordView, 930–931 CRectangle, 742–743 CRichEditView, 660 CScrollView, 660 CString, 858–859 CText, 861–862 CTreeView, 660 CTypedPtrList, 771 CView, 660
1145
Index
classes
classes (continued) classes (continued) CWinApp, 641–642 data members accessing, 337–339 definition, 335–336 private, 350–353 static, 365–367 Debug, 602–611 defining, 336 definition, 335 derived. See also inheritance. from base classes, 476–479 constructors, 482–486 copy constructors, 490–495 creating, 476–479 definition, 475 pointers to, 501–503 reference classes, C++/CLI, 524–526 value classes, C++/CLI, 520–526 document, 653 encapsulation, 335 fields, 336 frame window, 653 friend, 495–496 friend functions, 354–356 generic collection classes, 555–561 defining, 551–552 Dictionary, generic dictionary, 558 interface classes, 554–555 LinkedList, generic doubly linked list, 557 List, generic list, 556–557 using, 552–561 history of, 334 incomplete definitions, 504 inline functions, 342–343 instances counting, 366–367 definition, 335 instantiation, 335 interface, 526–531 member functions adding to a class, 339–341 defined outside the class, 362–363 definition, 335–336 positioning, 341–342 protecting, 361–362 static, 367–368
1146
members, 335–336 nesting, 516–519 OOP (object-oriented programming), 335 operations, 334–335 overview, 332–334 private members, 350–353 properties default indexed, 388 definition, 381 indexed, 381, 388–393 named indexed, 388 read-only, 381 reserved names, 394 scalar, 381, 382–388 static, 393–394 trivial scalar, 384–388 write-only, 381 protected class members, 486–489 serialization, 874 System::Data::DataColumn, 1090 System::Data::DataRow, 1090 System::Data::DataSet, 1090 System::Data::DataTable, 1090 this pointer, 358–360 Trace, 602–611 unions, 410 view, 653, 711–712, 954–957 virtual destructors, 511–516 virtual functions definition, 499 description, 497–501 pure, 505 references with, 503–504 classes, C++/CLI class properties default indexed, 388 definition, 381 indexed, 381, 388–393 named indexed, 388 read-only, 381 reserved names, 394 scalar, 381, 382–388 static, 393–394 trivial scalar, 384–388 write-only, 381 initonly fields, 394–395 literal fields, 377–378. See also initonly fields. operator overloading -- (minus signs), decrement operator, 467 ++ (plus signs), increment operator, 467
in reference classes, 467–470 in value classes, 461–466 reference class types, defining, 378–381 static constructors, 396 ToString() function, 376–377 value classes defining, 373–378 deriving, 520–526 overloading, 461–466 Clear() function, 1094 CLI (Common Language Infrastructure), 2 client area definition, 615 drawing, 634–636 redrawing, 731–732 client coordinates, 789–792 CLine class, 737–741 CList template class, 763–768. See also curves, drawing. arguments, 773–774 CCurve class defining, 775–777 exercising, 778–779 implementing, 777––778 drawing curves, 774–775 CListView class, 660 CLR (Common Language Runtime). See also C++/CLI programs. console applications description, 6 sample project, 24–27 description, 2–3 CMap template class, 768–771 CMyApp class, 653–654 CMyDoc class, 653–654 CMyView class, 653–654 C M y W n d class, 653–654 CObject-based classes, serialization, 872 collection classes. See also classes. arrays CArray template class, 761–763 collections of objects, 761–763 definition, 760 collections of objects arrays, 761–763 CArray template class, 761–763 CList template class, 763–768 CMap template class, 768–771 helper functions, 761–763 lists, 763–768
definition, 759–760 generic, 555–561 lists AddHead() function, 764–766 adding elements, 764–766 AddTail() function, 764–766 CList template class, 763–768 CompareElements() function, 767 ConstructElements() function, 768 counting elements, 773 definition, 760 deleting elements, 767–768 DestructElements() function, 768 empty, verifying, 773 Find() function, 766–767 GetHeadPosition() function, 766 GetTailPosition() function, 766 helper functions, 768 InsertAfter() function, 765–766 InsertBefore() function, 765–766 iterating through, 766 pointers to elements, 772–773 RemoveHead() function, 767–768 RemoveTail() function, 767–768 removing elements, 772–773 searching, 766–767 searching for pointers, 773 maps CMap template class, 768–771 definition, 760 hashing addresses, 768–769 HashKey() function, 770–771 helper functions, 770 LookUp() function, 769 retrieving objects from, 769 storing objects in, 769 shapes, 760 typed pointers AddHead() function, 772 AddTail() function, 772 CTypedPtrList class, 771 CTypedPtrList operators, 771–773 Find() function, 773 FindIndex() function, 773 GetAt() function, 772 GetCount() function, 773 GetHead() function, 772 GetHeadPos() function, 773 GetNext() function, 772 GetPrev() function, 772
1147
Index
collection classes
collection classes (continued) collection classes (continued) typed pointers GetTail() function, 772 GetTailPos() function, 773 InsertAfter() function, 773 InsertBefore() function, 773 IsEmpty() function, 773 RemoveAll() function, 772 RemoveAt() function, 773 RemoveHead() function, 772 RemoveTail() function, 772 SetAt() function, 773 types of collection, 760 type-safe handling, 760–761 collections of objects arrays, 761–763 CArray template class, 761–763 CList template class, 763–768 CMap template class, 768–771 helper functions, 761–763 lists, 763–768 colons (::), scope resolution operator classes, 341–342 definition, 26 example, 93–94 color BackColor property, 1099–1100 background, cells, 1099–1100 drawing in, 717–721 ForeColor property, 1099–1100 foreground, cells, 1099–1100 pen, 747–748 selected cells, 1099–1100 SelectionBackColor property, 1099–1100 SelectionForeColor property, 1099–1100 column types, 1095–1099 ColumnIndex property, 1109 columns, database tables adding, 1096 binding to controls, 1123–1127 buttons in cells, 1095 check boxes, 1095 defining, 1093–1099 drop-down lists, 1096 editing, 1096–1098 images in cells, 1096 links, displaying, 1096 width, setting, 1098–1099 combo boxes, 819, 1068–1070, 1072 ComboBox control, 1068–1070, 1072
1148
comma (,), expression separator, 76–77 command line output, 63–64, 104 command line pointer, 622 COMMAND messages, 689 command messages, 682–683 command update handler, 697–699 comments, 44–45 CommitTrans() function, 983–984 common controls, 819 Common Language Infrastructure (CLI), 2 Common Language Runtime (CLR). See CLR (Common Language Runtime). Common Type System (CTS), 3 CompareElements() function, 767 comparing values. See also loops. && (ampersands), logical AND, 125 ! (exclamation mark), logical NOT, 126 || (vertical bars), logical OR, 125–126 case labels, 130 C++/CLI, 150–156 conditional operator, 127–129 if statement description, 117–118 extended, 120–122 nesting, 118–120 if-else statement, nesting, 122–124 logical operators, 124–127 loops for, 133–139 continue statement, 139–140 definition, 132–133 do-while, 146–147 for each, 153–156 floating-point counters, 143 infinite, 137–139 multiple counters, 136–137 nesting, 147–150 non-integer counters, 140–143 while, 143–145 member access operators, 153 relational operators, 115–116 switch statement, 129–131 unconditional branching, 132 compiler, IDE, 9 compound statements, 49–50 conditional operator, 127–129 configurations, IDE, 19
console applications automatic generation, 50–51 CLR description, 6 sample projects, 24–27, 101–104 description, 6 sample project, 21–23 Win32 description, 6 sample project, 13–21 const modifier description, 70–71 function parameters, 249–250 member functions, 361–362 member functions defined outside the class, 362–363 objects, 360–361 constant pointers, 183–185 constants. See initonly fields; literal fields. constants, pointers to, 183–185 ConstructElements() function, 768 constructors. See class constructors. context menus associating with classes, 795–796 checking items, 800–802 choosing, 797–802 creating, 794–795 deleting elements, 807–808 drawing highlighted elements, 806–807 highlighting elements, 802–806 identifying selected elements, 798–800 masked elements, 814–815 moving elements, 808–814 positioning elements, 813–814 servicing menu messages, 807–814 Windows Forms creating, 1049 responding to, 1079–1086 WM_MOUSEMOVE handler, 810–811 ContextMenuStrip control, 1049 Context-sensitive help option, 659 continue statement, 139–140 ContinueRouting() method, 698 control menu, 616 control notification messages, 681 ControlBox property, 1068 controls. See also dialog boxes. adding to dialog boxes, 820–822 appearance, 1102–1103
buttons in cells, 1095 clicks, handling, 1076–1079, 1083–1086 definition, 819 illustration, 819 labels, changing, 992–993 movement, detecting, 725 categories of, 819 column format, 1106–1108 column headers, 1105–1106 combo boxes, 819 common, 819 database appearance, 1102–1103 binding to columns, 1123–1127 binding to data sources, 1115–1120 column format, 1106–1108 column headers, 1105–1106 setting up, 1103–1104 database update button label, changing, 992–993 Cancel button, visibility, 993–994 canceling the update, 997–998 description, 990–991 edit controls, enabling/disabling, 991–992 expediting the update, 996–997 Record menu, disabling, 994–996 edit boxes creating, 856–857 creating text elements, 863–865 creating the dialog classes, 858–859 CString class, 858–859 CText class, 861–862 definition, 819 drawing CText objects, 862 illustration, 819 moving CText objects, 862 text elements, defining, 860–862 Text menu item, 859–860 group boxes, 821–822 horizontal guides, 821 illustration, 819 linking to recordsets, 946–948 list boxes creating, 853–855 creating the dialog class, 854–855 definition, 819 displaying, 855 illustration, 819 scaling, 852–853
1149
Index
controls
controls (continued) controls (continued) positioning, 822 scrollbars, 819 setting up, 1103–1104 spin buttons creating, 835–837 dialog data exchange, 840 displaying, 841–842 initializing the dialog, 840–841 scale dialog class, 838–841 scale menu item, 835 scale toolbar button, 835 scaling, 835 validation, 840 static, 819 tab sequence, 838 testing, 822 cooperative mulltitasking, 629–630 coordinate systems client coordinates, 789–792, 843 device coordinates, 843 drawing, 708 logical coordinates, 789–790 page coordinates, 843 screen coordinates, 843 copy class constructors, 356–358 copy constructors, 405–407, 490–495 copying classes, 356–358 rows, 1094 CPrintInfo class, 886 CreateElement() function, 751–753 CRecordset class, 930–931 CRecordset operations, 980–982 CRecordView class, 930–931 CRectangle class, 742–743 CRichEditView class, 660 _CRTDBG... control bits, 595–596 _crtDbgFlag flag, 595 crtdbg.h header, 594–595 CrtSetReportFile() function, 596–597 CrtSetReportMode() function, 596–597 CScrollView class, 660 CString class, 858–859 CText class, 861–862 CTreeView class, 660 Ctrl key detection, 728 CTS (Common Type System), 3
1150
CTypedPtrList class, 771 CTypedPtrList operators, 771–773 curly braces ({ }), function syntax, 46 current position, 713 CurrentPosition() function, 1121 cursor position, recording, 729–731 curves, drawing CCurve class defining, 775–777 drawing curves, 746 exercising, 778–779 implementing, 777––778 CList template class, 774–775 example, 723–724 CView class, 660 CWinApp class, 641–642
D dash-dot lines, 718 dashed lines, 718 data, displaying. See DataGridView control. data members accessing, 337–339 defining, example, 446–447 definition, 335–336 private, 350–353 static, 365–367 data sources. See databases. data types. See also variables. fundamental. See also Boolean variables. bool, 57 Boolean variables, 57 boxing, 101 C++/CLI, 99–104, 109–111 char, 55–56 character, 55–56 const modifier, 70–71 double, 58 enumeration constants, 62, 109–111 float, 58 floating-point, 57–58 int, 54 integer type modifiers, 56–57 integer variables, 54–55 literals, 59 long, 55
long double, 58 minimum/maximum values, 56–57 short, 54 signed modifier, 56–57 summary of, 58–59 synonyms for, 60 true/false, 57 typedef keyword, 60 unboxing, 101 wchar_t, 56 wide character, 56 Windows programs BOOLEAN, 618 BYTE, 618 CHAR, 618 CTS (Common Type System), 3 DWORD, 618 HANDLE, 618 HBRUSH, 618 HCURSOR, 618 HDC, 618 HINSTANCE, 618 LPARAM, 619 LPCSTR, 619 LPHANDLE, 619 LRESULT, 619 overview, 332–334 WORD, 619 database applications, creating dynaset recordsets, 935–936 generating an MFC ODBC program, 933–936 program structure database/recordset data transfer, 940–941 DDX_FieldText() function, 946–948 DoFieldExchange() function, 940–941 linking controls to recordsets, 946–948 querying the database, 938–940 record view, 941–943 recordsets, 937–941 RFX_() function, 941 view dialog, creating, 943–946 registering an ODBC database, 931–933 snapshot recordsets, 935–936 database applications, Windows Forms accessing data, 1090–1091 AddNew() function, 1121 BindingNavigator control, 1120–1123 BindingSource component, 1115–1120 bound mode, 1114–1115
cells alignment, 1100 background color, 1099–1100 buttons, 1095 CellStyle property, 1109 ColumnIndex property, 1109 default styles, 1101–1108 DesiredType property, 1109 dynamic styles, 1108–1114 fonts, 1099–1100 foreground color, 1099–1100 formatting, 1100 FormattingApplied property, 1109 header, customizing, 1101 highlighting on mouseover, 1110–1114 images, 1096 non-header, customizing, 1101–1108 padding, 1100 properties, 1109 RowIndex property, 1109 selection color, 1099–1100 Value property, 1109 wrapping text, 1100 columns adding, 1096 binding to controls, 1123–1127 buttons in cells, 1095 check boxes, 1095 defining, 1093–1099 drop-down lists, 1096 editing, 1096–1098 images in cells, 1096 links, displaying, 1096 width, setting, 1098–1099 controls appearance, 1102–1103 binding to columns, 1123–1127 binding to data sources, 1115–1120 column format, 1106–1108 column headers, 1105–1106 setting up, 1103–1104 CurrentPosition() function, 1121 data source classes, 1090 DataGridView control Add() function, 1094 AddCopy() function, 1094 bound mode, 1093 Clear() function, 1094 column types, 1095–1099
1151
Index
database applications, Windows Forms
database applications, Windows Forms (continued) database applications, Windows Forms (continued) DataGridView control DataGridViewButtonColumn column, 1095 DataGridViewCheckBoxColumn column, 1095 DataGridViewComboBoxColumn column, 1096 DataGridViewImageColumn column, 1096 DataGridViewLinkColumn column, 1096 definition, 1090 displaying data, 1091–1093 Insert() function, 1094 InsertCopy() function, 1094 modes, 1092–1099 Remove() function, 1094 RemoveAt() function, 1094 unbound mode, 1093–1099 virtual mode, 1093 DataGridView control, customizing Alignment property, 1100 databases. See also DataGridView control. customer details dialog resource, 968 filter parameters, 972–973 filters, 970–972 linking dialogs, 973–975 recordset, 967 view class, 968–970 fields, 922 keys, 923 MFC support for CDatabase class, 930–931 CDBException class, 930–931 CFieldExchange class, 930–931 classes, 930–931 CRecordset class, 930–931 CRecordView class, 930–931 ODBC approach, 929–930 OLE DB approach, 929–930 m_strSort() function, 948 overview, 922–924 primary keys, 923 RDBMS (relational database management systems), 923 records, 922 recordsets description, 937–941 dynaset, 935–936 snapshot, 935–936 sorting, 948–950
1152
recordsets, second object customizing, 957–961 dialog resources, creating, 954–955 filter parameters, defining, 958–960 filters, adding, 958 initializing record view, 960–961 m_strFilter() function, 958 multiple table views, 961–966 OnActiveView() function, 965–966 recordset class, adding, 950–954 switching views, 961–965 view activation, 965–966 view class, adding, 954–957 viewing product orders, 966–967 relational, 921 SQL choosing records, 925–926 joining tables, 926–928 retrieving data, 924–926 sorting records, 929 tables, 922 window caption, modifying, 949–950 databases, updating adding records, 980–982 adding rows to tables adding orders, 1023–1028 dialog switching, 1010–1014 order data, storing, 1019–1021 order entry process, 1000–1001 order IDs, creating, 1014–1019 overview, 999–1000 recordsets, creating, 1002 recordsets views, creating, 1002–1006 resources, adding controls, 1006–1010 resources, creating, 1001 selecting products, 1021–1023 setting dates, 1020–1021 AddNew() function, 980–982 BeginTrans() function, 983–984 canceling updates, 980–982, 997–998 CancelUpdate() function, 980–982 CDatabase class, 983–984 CommitTrans() function, 983–984 completing an update, 980–982 controls button label, changing, 992–993 Cancel button, visibility, 993–994 canceling the update, 997–998
description, 990–991 edit controls, enabling/disabling, 991–992 expediting the update, 996–997 Record menu, disabling, 994–996 CRecordset operations, 980–982 Delete() function, 980–982 deleting records, 980–982 Edit() function, 980–982 editing records, 980–982 example, 984–988 inhibiting update, 988–990 optimistic record locking, 982 pessimistic record locking, 982 record locking, 982 Rollback() function, 983–984 rolling back an update, 982–984 starting an update, 988–990 tables, adding rows to adding orders, 1023–1028 dialog switching, 1010–1014 order data, storing, 1019–1021 order entry process, 1000–1001 order IDs, creating, 1014–1019 overview, 999–1000 recordsets, creating, 1002 recordsets views, creating, 1002–1006 resources, adding controls, 1006–1010 resources, creating, 1001 selecting products, 1021–1023 setting dates, 1020–1021 transactions, 982–984 Update() function, 980–982 update mode button label, changing, 992–993 Cancel button, visibility, 993–994 canceling the update, 997–998 description, 990–991 edit controls, enabling/disabling, 991–992 expediting the update, 996–997 Record menu, disabling, 994–996 validating operations, 981 DataGridView control Add() function, 1094 AddCopy() function, 1094 bound mode, 1093 Clear() function, 1094 column types, 1095–1099
customizing Alignment property, 1100 AlternatingRowsDefaultCellStyle property, 1101 BackColor property, 1099–1100 DataGridViewCellStyle object, 1099–1100 DefaultCellStyle property, 1101 Font property, 1099–1100 ForeColor property, 1099–1100 Format property, 1100 InheritedStyle property, 1100–1101 Padding property, 1100 RowsDefaultCellStyle property, 1101 SelectionBackColor property, 1099–1100 SelectionForeColor property, 1099–1100 Style property, 1101 System::Collections::Ilist interface, 1114 System::ComponentModel::BindingList interface, 1114 System::ComponentModel::BindingListView interface, 1114 System::ComponentModel::IlistSource interface, 1114 WrapMode property, 1100 DataGridViewButtonColumn column, 1095 DataGridViewCheckBoxColumn column, 1095 DataGridViewComboBoxColumn column, 1096 DataGridViewImageColumn column, 1096 DataGridViewLinkColumn column, 1096 definition, 1091 displaying data, 1091–1093 Insert() function, 1094 InsertCopy() function, 1094 modes, 1092–1099 Remove() function, 1094 RemoveAt() function, 1094 unbound mode, 1093–1099 virtual mode, 1093 DataGridViewButtonColumn column, 1095 DataGridViewCellStyle object, 1099–1100 DataGridViewCheckBoxColumn column, 1095 DataGridViewComboBoxColumn column, 1096 DataGridViewImageColumn column, 1096 DataGridViewLinkColumn column, 1096 DDX_FieldText() function, 946–948 Debug class, 602–611 Debug configuration, 570
1153
Index
Debug configuration
debugger debugger definition, 568 starting, 570, 573–576 windows, 575 debugging. See also bugs. adding code for, 578–585 assert() function, 578–580 assertions, 578–580 basic operations, 568–570 breakpoints, 570–572 call stack, 585–587 C++/CLI Assert() function, 607–608 assertions, 607–608 controlling output, 605–607 Debug class, 602–611 generating output, 603–604 Indent() function, 604–605 indenting output, 604–605 listeners, 604 output destination, 604 Trace class, 602–611 trace switches, 605–607 Unindent() function, 604–605 Write() function, 603–604 WriteIf() function, 603–604 WriteLine() function, 603–604 WriteLineIf() function, 603–604 changing variables, 577–578 _CRTDBG... control bits, 595–596 _crtDbgFlag flag, 595 crtdbg.h header, 594–595 CrtSetReportFile() function, 596–597 CrtSetReportMode() function, 596–597 definition, 565 description, 565–566 dynamic memory, 593–601 finding the next bug, 593 free store operations, 594–601 in IDE, 19–23 #ifdef/#endif directives, 580–581 inspecting variables, 576–577 memory leaks, 594–601 NDEBUG symbol, 578–579 null pointers, 576 setting a watch, 576 stepping through code, 587–590 testing the extended class, 591–593 tracepoints, 572–573 DECLARE_DYNAMIC() macro, 872
1154
DECLARE_DYNCREATE() macro, 869, 872 DECLARE_SERIAL() macro, 872 declaring pointers, 173–174 variables, 52–53, 91 _declspec keyword, 916–917 decoding windows messages, 633–636 decorated names, 912 decrementing variables, 74–76 default indexed properties, 388 DefaultCellStyle property, 1101 definition, 759–760 delegates calling, 540–541 creating, 537–541 declaring, 537 definition, 536 unbound, 541–545 Delete() function, 980–982 delete operator, 193 deleting context menu elements, 807–808 database records, 980–982 list elements, 767–768 rows, 1094 shapes from documents, 793–794 de-referencing pointers, 174 derived classes from base classes, 476–479 class constructors, 482–486 constructors, 482–486 copy constructors, 490–495 creating, 476–479 definition, 475 pointers to, 501–503 reference classes, C++/CLI, 524–526 value classes, C++/CLI, 520–526 DesiredType property, 1109 DestructElements() function, 768 device context, 634–636, 709, 893 Dialog based option, 657–658 dialog boxes adding, 820–822 adding a class, 823–824 closing, 827 controls adding, 820–822 enabling, 831 initializing, 828–830
radio button messages, 830–831 creating elements, 833–834 description, 817–818 displaying, 824–827 enabling, 831 illustration, 818 initializing, 828–830 linking, 973–975 modal, 824 modeless, 824 pen widths, 832–833 radio button messages, 830–831 scale factor document size, 844 mapping mode, 844–846 scaleable mapping modes, 842–844 scrolling, 846–848 scrollbars, 847–848 status bars adding to frames, 848–850 overview, 848 parts of, 850–851 updating, 851––852 testing, 822, 834–835 Windows Forms adding, 1068–1075 button clicks, handling, 1076–1079, 1083–1086 ComboBox control, 1068–1070, 1072 context menu, responding to, 1079–1086 ControlBox property, 1068 creating, 1056–1062 DialogResult property, 1057, 1063–1066 event handler, Reset menu, 1067–1068 FormBorderStyle property, 1068 getting data from, 1070–1073 Help > About menu, 1075–1076 input controls, disabling, 1073–1074 Limits menu, 1074–1075 MaximizeBox property, 1068 MinimizeBox property, 1068 NumericUpDown control, 1068–1070, 1073 Show() function, 1062–1066 ShowDialog() function, 1062–1063 Text property, 1068 using, 1062–1068 validating input, 1063–1066 dialog button events, 1058–1060 dialog objects, creating, 1061–1062
DialogResult property, 1057, 1063–1066 Dictionary, generic dictionary, 558 direct base classes, 475–476 display content, 634–636 displaying data. See DataGridView control. displaying graphics, 713–717 dllexport attribute, 916–917 DllMain() function, 906, 910–911 DLLs (dynamic link libraries) AFX_EXT_CLASS keyword, 912–913, 916 contents choosing, 907–908 description, 906 _declspec keyword, 916–917 decorated names, 912 dllexport attribute, 916–917 DllMain() function, 906 early binding, 904–906 exporting symbols, 917–920 variables and functions, 916–917 functional description, 903–906 importing symbols, 917 interface, 906, 913 late binding, 904–906 load-time dynamic linking, 904–906 MFC extension, 906–907 ordinals, 912 overview, 901–903 regular, dynamically linked, 907 regular, statically linked, 907 run-time dynamic linking, 904–906 varieties, 906–907 writing extension DLLs adding classes, 911–912 building DLLs, 914 DllMain() function, 910–911 example, 914–915 exporting classes, 912–913 overview, 908–910 required files, 915–916 docking toolbars, 12 document class, 653 document interfaces, MFC, 650 documentation, IDE, 12–13 documents. See also printing documents; serialization; views. context menus
1155
Index
documentation, IDE
documents associating with classes, 795–796 checking items, 800–802 choosing, 797–802 creating, 794–795 deleting elements, 807–808 drawing highlighted elements, 806–807 highlighting elements, 802–806 identifying selected elements, 798–800 masked elements, 814–815 moving elements, 808–814 positioning elements, 813–814 servicing menu messages, 807–814 WM_MOUSEMOVE handler, 810–811 creating adding elements, 783–784 CTypedPtrList template, 779–784 document destructor, 780–781 drawing the document, 781–783 OnDraw() function, 781–783 pointers to shape classes, 779–784 RectVisible() function, 783 definition, 650 deleting shapes, 793–794 linking to views, 652–653 moving shapes, 793–794 moving text, 882–883 pen widths, 832–833 recording changes, 874–876 size, getting, 889–890 size, scale factor, 844 template classes, 653 templates, 652–653 Document/View architecture support option, 657–658 DoFieldExchange() function, 940–941 dotted lines, 718 double data type, 58 double quotes (“...”), special character indicator, 65 do-while loops, 146–147 Draw() function, 738–739 drawing in windows alternating dash-dot lines, 718 Arc() function, 716–717 brushes, 719–721 CDC class, 712–720
1156
circles Arc() function, 715–717 CCircle class, 744–746 Ellipse() function, 715–717 with the mouse, 722–723, 744–746 in color, 717–721 coordinate system, 708 current position, 713 curves CCurve class, 746, 775––778, 778–779 CList template class, 774–775 example, 723–724 dashed lines, 718 device context, 709 displaying graphics, 713–717 dotted lines, 718 GDI (Graphical Device Interface), 709–711 hatching, 719–720 HS_BDIAGONAL hatching, 720 HS_CROSS hatching, 720 HS_DIAGCROSS hatching, 720 HS_FDIAGONAL hatching, 720 HS_HORIZONTAL hatching, 720 HS_VERTICAL hatching, 720 inside a frame, 718 lines alternating dash-dot, 718 CLine class, 737–741 dashed, 718 dotted, 718 LineTo() function, 714–715 with the mouse, 737–741 solid, 718 straight, 714–715 LineTo() function, 714–715 mapping modes, 709–711 MM_ANISOTROPIC mapping mode, 710–711 MM_HIENGLISH mapping mode, 709–711 MM_HIMETRIC mapping mode, 709–711 MM_ISOTROPIC mapping mode, 709–711 MM_LOENGLISH mapping mode, 709–711 MM_LOMETRIC mapping mode, 709–711 MM_TEXT mapping mode, 709–711 MM_TWIPS mapping mode, 710–711 mouse black-and-white, 747 bounding rectangles, 739–741 button movement, detection, 725
CCircle class, 744–746 CCurve class, 746 CElement class, 736–737 circles, 744–746 CLine class, 737–741 CreateElement() function, 751–753 creating elements, 751–753 CRectangle class, 742–743 Ctrl key detection, 728 cursor position, recording, 729–731 curves, 746 Draw() function, 738–739 drawing mode, 747–749 element classes, 732–736 Ellipse() function, 745–746 InvalidateRect() function, 731–732 left button detection, 725, 728 lines, 737–741 message handlers, 727–729, 747–753 messages, capturing, 755–756 messages, types of, 725–727 middle button detection, 728 MK_CONTROL flag, 728–729 MK_LBUTTON flag, 728–729 MK_MBUTTON flag, 728–729 MK_RBUTTON flag, 728–729 MK_SHIFT flag, 728–729 movement, handling, 749–751 normalized rectangles, 741 OnMouseMove() handler, 749–751 pen color, 747–748 R2_BLACK mode, 747–748 R2_COPYPEN mode, 747–748 R2_MASKNOTOPEN mode, 748 R2_MASKPEN mode, 748 R2_MASKPENNOT mode, 747–748 R2_MERGENOTOPEN mode, 747–748 R2_MERGEPEN mode, 748 R2_MERGEPENNOT mode, 747–748 R2_NOP mode, 747–748 R2_NOT mode, 747–748 R2_NOTCOPYPEN mode, 747–748 R2_NOTMASKPEN mode, 748 R2_NOTMERGEPEN mode, 748 R2_NOTXORPEN mode, 748 R2_WHITE mode, 747–748 R2_XORPEN mode, 748 Rectangle() function, 743
rectangles, 739–741, 742–743 redrawing the client area, 731–732 ReleaseCapture() function, 755–756 right button detection, 728 rubberbanding, 747, 750 SetCapture() function, 755–756 SetROP2() function, 747–750 Shift key detection, 728 temporary element storage, 734–736 update region, 731 WM_LBUTTONDOWN message, 725–726 WM_LBUTTONUP message, 725, 727, 753 WM_MOUSEMOVE message, 725, 726–727 OnDraw() function, 711–712 pen objects, 717–719 positioning the drawing, 708 PS_DASH pen style, 718 PS_DASHDOT pen style, 718 PS_DASHDOTDOT pen style, 718 PS_DOT pen style, 718 PS_INSIDEFRAME pen style, 718 PS_NULL pen style, 718 PS_SOLID pen style, 718 rectangles, 722, 724 rectangles, with the mouse bounding rectangles, 739–741 CRectangle class, 742–743 normalized rectangles, 741 Rectangle() function, 743 rectangles, 722, 724, 739–741, 742–743 solid lines, 718 view class, 711–712 window client area, 708 WM_PAINT message, 708, 711, 731, 754–755 drawing mode, 747–749 drop-down lists, in cells, 1096 d w prefix, 619–620 DWORD data type, 618 dynamic link libraries (DLLs). See DLLs. dynamic memory, debugging, 593–601 dynamic memory allocation. See also free store. allocating, 193 C++/CLI arrays of arrays, 213–216 CLR arrays, 200–205 freeing memory, 198–199 garbage collection, 198–199 handles, 199–200
1157
Index
dynamic memory allocation
dynamic memory allocation (continued) dynamic memory allocation (continued) C++/CLI jagged arrays, 213–216 multidimensional arrays, 209–213 searching one-dimensional arrays, 206–209 sorting one-dimensional arrays, 205–206 string handling, 216–225 tracking handles, 199–200 class destructors, 402–405 delete operator, 193 free store definition, 192–193 example, 194–196 freeing, 193 handling allocation errors, 284–285 multidimensional arrays, 196–197 new operator, 193, 284–285 one-dimensional arrays, 194–196 references. See also pointers; tracking references. declaring, 197–198 definition, 197 initializing, 197–198 dynamic_cast operator, 516 dynaset recordsets, 935–936
E early binding, 904–906 edit boxes creating, 856–857 CString class, 858–859 CText class, 861–862 definition, 819 dialog classes, creating, 858–859 drawing CText objects, 862 illustration, 819 moving CText objects, 862 text elements, creating, 863–865 text elements, defining, 860–862 Text menu item, 859–860 Edit() function, 980–982 editing columns, 1096–1098 database records, 980–982 editor, IDE, 9 Editor tab, 10 element classes, 732–736, 877–879
1158
elements, of arrays, 160 Ellipse() function, 745–746 Enable() method, 698 encapsulation, 335 EndsWith() function, 222–225 enumeration, 60–62 enumeration constants, 62, 109–111 equal sign (=), assignment operator, overloading, 418–422 equal signs (==), relational operator, 115–116 error handling, 23–24. See also exceptions. escape sequences, 65–67 event handlers dialog button, 1058–1060 menu items, 1049–1056 Reset menu, 1067–1068 event-driven applications, 7 Windows programs, 617 events creating, 545–546 definition, 536 handling, 547–548 Windows applications, 7 exceptions. See also error handling. catch blocks, 281–282 catching C++/CLI, 308–309 example, 280–281 C++/CLI, 308–309 definition, 279–280 in the MFC, 283 throwing C++/CLI, 308–309 description, 281 example, 280–281 try blocks, 281–283 exclamation mark, equal sign (!=), relational operator, 115–116 exclamation mark (!), logical NOT, 126 .exe file extension, 19 executing programs, IDE, 20–21 explicit casts, 80–81 exporting classes from extension DLLs, 912–913 symbols from DLLs, 917–920 variables and functions from DLLs, 916–917
expressions casting in assignment statements, 79–80 definition, 78 explicit casts, 80–81 old-style casts, 81 rules for, 78–79 evaluating, 295–298, 316–317 mixed type, casting, 80–81 separating, 76–77 extension DLLs adding classes, 911–912 building DLLs, 914 DllMain() function, 910–911 example, 914–915 exporting classes, 912–913 overview, 908–910 required files, 915–916
F fields classes, 336 databases, 922 file scope. See global scope. filter parameters, databases, 958–960, 972–973 filters, databases, 958, 970–972 finalizers, 549–551 Find() function, 766–767, 773 FindIndex() function, 773 FixedDialog property, 1056–1062 float data type, 58 floating-point data types, 57–58 floating-point loop counters, 143 fn prefix, 619–620 Font property, 1099–1100 fonts, cells, 1099–1100 for each loops, 153–156 for loops, 133–139 ForeColor property, 1099–1100 foreground color, cells, 1099–1100 Format property, 1100 formatting cells, 1100 formatting output, 64–65, 104–107 FormattingApplied property, 1109 FormBorderStyle property, 1056–1062, 1068 forms. See Windows Forms.
frame window class, 653 frame windows, 642 free store debugging, 594–601 definition, 192–193 example, 194–196 freeing memory, 193, 198–199. See also garbage collection. friend classes, 495–496 friend functions, in classes, 354–356 function members. See member functions. function pointers as arguments, 275–277 arrays of as arguments, 277 declaring, 272–273 definition, 271–272 example, 273–275 functions { } (curly braces), function syntax, 46 Add(), 1094 AddCopy(), 1094 AddHead(), 764–766, 772 AddNew(), 980–982, 1121 AddTail(), 764–766, 772 Arc(), 716–717 arguments arrays as, 243–247 arrays of function pointers as, 277 definition, 232 function pointers as, 275–277 passing to main(), 250–252, 267–268 passing-by-pointer, 241–243 passing-by-reference, 247–249 passing-by-value, 240–241 pointer notation, 244–245 variable number of, 252–254, 266–267 Assert(), 578–580, 607–608 BeginTrans(), 983–984 body, 46, 234–235 calling, 235–239 calling, recursively, 262–265 calls, counting, 260 CancelUpdate(), 980–982 C++/CLI, 265–268, 309–315 Clear(), 1094 CommitTrans(), 983–984 CompareElements(), 767 ConstructElements(), 768
1159
Index
functions
functions (continued) functions (continued) CreateElement(), 751–753 CrtSetReportFile(), 596–597 CrtSetReportMode(), 596–597 CurrentPosition(), 1121 DDX_FieldText(), 946–948 Delete(), 980–982 description, 38 DestructElements(), 768 DllMain(), 906, 910–911 DoFieldExchange(), 940–941 Draw(), 738–739 Edit(), 980–982 Ellipse(), 745–746 EndsWith(), 222–225 executable statements, 46 Find(), 766–767, 773 FindIndex(), 773 generic, 309–315 GetAt(), 772 GetCount(), 773 GetFromPage(), 887 GetHead(), 772 GetHeadPos(), 773 GetHeadPosition(), 766 GetMaxPage(), 887 GetMinPage(), 887 GetNext(), 772 GetPrev(), 772 GetTail(), 772 GetTailPos(), 773 GetTailPosition(), 766 GetToPage(), 887 global variables, 260 HashKey(), 770–771 header, 233–234 Indent(), 604–605 inline, in classes, 342–343 Insert(), 1094 InsertAfter(), 765–766, 773 InsertBefore(), 765–766, 773 InsertCopy(), 1094 InvalidateRect(), 731–732 IsEmpty(), 773 LineTo(), 714–715 LookUp(), 769 main(), 46, 250–252, 267–268 MoveFirst(), 1121 MoveLast(), 1121
1160
MoveNext(), 1121 MovePrevious(), 1121 m_strFilter(), 958 new, 536 OnActiveView(), 965–966 OnDraw(), 711–712 OnUpdate(), 785–787 overloading, 285–288 parameters description, 232 initializing, 277–279 protecting, 249–250 prototypes, 235–239 Rectangle(), 743 recursive, 262–265 RegisterClassEx(), 625–627 ReleaseCapture(), 755–756 Remove(), 1094 RemoveAll(), 772 RemoveAt(), 773, 1094 RemoveCurrent(), 1121 RemoveHead(), 767–768, 772 RemoveTail(), 767–768, 772 return statement, 235 returning values from addresses, 256–257 bad pointers, 255–256 pointers, 254–257 references, 258–260 terms, 298–299, 318 RFX_(), 941 Rollback(), 983–984 Serialize() definition, 870 serializing documents, 876–877 shape classes, 879–881 SetAt(), 773 SetCapture(), 755–756 SetMaxPage(), 887 SetMinPage(), 887 SetROP2(), 747–750 Show(), 1062–1066 ShowDialog(), 1062–1063 StartsWith(), 222–225 static variables, 261–262 structure of, 233–235 templates, 288–291 ToString(), 376–377 TotalNumberofItems(), 1121
trim(), 220–221 Unindent(), 604–605 Update(), 980–982 UpdateAllViews(), 785–787 uses for, 233 using, 235–239 WINAPI(), 622 WindowProc(), 632–637 WinMain() arguments, 622 example, 631–632 hInstance argument, 622 hPrevInstance argument, 622 lpCmdLine argument, 622 nCmdShow argument, 622 prototype, 621 RegisterClassEx() function, 625–627 WINAPI() function, 622 WNDCLASSEX struct, 623–625 Write(), 103–104, 603–604 WriteIf(), 603–604 WriteLine(), 103–104, 603–604 WriteLineIf(), 603–604 functions, example (calculator) analyzing a number, 299–302, 318–319 C++/CLI, 315–320 expressions, evaluating, 295–298, 316–317 extending the program, 304–305 project description, 291–294 returning values from terms, 298–299, 318 running the program, 307–308 source code, 302–303 strings extracting substrings, 305–307, 319–320 removing blanks, 294–295, 316 fundamental data types. See also Boolean variables; data types. bool, 57 Boolean variables, 57 boxing, 101 C++/CLI, 99–104, 109–111 char, 55–56 character, 55–56 const modifier, 70–71 double, 58 enumeration constants, 62, 109–111 float, 58 floating-point, 57–58 int, 54
integer type modifiers, 56–57 integer variables, 54–55 literals, 59 long, 55 long double, 58 minimum/maximum values, 56–57 short, 54 signed modifier, 56–57 summary of, 58–59 synonyms for, 60 true/false, 57 typedef keyword, 60 unboxing, 101 wchar_t, 56 wide character, 56
G garbage collection, 198–199 GDI (Graphical Device Interface), 709–711 generic classes collection classes, 555–561 defining, 551–552 Dictionary, generic dictionary, 558 interface classes, 554–555 LinkedList, generic doubly linked list, 557 List, generic list, 556–557 using, 552–561 generic functions, 309–315 GetAt() function, 772 GetCount() function, 773 GetFromPage() function, 887 GetHead() function, 772 GetHeadPos() function, 773 GetHeadPosition() function, 766 GetMaxPage() function, 887 GetMinPage() function, 887 GetNext() function, 772 GetPrev() function, 772 GetTail() function, 772 GetTailPos() function, 773 GetTailPosition() function, 766 GetToPage() function, 887 global functions, defining, 453–455 global namespace scope. See global scope. global scope, 91–94 global variables, 260
1161
Index
global variables
Graphical Device Interface (GDI) Graphical Device Interface (GDI), 709–711 Graphical User Interface (GUI). See GUI (Graphical User Interface). graphics, displaying, 713–717 greater than, equal sign (>=), relational operator, 115–116 greater than (>) operator overloading, 415–417 OR, 84–85 relational operator, 115–116 group boxes, 821–822, 1042–1044 GroupBox control, 1042–1044 grouping controls, 821–822, 1042–1044 GUI (Graphical User Interface), Windows Forms Button control, 1044–1046 context menus, 1049 ContextMenuStrip control, 1049 dialog boxes adding, 1068–1075 button clicks, handling, 1076–1079, 1083–1086 ComboBox control, 1068–1070, 1072 context menu, responding to, 1079–1086 ControlBox property, 1068 creating, 1056–1062 DialogResult property, 1057, 1063–1066 event handler, Reset menu, 1067–1068 FormBorderStyle property, 1068 getting data from, 1070–1073 Help > About menu, 1075–1076 input controls, disabling, 1073–1074 Limits menu, 1074–1075 MaximizeBox property, 1068 MinimizeBox property, 1068 NumericUpDown control, 1068–1070, 1073 Show() function, 1062–1066 ShowDialog() function, 1062–1063 Text property, 1068 using, 1062–1068 validating input, 1063–1066 dialog button events, 1058–1060 dialog objects, creating, 1061–1062 event handler, dialog button, 1058–1060 event handlers, menu items, 1049–1056 FixedDialog property, 1056–1062 FormBorderStyle property, 1056–1062 GroupBox control, 1042–1044 grouping controls, 1042–1044
1162
list boxes, 1058–1061 menu items, event handlers, 1049–1056 menus, 1037–1038 overview, 1035–1036 submenus, 1038–1040 tab controls, 1040–1042 TabControl control, 1040–1042 testing, 1048–1049 Web browser controls, 1047–1048 WebBrowser control, 1047–1048
H h prefix, 619–620 HANDLE data type, 618 handles, 199–200, 622 hashing addresses, 768–769 HashKey() function, 770–771 hatching, 719–720 HBRUSH data type, 618 HCURSOR data type, 618 HDC data type, 618 headers cell, customizing, 1101 functions, 233–234 programs, 45 Help > About menu, 1075–1076 helper functions collections of objects, 761–763 lists, 768 maps, 770 highlighting cells on mouseover, 1110–1114 hInstance argument, 622 HINSTANCE data type, 618 horizontal guides, in controls, 821 hPrevInstance argument, 622 HS_BDIAGONAL hatching, 720 HS_CROSS hatching, 720 HS_DIAGCROSS hatching, 720 HS_FDIAGONAL hatching, 720 HS_HORIZONTAL hatching, 720 HS_VERTICAL hatching, 720 Hungarian notation MFC (Microsoft Foundation Classes), 640 Windows programs, 620
I iprefix, 619–620 .idb file extension, 19 IDE (Integrated Development Environment) :: (colons), scope resolution operator, 26 assemblies, 25 Class View, 10, 17 compiler, 9 components, 9 configurations, 19 debugging, 19–23 documentation, 12–13 Editor, 10 editor, 9 error handling, 23–24 executing programs, 20–21 file extensions, 19 libraries, 9 linker, 9 namespaces, 26 options, setting, 26 Output window, 10 project folder, 13 projects current settings, displaying, 14 defining, 13–19, 21–23 definition, 13 naming, 14 type of, displaying, 14 viewing, 16–17 projects, samples CLR console application, 24–27 empty console application, 21–23 Win32 console application, 13–21 Property Manager, 10, 16 release versions, 19–23 Resource View, 10, 16 Solution Explorer, 10, 16 solutions creating, 18–19 definition, 13 source code, modifying, 17–18 Standard C++ Library, 9 toolbar options, 10–12 toolbars, docking, 12 user interface, 10
Windows applications, creating and executing MFC, 28–31 Windows Forms, 31–35 identifiers, variables, 51–52 i f statement description, 117–118 extended, 120–122 nesting, 118–120 #ifdef/#endif directives, 580–581 if-else statement, nesting, 122–124 .ilk file extension, 19 images, in cells, 1096 IMPLEMENT_SERIAL() macro, 872–873 importing symbols into DLLs, 917 #include directive, 45 inclusive OR, 84–85 incomplete class definitions, 504 incrementing variables, 74–76 Indent() function, 604–605 indexed properties, 381, 388–393 indexing arrays, 160–161 indirect base classes, 475–476, 508–511 infinite loops, 137–139 inheritance. See also classes. abstract classes, 505–508 access control, 479–482, 489–490 base classes accessing private members, 480–482 definition, 475–476 deriving classes from, 476–479 direct, 475–476 indirect, 475–476, 508–511 pointers to, 501–503 definition, 475 derived classes constructors, 482–486 copy constructors, 490–495 creating, 476–479 definition, 475 pointers to, 501–503 friend classes, 495–496 incomplete class definitions, 504 multiple levels of, 508–511 pointers to class objects, 501–503 polymorphism, 501 protected class members, 486–489
1163
Index
inheritance
inheritance (continued) inheritance (continued) virtual destructors, 511–516 virtual functions definition, 499 description, 497–501 pure, 505 references with, 503–504 inheritance, C++/CLI access specifiers, 531–532 class libraries, creating, 532–535 delegates calling, 540–541 creating, 537–541 declaring, 537 definition, 536 unbound, 541–545 derived reference classes, 524–526 derived value classes, 520–524 events creating, 545–546 definition, 536 handling, 547–548 finalizers, 549–551 generic classes collection classes, 555–561 defining, 551–552 Dictionary, generic dictionary, 558 interface classes, 554–555 LinkedList, generic doubly linked list, 557 List, generic list, 556–557 using, 552–561 interface classes, 526–531 new functions, 536 reference class destructors, 549–551 visibility specifiers, 531 InheritedStyle property, 1100–1101 Initial status bar option, 658 initializing multidimensional arrays, 170–172 one-dimensional arrays, 164–165 pointers, 176–179 references, 197–198 variables, 53–54 initonly fields, 394–395 inline functions, in classes, 342–343
1164
input/output operations >> (angle brackets), extraction operator, 62–63 “...” (double quotes), special character indicator, 65 C++/CLI, 104–108 command line output, 63–64, 104 escape sequences, 65–67 formatting output, 64–65, 104–107 keyboard input, 62–63, 107–108, 152–153 manipulators, 64–65 special characters, 65–67 streams, 48 Insert() function, 1094 InsertAfter() function, 765–766, 773 InsertBefore() function, 765–766, 773 InsertCopy() function, 1094 instance handles, 622 instances counting, 366–367 definition, 335 overview, 332–334 instantiation, 335 int data type, 54 integer type modifiers, 56–57 integer variables, 54–55 Integrated Development Environment (IDE). See IDE (Integrated Development Environment). interface, DLL, 906, 913 interface classes, 526–531, 554–555 interior pointers, 225–228 internal specifier, 531 InvalidateRect() function, 731–732 IsEmpty() function, 773
J jagged arrays, 213–216 joining strings, 217–219
K keyboard input, 62–63, 107–108 keys, databases, 923 keywords, C++ C++/CLI, 1132 ISO/ANSI, 1131–1132 reserved, 52
L lprefix, 619–620 late binding, 904–906 left angle brackets (>), shift right, 86–87 right button detection, 728 Rollback() function, 983–984
rolling back database update, 980–982, 982–984, 997–998 RowIndex property, 1109 rows, database tables adding to tables adding orders, 1023–1028 DataGridView control, 1094 dialog switching, 1010–1014 order data, storing, 1019–1021 order entry process, 1000–1001 order IDs, creating, 1014–1019 overview, 999–1000 recordsets, creating, 1002 recordsets views, creating, 1002–1006 resources, adding controls, 1006–1010 resources, creating, 1001 selecting products, 1021–1023 setting dates, 1020–1021 alternate, customizing, 1108 copying, 1094 deleting, 1094 RowsDefaultCellStyle property, 1101 rubberbanding, 747, 750 run-time dynamic linking, 904–906 Rvalues, 68
S s prefix, 619–620 safe_cast operation, 108–109 scalar properties, 381, 382–388 scale factor document size, 844 mapping mode, 844–846 scaleable mapping modes, 842–844 scrolling, 846–848 scaling list boxes, 852–853 spin buttons, 835 scope of variables block, 88 global, 91–94 local, 88 scrollbars definition, 819 illustration, 819 setting up, 847–848
scrolling scale factor, 846–848 views, 787–792 SDI (Single Document Interface). See also MFC (Microsoft Foundation Classes). creating applications base classes, 660 Browser style toolbar option, 659 CEditView class, 660 CFormView class, 660 CHtmlEditView class, 660 CHtmlView class, 660 CListView class, 660 Context-sensitive help option, 659 CRichEditView class, 660 CScrollView class, 660 CTreeView class, 660 CView class, 660 Dialog based option, 657–658 Document/View architecture support option, 657–658 Initial status bar option, 658 Maximize box option, 658 Maximized option, 658 Minimize box option, 658 Minimized option, 658 Multiple top-level documents option, 657–658 options, 657–660 Printing and print preview option, 659 Resource language option, 657–658 SDI (Single Document Interface), 657–660 Split window option, 658 Standard docking toolbar option, 659 Thick Frame option, 658 Use Unicode libraries option, 657–658 definition, 650 searching lists, 766–767 one-dimensional arrays, 206–209 pointers in lists, 773 strings, 222–225 selection color, cells, 1099–1100 SelectionBackColor property, 1099–1100 SelectionForeColor property, 1099–1100 semantic errors, 567 semicolon (;), end of statement indicator, 47
1173
Index
semicolon (;), end of statement indicator
serialization serialization applying to documents, 876–877 to element classes, 877–879 recording document changes, 874–876 to shape classes, 879–881 CArchive class, 870–871 for a class, 874 CObject-based classes, 872 DECLARE_DYNAMIC() macro, 872 DECLARE_DYNCREATE() macro, 869, 872 DECLARE_SERIAL() macro, 872 default constructor, 869 disk input/output capability, 870–871 in document class definition, 868–869 to documents, 876–877 IMPLEMENT_SERIAL() macro, 872–873 moving text, 882–883 object types, 871 primitive types, 871 process description, 873–874 Serialize() function definition, 870 serializing documents, 876–877 shape classes, 879–881 Serialize() function definition, 870 serializing documents, 876–877 shape classes, 879–881 SetAt() function, 773 SetCapture() function, 755–756 SetCheck() method, 698 SetMaxPage() function, 887 SetMinPage() function, 887 SetRadio() method, 698 SetROP2() function, 747–750 SetText() method, 698 shape classes, serialization, 879–881 shapes, collection classes, 760 shapes, drawing circles Arc() function, 715–717 CCircle class, 744–746 Ellipse() function, 715–717 with the mouse, 722–723, 744–746 curves CCurve class, 746, 775–779 CList template class, 774–775 example, 723–724
1174
lines alternating dash-dot, 718 CLine class, 737–741 dashed, 718 dotted, 718 LineTo() function, 714–715 with the mouse, 737–741 solid, 718 straight, 714–715 rectangles with the mouse, 722, 724, 739–743 RECT struct, 330 Shift key detection, 728 short data type, 54 Show() function, 1062–1066 ShowDialog() function, 1062–1063 signed modifier data type, 56–57 Single Document Interface (SDI). See SDI (Single Document Interface). sizeof operator, 181–183 slashes (//), comment indicator, 44 snapshot recordsets, 935–936 solid lines, 718 Solution Explorer, 10, 16 solutions creating, 18–19 definition, 13 sorting database records, 929 one-dimensional arrays, 205–206 recordsets, 948–950 source code automatic indenting, 22 compiler, 9 linker, 9 modifying, 17–18 naming program files, 460–461 organizing, 458–461 sources of data. See databases. special characters, input/output, 65–67 spin buttons creating, 835–837 dialog data exchange, 840 displaying, 841–842 initializing the dialog, 840–841 scale dialog class, 838–841 scale menu item, 835 scale toolbar button, 835 scaling, 835 validation, 840
Split window option, 658 SQL choosing records, 925–926 joining tables, 926–928 retrieving data, 924–926 sorting records, 929 stack space, 88 Standard C++ Library, 9 Standard docking toolbar option, 659 StartsWith() function, 222–225 statement blocks, 49–50 static constructors, 396 controls, 819 data members, 365–367 member functions, 367–368 properties, 393–394 storage duration, 91, 94–95 variables, 261–262 static specifier, 94–95 static_cast keyword, 80–81 status bars adding to frames, 848–850 overview, 848 parts of, 850–851 updating, 851––852 storage duration, 88–91, 94–95 streams, input/output, 48 string handling dynamic memory allocation, 216–225 multidimensional arrays, 171–172 one-dimensional arrays, 166–169 pointers, 189–190 strings array termination character, 166 C++/CLI + (plus sign), join operator, 217 description, 216 EndsWith() function, 222–225 joining, 217–219 modifying, 220–221 searching, 222–225 StartsWith() function, 222–225 trim() function, 220–221 trimming, 220–221 counting characters, 154–156, 189–190 extracting substrings, 305–307, 319–320
looping through, 154–156 removing blanks, 294–295, 316 structs . (period) member access operator, 325 member selection operator, 325 -> (arrow) indirect member access operator, 332 indirect member selection operator, 332 defining, 324–325 definition, 324 example, 326–329 initializing, 325 intellisense assistance, 329–330 linked lists, 331 members access, 325–329, 330–332 pointers, 330–332 RECT, 330 unions, 410 Style property, 1101 styles, cells default, 1101–1108 dynamic, 1108–1114 submenus, Windows Forms, 1038–1040 switch statement, 129–131 synonyms for data types, 60 syntactic errors, 567 system menu, 616 System using directive, 1033–1034 System::Collections using directive, 1033–1034 System::Collections::Ilist interface, 1114 System::ComponentModel using directive, 1033–1034 System::ComponentModel::BindingList interface, 1114 System::ComponentModel::BindingListView interface, 1114 System::ComponentModel::IlistSource interface, 1114 System::Data using directive, 1033–1034 System::Data::DataColumn class, 1090 System::Data::DataRow class, 1090 System::Data::DataSet class, 1090 System::Data::DataTable class, 1090 System::Drawing using directive, 1033–1034 System::Windows::Forms using directive, 1033–1034 sz prefix, 619–620
1175
Index
sz prefix
tab controls, Windows Forms
T tab controls, Windows Forms, 1040–1042 TabControl control, 1040–1042, 1127–1128 table adapters, 1090 tables, databases adding rows to adding orders, 1023–1028 dialog switching, 1010–1014 order data, storing, 1019–1021 order entry process, 1000–1001 order IDs, creating, 1014–1019 overview, 999–1000 recordsets, creating, 1002 recordsets views, creating, 1002–1006 resources, adding controls, 1006–1010 resources, creating, 1001 selecting products, 1021–1023 setting dates, 1020–1021 multiple, 1127–1128 tag names, 408–409 template classes, 653 template member functions, 430–431 templates, MFC documents, 652–653 temporary element storage, 734–736 ternary operator. See conditional operator. Text menu item, 859–860 Text property, 1068 Thick Frame option, 658 this pointer, 358–360 throwing exceptions C++/CLI, 308–309 description, 281 example, 280–281 tilde (~), NOT, 86 title bar, 615 toolbar, navigation, 1120–1123 toolbars adding buttons to editing button properties, 701–702 overview, 700–701 testing the buttons, 703 tooltips, 703–704 IDE, 10–12 tooltips, 703–704 ToString() function, 376–377 TotalNumberofItems() function, 1121 Trace class, 602–611 trace switches, 605–607
1176
tracepoints, 572–573 tracking handles, 199–200 tracking references, 225. See also references. transactions, database update, 982–984 trim() function, 220–221 trimming strings, 220–221 trivial scalar properties, 384–388 true/false data types, 57 try blocks, 281–283 typed pointers, collection classes AddHead() function, 772 AddTail() function, 772 CTypedPtrList class, 771 CTypedPtrList operators, 771–773 Find() function, 773 FindIndex() function, 773 GetAt() function, 772 GetCount() function, 773 GetHead() function, 772 GetHeadPos() function, 773 GetNext() function, 772 GetPrev() function, 772 GetTail() function, 772 GetTailPos() function, 773 InsertAfter() function, 773 InsertBefore() function, 773 IsEmpty() function, 773 RemoveAll() function, 772 RemoveAt() function, 773 RemoveHead() function, 772 RemoveTail() function, 772 SetAt() function, 773 typedef keyword, 60 type-safe collections, 760–761
U unbound delegates, 541–545 unbound mode, 1093–1099 unboxing data types, 101 unconditional branching, 132 Unindent() function, 604–605 unions anonymous, 409–410 in classes and structures, 410 defining, 408–409 definition, 407 tag names, 408–409
unmanaged C++, 3 Update() function, 980–982 update handlers, 699–700 update mode button label, changing, 992–993 Cancel button, visibility, 993–994 canceling the update, 997–998 description, 990–991 edit controls, enabling/disabling, 991–992 expediting the update, 996–997 Record menu, disabling, 994–996 update region, 731 UpdateAllViews() function, 785–787 UPDATE_COMMAND_UI messages, 689 updating databases adding records, 980–982 adding rows to tables adding orders, 1023–1028 dialog switching, 1010–1014 order data, storing, 1019–1021 order entry process, 1000–1001 order IDs, creating, 1014–1019 overview, 999–1000 recordsets, creating, 1002 recordsets views, creating, 1002–1006 resources, adding controls, 1006–1010 resources, creating, 1001 selecting products, 1021–1023 setting dates, 1020–1021 AddNew() function, 980–982 BeginTrans() function, 983–984 canceling updates, 980–982, 997–998 CancelUpdate() function, 980–982 CDatabase class, 983–984 CommitTrans() function, 983–984 completing an update, 980–982 controls button label, changing, 992–993 Cancel button, visibility, 993–994 canceling the update, 997–998 description, 990–991 edit controls, enabling/disabling, 991–992 expediting the update, 996–997 Record menu, disabling, 994–996 CRecordset operations, 980–982 Delete() function, 980–982 deleting records, 980–982 Edit() function, 980–982
editing records, 980–982 example, 984–988 inhibiting update, 988–990 optimistic record locking, 982 pessimistic record locking, 982 record locking, 982 Rollback() function, 983–984 rolling back an update, 982–984 starting an update, 988–990 tables, adding rows to adding orders, 1023–1028 dialog switching, 1010–1014 order data, storing, 1019–1021 order entry process, 1000–1001 order IDs, creating, 1014–1019 overview, 999–1000 recordsets, creating, 1002 recordsets views, creating, 1002–1006 resources, adding controls, 1006–1010 resources, creating, 1001 selecting products, 1021–1023 setting dates, 1020–1021 transactions, 982–984 Update() function, 980–982 update mode button label, changing, 992–993 Cancel button, visibility, 993–994 canceling the update, 997–998 description, 990–991 edit controls, enabling/disabling, 991–992 expediting the update, 996–997 Record menu, disabling, 994–996 validating operations, 981 Use Unicode libraries option, 657–658 user interface. See GUI (Graphical User Interface). using directives, 46, 96, 1033–1034
V validating database update operations, 981 input, dialog boxes, 1063–1066 value classes defining, 373–378 derived classes, C++/CLI, 520–526 deriving, 520–526 overloading, 461–466 Value property, 1109
1177
Index
Value property
variables variables See also const modifier See also literals See also pointers See also storage duration See also unions assigning values to, 47 automatic variables, 88–91 casting in assignment statements, 79–80 definition, 78 explicit casts, 80–81 old-style casts, 81 rules for, 78–79 debugging, 576–578 declaring, 47, 52–53, 91 decrementing, 74–76 default type, 88–91 definition (declaring), 53 definition (meaning of), 51 enumeration, 60–62 identifiers, 51–52 incrementing, 74–76 initialization, 53–54 limiting values of, 60–61 modifying, 73–74 naming, 51–52, 619–620 positioning declaration, 91 prefixes, 619–620 reserved keywords, 52 scope block, 88 global, 91–94 local, 88 stack space, 88 static storage duration, 91, 94–95 storage duration, 88–91, 94–95 vertical bars (||), logical OR, 125–126 view class, 653, 711–712, 954–957 viewing data. See DataGridView control. views. See also documents. client coordinates, 789–792 creating elements, 833–834 logical coordinates, 789–790 MM_LOENGLISH MAPPING MODE, 792–793 OnUpdate() function, 785–787 scrolling, 787–792 UpdateAllViews() function, 785–787 updating multiple, 785–787
1178
virtual class destructors, 511–516 virtual destructors, 511–516 virtual functions definition, 499 description, 497–501 inheritance, 497–501 pure, 505 references with, 503–504 virtual keyword, 499–501 virtual mode, 1093 visibility specifiers, 531
W w prefix, 619–620 watch, setting, 576 wchar_t data type, 56 Web browser controls, 1047–1048 WebBrowser control, 1047–1048 while loops, 143–145 whitespace, 49 wide character data type, 56 Win32 console applications, 6, 13–21 WINAPI() function, 622 window class, registering, 625–627 WindowProc() function, 632–637 windows client area, 708 creating, 625–627 elements borders, 615 child windows, 615 client area, 615 control menu, 616 illustration, 615 parent windows, 615 resource files, 616 system menu, 616 title bar, 615 ending the program, 636 example program, 637–638 initializing, 627 look and feel, 622 messages client area, drawing, 634–636 cooperative mulltitasking, 629–630 decoding, 633–636 definition, 681
device content, 634–636 display content, 634–636 message loop, 628–629 message processing functions, 632–637 message pump, 628–629 mulltitasking, 629–630 non-queued, 627–628 pre-emptive mulltitasking, 629–630 queued, 627–628 specifying, 623–625 Windows Forms containers, 1031 definition, 1031 dialog boxes adding, 1068–1075 button clicks, handling, 1076–1079, 1083–1086 ComboBox control, 1068–1070, 1072 context menu, responding to, 1079–1086 ControlBox property, 1068 creating, 1056–1062 DialogResult property, 1057, 1063–1066 event handler, Reset menu, 1067–1068 FormBorderStyle property, 1068 getting data from, 1070–1073 Help > About menu, 1075–1076 input controls, disabling, 1073–1074 Limits menu, 1074–1075 MaximizeBox property, 1068 MinimizeBox property, 1068 NumericUpDown control, 1068–1070, 1073 Show() function, 1062–1066 ShowDialog() function, 1062–1063 Text property, 1068 using, 1062–1068 validating input, 1063–1066 library, 9 overview, 1031–1032 Windows Forms, application databases accessing data, 1090–1091 AddNew() function, 1121 BindingNavigator control, 1120–1123 BindingSource component, 1115–1120 bound mode, 1114–1115 cells alignment, 1100 background color, 1099–1100 buttons, 1095 CellStyle property, 1109
ColumnIndex property, 1109 default styles, 1101–1108 DesiredType property, 1109 dynamic styles, 1108–1114 fonts, 1099–1100 foreground color, 1099–1100 formatting, 1100 FormattingApplied property, 1109 header, customizing, 1101 highlighting on mouseover, 1110–1114 images, 1096 non-header, customizing, 1101–1108 padding, 1100 properties, 1109 RowIndex property, 1109 selection color, 1099–1100 Value property, 1109 wrapping text, 1100 columns adding, 1096 binding to controls, 1123–1127 buttons in cells, 1095 check boxes, 1095 defining, 1093–1099 drop-down lists, 1096 editing, 1096–1098 images in cells, 1096 links, displaying, 1096 width, setting, 1098–1099 controls appearance, 1102–1103 binding to columns, 1123–1127 binding to data sources, 1115–1120 column format, 1106–1108 column headers, 1105–1106 setting up, 1103–1104 CurrentPosition() function, 1121 data source classes, 1090 DataGridView control Add() function, 1094 AddCopy() function, 1094 bound mode, 1093 Clear() function, 1094 column types, 1095–1099 DataGridViewButtonColumn column, 1095 DataGridViewCheckBoxColumn column, 1095 DataGridViewComboBoxColumn column, 1096 DataGridViewImageColumn column, 1096
1179
Index
Windows Forms, application databases
Windows Forms, application databases (continued) Windows Forms, application databases (continued) DataGridView control DataGridViewLinkColumn column, 1096 definition, 1090 displaying data, 1091–1093 Insert() function, 1094 InsertCopy() function, 1094 modes, 1092–1099 Remove() function, 1094 RemoveAt() function, 1094 unbound mode, 1093–1099 virtual mode, 1093 DataGridView control, customizing Alignment property, 1100 AlternatingRowsDefaultCellStyle property, 1101 BackColor property, 1099–1100 DataGridViewCellStyle object, 1099–1100 DefaultCellStyle property, 1101 Font property, 1099–1100 ForeColor property, 1099–1100 Format property, 1100 InheritedStyle property, 1100–1101 Padding property, 1100 RowsDefaultCellStyle property, 1101 SelectionBackColor property, 1099–1100 SelectionForeColor property, 1099–1100 Style property, 1101 System::Collections::Ilist interface, 1114 System::ComponentModel::BindingList interface, 1114 System::ComponentModel::BindingListView interface, 1114 System::ComponentModel::IlistSource interface, 1114 WrapMode property, 1100 displaying data, 1090–1091 MoveFirst() function, 1121 MoveLast() function, 1121 MoveNext() function, 1121 MovePrevious() function, 1121 navigating data sources, 1120–1123 RemoveCurrent() function, 1121 rows adding, 1094 alternate, customizing, 1108 copying, 1094 deleting, 1094
1180
System::Data::DataColumn class, 1090 System::Data::DataRow class, 1090 System::Data::DataSet class, 1090 System::Data::DataTable class, 1090 TabControl control, 1127–1128 table adapters, 1090 tables, multiple, 1127–1128 toolbar, navigation, 1120–1123 TotalNumberofItems() function, 1121 updating a database, 1122–1123 Windows Forms, application GUI Button control, 1044–1046 context menus, 1049 ContextMenuStrip control, 1049 dialog boxes adding, 1068–1075 button clicks, handling, 1076–1079, 1083–1086 ComboBox control, 1068–1070, 1072 context menu, responding to, 1079–1086 ControlBox property, 1068 creating, 1056–1062 DialogResult property, 1057, 1063–1066 event handler, Reset menu, 1067–1068 FormBorderStyle property, 1068 getting data from, 1070–1073 Help > About menu, 1075–1076 input controls, disabling, 1073–1074 Limits menu, 1074–1075 MaximizeBox property, 1068 MinimizeBox property, 1068 NumericUpDown control, 1068–1070, 1073 Show() function, 1062–1066 ShowDialog() function, 1062–1063 Text property, 1068 using, 1062–1068 validating input, 1063–1066 dialog button events, 1058–1060 dialog objects, creating, 1061–1062 event handler, dialog button, 1058–1060 event handlers, menu items, 1049–1056 FixedDialog property, 1056–1062 FormBorderStyle property, 1056–1062 GroupBox control, 1042–1044 grouping controls, 1042–1044 list boxes, 1058–1061 menu items, event handlers, 1049–1056 menus, 1037–1038 overview, 1035–1036
submenus, 1038–1040 tab controls, 1040–1042 TabControl control, 1040–1042 testing, 1048–1049 Web browser controls, 1047–1048 WebBrowser control, 1047–1048 Windows Forms, applications creating, 31–35 example, 645–647 overview, 1032–1034 properties, modifying, 1034–1035 starting, 1035 System using directive, 1033–1034 System::Collections using directive, 1033–1034 System::ComponentModel using directive, 1033–1034 System::Data using directive, 1033–1034 System::Drawing using directive, 1033–1034 System::Windows::Forms using directive, 1033–1034 using directives, 1033–1034 Windows programs. See also MFC (Microsoft Foundation Classes). API (application programming interface), 617–618 b prefix, 619–620 BOOLEAN data type, 618 by prefix, 619–620 BYTE data type, 618 c prefix, 619–620 C++ standards, 5–6 C++ versions, 5 CHAR data type, 618 CLR console applications, 6 command line pointer, 622 console applications, 6 data types, 618–619 dw prefix, 619–620 DWORD data type, 618 event-driven, 7, 617 events, 7 fn prefix, 619–620 h prefix, 619–620 HANDLE data type, 618 handles, 622 HBRUSH data type, 618 HCURSOR data type, 618 HDC data type, 618 HINSTANCE data type, 618
Hungarian notation, 620 i prefix, 619–620 instance handles, 622 l prefix, 619–620 lp prefix, 619–620 LPARAM data type, 619 LPCSTR data type, 619 LPHANDLE data type, 619 LRESULT data type, 619 message queue, 617 n prefix, 619–620 operating system, 616 organizing, 638–640 p prefix, 619–620 programming concepts, 6–8 s prefix, 619–620 structure of. See also WindowProc() function; WinMain() function. required functions, 620–621 sz prefix, 619–620 variable name notation, 619–620 variable prefixes, 619–620 w prefix, 619–620 Win32 console applications, 6 window class, registering, 625–627 window elements borders, 615 child windows, 615 client area, 615 control menu, 616 illustration, 615 parent windows, 615 resource files, 616 system menu, 616 title bar, 615 WindowProc() function, 632–637 windows creating, 625–627 ending the program, 636 example program, 637–638 initializing, 627 look and feel, 622 specifying, 623–625 windows messages client area, drawing, 634–636 cooperative mulltitasking, 629–630 decoding, 633–636 device content, 634–636
1181
Index
Windows programs
Windows programs (continued) Windows programs (continued) windows messages display content, 634–636 message loop, 628–629 message processing functions, 632–637 message pump, 628–629 mulltitasking, 629–630 non-queued, 627–628 pre-emptive mulltitasking, 629–630 queued, 627–628 WORD data type, 619 WinMain() function arguments, 622 example, 631–632 hInstance argument, 622 hPrevInstance argument, 622 lpCmdLine argument, 622 nCmdShow argument, 622 prototype, 621
1182
RegisterClassEx() function, 625–627 WINAPI() function, 622 WNDCLASSEX struct, 623–625 wizard. See MFC Application wizard. W M _ L B U T T O N D O W N message, 725–726 WM_LBUTTONUP message, 725, 727, 753 W M _ M O U S E M O V E handler, 810–811 W M _ M O U S E M O V E message, 725, 726–727 WM_PAINT message, 708, 711, 731, 754–755 WNDCLASSEX struct, 623–625 WORD data type, 619 WrapMode property, 1100 wrapping text, 1100 Write() function, 103–104, 603–604 WriteIf() function, 603–604 WriteLine() function, 103–104, 603–604 WriteLineIf() function, 603–604 write-only properties, 381