Introduction to Windows and Graphics Programming with Visual C++

by Roger Mayne, 2015
  1. Chapter 1: Basic Concept
  2. The focus of this book is on how to use Visual C++ to develop computer programs which include the Windows graphical interface (and the touch screen). If you are unfamiliar with basic C/C++ programming, you will find it helpful to have an introductory programming book at hand to review syntax and language details.
  3. Sample code can be downloaded from World Scientific website. However, it requires me to register an account, so I don't think it is worthy.
  4. If you accidentally changed the layout of your IDE, closing the solution and re-opening it still gets you the layout before it is closed. At this time, you may want to Window - Reset Window Layout.
  5. Debugging in Visual Studio
  6. MFC Debugging Techniques
  7. P.7 VS2017 accepts "void main(void)" with a warning, but neither g++ nor clang++ allows this. "main()" must return "int".
  8. P.10 For solutions which consist of only a single project, you may want to uncheck "Create directory for solution" so that Visual C++ does not create an extra level of directories.
    1. If you uncheck it, the directory hierarchy looks like:
      • hello
        • hello.cpp
        • hello.sln
        • hello.vcxproj
        • hello.vcxproj.filters
        • hello.vcxproj.user
    2. If you check "Create directory for solution", the directory hierarchy looks like:
      • hello
        • hello.sln
        • hello (project directory)
          • Debug
            • hello.obj
            • hello.log
            • vc141.idb
            • vc141.pdb
            • hello.tlog
              • CL.command.tlog
              • CL.read.1.tlog
              • CL.write.1.tlog
              • link.command.1.tlog
              • link.read.1.tlog
              • link.write.1.tlog
              • hello.lastbuildstate
          • hello.c
          • hello.vcxproj
          • hello.vcxproj.filters
          • hello.vcxproj.user
        • Debug
          • hello.exe
          • hello.ilk
          • hello.pdb
  9. If you copy the "test.exe" under "Debug" to another PC where Visual C++ is not installed, the program cannot run. The error message is:
    The program can't start because MSVCP140D.dll is missing from your computer. Try reinstalling the program to fix this problem.
  10. P.23 If you compile the program with "Release Mode", the EXE file can be copied and run stand-alone on any Windows PC.
  11. P.13 Build - Compile allows you to check syntax only (without linking libraries).
  12. P.19 In Windows OS, you may #include <conio.h> and then in your program, _getch() will halt the program and wait the user for a keystroke.
    Note: This does not work on Unix, neither GCC nor clang.
  13. P.23 _getche() will "echo" the character pressed.
  14. Chapter 2: Arrays, Pointers and Structures
  15. P.41 "%lf" format for printf() to display a double variable
  16. P.49 "%p" format to display a pointer value
  17. P.47 It is a better practice to use pointers to pass arrays between functions rather than to make them global variables.
  18. P.50 The use of the name of a one-dimensional array without subscript represents the address of the first entry int he array.
    i.e., if you declare "int students[50];", then "students" will be equivalent to "&students[0]".
  19. P.67 In C, after you define a data type
    struct Ratoinal
    {
        int numerator;
        int denominator;
    };  
    you must refer to the data type as "struct Rational".
    However, in C++ it may be simply referred to as "Rational".
  20. Chapter 3: Introducing Classes and Objects
  21. P.83 For clarity, we will not be using overloaded functions in our example programs.
    Solomon: That's too bad. Overloading is an important feature in C++. You need overloaded constructors for a class.
  22. P.98 It may not be necessary for you to write virtual functions yourself, but you should be familiar with the concept.
  23. P.95 The use of virtual functions allows special treatment of objects from derived classes. When an object is processed, it can automatically be directed to the proper member function depending on whether it is a rectangle or a circle. This behavior is referred to as "polymorphism" and is a key feature of derived classes.
  24. member function (method)
  25. data member (instance variable). This book will call them "member variables".
  26. base class / derived class
  27. Document/View architecture
  28. In this book, we place a focus on graphics programming.
  29. Object-oriented programming is an important aspect of MFC applications and Windows.
  30. Chapter 4: Beginning Windows Programming
  31. In MFC programming, you don't need to write the main(). The OS is running a WinMain() for you. When you press your keyboard or click your mouse, the OS sends a Windows Message to your MFC program. All you need to do is prepare a Message Handler.
  32. P.119 Create an MFC Application
    1. Click the radio button "Single document interface".
      • An application may manipulate more than one document.
    2. Set the "Project style..." to "MFC Standard".
    3. We select the default "Use MFC in a shared DLL", because this leads to an executable which is compact in size (but requires a set of ".dll" library files in order to execute.
      Later if you want to generate an executable file to run on other computers without a Visual C++ installation and without separately providing the .dll files, you may change the project's "Properties", choose General - Use of MFC - in a Static Library, and build the application in "Release" mode. (You may change this in Build - Configuration Manager.)
  33. In Class View, expand CBlankView, you can see its Base Types is CView.
  34. P.125 .pch - pre-compiled header files
  35. In CView::OnDraw():
  36. P.135 To create a message handler, right-click the CView class and select "Properties". In the Properties windows, click the "Messages" button (to the right of the lightning bolt). Beside WM_KEYDOWN, there is a dropdown arrow to add OnKeyDown().
  37. P.139 In CView::OnKeyDown(), if you don't consider the Shift key, the character set is rather limited. Only uppercase letters are considered.
  38. P.146 The CDoc::OnNewDocument() function is automatically called at the beginning of program execution and before the OnDraw() function is called. It is also called when File - New is clicked from the menu bar or the "New" toolbar item is clicked. Therefore, the OnNewDocument() function is usefulfor initializing data members.
  39. P.149 In OnKeyDown() you may call pDoc->UpdateAllViews(NULL); When executed with the NULL argument, it results in
    1. clearing the window
    2. execution of the OnDraw() function to redraw the display using the current document data.

    Note: If you did not add any code to OnDraw(), this will display an empty window.
  40. P.155 Select a different color in drawing lines:
    
    CPen BluePen;
    BluePen.CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
    aDC.SelectObject(&BluePen);
    
    
  41. P.167 aDC.SetROP2(R2_NOTXORPEN);
  42. Chapter 5: Basic Graphics
    1. MouseDraw - OnRButtonDown(), OnLButtonDown(), MoveTo(), LineTo()
    2. RememberDraw - Saving the drawn images in document variables StartPoint[100], EndPoint[100], and re-draw in OnDraw(). How to add a data member.
    3. RubberBand - OnMouseMove(), SetROP2().
    4. SimpleAnimate - Moving an image. Arrow keys. SetTimer(n, ms, NULL); OnTimer(); KillTImer(n).
    5. DrawCir - Add a member function
    6. SaveFile -
      
      void CDoc::Serialize(CArchive& ar)
      {
          if (ar.IsStoring())
          {
              // TODO: add storing code here
              ar << m_nLines;
              for (int i = 0; i < m_nLines; ++i)
                  ar << StartPoint[i] << EndPoint[i];
          }
          else
          {
              // TODO: add loading code here
              ar >> m_nLines;
              for (int i = 0; i < m_nLines; ++i)
                  ar >> StartPoint[i] >> EndPoint[i];
          }
      }  
      1. Serialization is the process of writing or reading an object to or from a persistent storage medium such as a disk file.
      2. The MFC function Serialize() is a standard function of the Document class, and provides a very convenient tool for saving data in files.
      3. The object itself is responsible for preparing an overloading "<<" or ">>" to read and write its own state.
      4. After the Serialize function executes, the view is automatically redrawn. Do not confuse the CArchive class with general-purpose iostream classes, which are for formatted text only. The CArchive class is for binary-format serialized object.
    7. After the flag is set by pDoc->SetModifiedFlag(); the application will automatically remind you to save the file when you try to exit the program without saving.
    8. P.195 SetMapMode - MM_TEXT vs. MM_MOMETRIC, if you want to print in exact sizes.
  43. Chapter 6 - Menu and Toolbar
    1. If you find that a "Build" operation leaves you with a compiler or linker error related to the resource files, switch to "Rebuild" to perform a full recompile and relink.
    2. P.224 An UPDATE_COMMAND_UI message is handled just before the menu is displayed and a check mark can be set next to an item.
    3. P.227 Declare a member variable m_Color to be of type COLORREF so that it will be assigned values returned by RGB().
    4. P.228 In editing a toolbar button, you may right-click the Edit Window and choose "Show Color Window".
    5. P.238 Add a member variable in the Dialog class as a "Control Variable". This will allows the exchange of data between the dialog window and the main program.
      1. Right-click the edit control in the dialog window.
      2. Select "Value" for the Category box.
      3. Enter "m_DialogWidth" as the member variable name.
      4. Enter "int" as the Variable Type.
    6. P.240 A "modal" dialog window requires your immediate attention and the operating program will not continue until you have clicked the OK button to carry out its operation or the Cancel button to cancel the dialog.
  44. Chapter 7 - Combo Lists, Radio Buttons, and Scrollbars
    1. P.253 To remove a button from the toolbar, you click on the button and drag it off into white space. If you accidentally remove a button by mistake, you can Edit - Undo from Visual Studio.
    2. P.255 The Caption property of a Menu item can be set to "&Delete Line\tCtrl+R" so that the accelerator key is also shown in the drop-down menu. (Note that the accelerator key will not be automatically shown.)
    3. P.260 The entries in a combo list can be entered into the Properties window on the Data line using a semicolon to separate entries (e.g., "5;10;15;20").
      To prevent it from being displayed in a sorted order, you may set the Sort property to False.
    4. P.263 _wtoi() converts a CString to int.
    5. P.267 When a window is about to be displayed, WM_SIZE Windows Message is sent, so you can define an OnSize event handler to receive the x and y dimensions of the window in pixels.
    6. P.268 "Radio buttons were named after the mechanical buttons used on older radios (particularly on cars) to select preset stations. Only one button could be pressed at a time. Pressing a second button caused the first to "pop out".
    7. P.271 After you use a Group Box to enclose a few radio buttons, you may wish to set the Group property of the Group Box to be True so that radio buttons in different Group Boxes will become independent.
    8. P.274 To initialize the radio buttons in a dialog, choose Overrides and then OnInitDialog.
      if (m_DialogSnap == 1) { CheckDlgButton(IDC_SnapOn, 1); } 
    9. P.278 To equip your project with scrollbars, you should create your project using the base class CScrollView instead of CView. However, can I change the base class without reconstructing the whole project? Yes.
      1. View.h (top of the header file): classCYourProjectView: public CView changed to classCYourProjectView: public CScrollView
      2. View.cpp (right after the "include" statements): IMPLEMENT_DYNCREATE(CYourProjectView, CScrollView)
      3. BEGIN_MESSAGE_MAP(CYourProjectView, CScrollView)
    10. P.283 Archiving as text files:
      CString buffer;
      buffer.Format(L"%10d\r\n", m_FileForm);
      ar.WriteString(buffer);
      Similarly, reading texts can be done with
      CString buffer;
      ar.ReadString(buffer);
      m_FileForm = _wtoi(buffer);
    11. P.285 CString has some useful functions:
      1. Left(n)
      2. Find(str)
      3. Delete(start, len)
  45. Chapter 8: Classes, Objects and Animation
    1. P.290 You don't need to define an empty constructor. The default constructor suffices.
    2. You cannot use member initializers in Adjust(). Only constructors take member initializers.
    3. P.292 If a variable is manualy inserted (i.e., without the Add Variable Wizard), you'll have to also manually insert the "#include" statement of its class definition file (.h).
    4. P.300, after rotating angle t (with respect to the origin), the coordination of point (x,y) becomes (x cos t - y sin t, x sin t + y cos t).
      If the y-axis goes positive downward, then a positive rotation would be clockwise.
  46. Chapter 9: Classes for Graphs, Plotting and Calculations
    1. CPoint::SetPoint(x, y) - This is not even documented in MSDN!
    2. CPoint::Offset(dx, dy)
    3. CSize(cx, cy) - althought the data type seems to be compatible with CPoint, this is better to represent "relative position" while CPoint represents the exact (x,y) coordinate.
    4. CSize also has an undocumented SetSize()
    5. P.356 CDC::FillSolidRect() - Alternative way to fill a rectangle if you don't want to define a new brush.
    6. P.357 CDC::GetBkColor(), CDC::SetBkColor(COLORREF crColor)
    7. P.363 psi (pound per square inch)
Finished on 2021-06-06.