Chapter 15: Fundamental Controls Visual C++ and MFC Fundamentals 426 © FunctionX, Inc. GetClientRect() function is called to get the dimensions of the view’s client area of a frame-based application and use the resulting rectangle to paint that area: void CCView1View::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here CRect Recto; CBrush SelectedBrush(SelectedColor); CPen SelectedBlue(PS_SOLID, 1, SelectedColor); GetClientRect(&Recto); CBrush *pOldBrush = dc.SelectObject(&SelectedBrush); CPen *pOldPen = dc.SelectObject(&SelectedBlue); dc.Rectangle(Recto); dc.SelectObje ct(pOldBrush); // Do not call CView::OnPaint() for painting messages } Once the control is already positioned on the client area, to get its location and dimensions, you can call the CWnd::GetWindowRect() method. Here is an example: void CTabDlg::OnBtnInfo() { // TODO: Add your control notification handler code here CRect Recto; char LocDim[80]; m_Panel.GetWindowRect(&Recto); sprintf(LocDim, " - Panel Information -\nLeft: %d," "\nTop: %d,\nWidth: %d,\nHeight: %d", Recto.left, Recto.top, Recto.Width(), Recto.Height()); MessageBox(LocDim); } Practical Learning: Using the Client Area 1. Open the Geometry application you were working on earlier 2. Open the Quadrilateral.cpp source file and change its OnPaint() event as follows: Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls © FunctionX, Inc. 427 void CQuadrilateral::OnPaint() { CPaintDC dc(this); // device context for painting CRect Recto; // Create a light green brush CBrush BrushLightGreen(RGB(212, 235, 235)); // Create a navy pen CPen PenNavy(PS_SOLID, 1, RGB(0, 0, 128)); // Create a green brush CBrush BrushGreen(RGB(100, 175, 180)); // Create a dark green pen CPen PenGreen(PS_SOLID, 2, RGB(0, 115, 115)); // Get the location and dimensions of the client rectangle GetClientRect(&Recto); // Select the light green brush CBrush *pOldBrush = dc.SelectObject(&BrushLightGreen); // Select the navy pen CPen *pOldPen = dc.SelectObject(&PenNavy); // Draw a rectangular shape on the left side of the property page dc.Rectangle(0, 0, 162, Recto.Height()); // Select the green brush pOldBrush = dc.SelectObject(&BrushGreen); // Select the dark green pen pOldPen = dc.SelectObject(&PenGreen); // Draw the square dc.Rectangle(40, 40, 120, 100); // Draw the rectangle dc.Rectangle(20, 170, 140, 240); // Set the back mode to transparent for the text dc.SetBkMode(TRANSPARENT); // Display indicative labels dc.TextOut(60, 105, "Square"); dc.TextOut(45, 250, "Rectangle"); // Restore the old GDI tools dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush); if (IsIconic()) { SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect ); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; Chapter 15: Fundamental Controls Visual C++ and MFC Fundamentals 428 © FunctionX, Inc. // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CPropertyPage::OnPaint(); } } 3. Test the application: 4. Close the application and return to MSVC 14.2.3 The Screen and Client Coordinates When calling either the GetClientRect() or the GetWindowRect() methods to get the location and the dimensions of a control or another object, it is important to know the origin of the produced rectangle. By default, the rectangle returned by the GetWindowRect() method called by a control has its origin on the top left corner of the monitor and not on the top-left corner of the parent window. Consider the following event. It gets the location and dimensions of a control and stores them in a CRect variable. Then it paints a rectangle (it is supposed to paint the control) located on, and equal to the dimensions of, the control: void CTabDlg::OnBtnInfo() { // TODO: Add your control notification handler code here CRect Recto; m_Panel.GetWindowRect(&Recto); CClientDC dc(this); CBrush BlueBrush(RGB(0, 128, 192)); CBrush *pOldBrush = dc.SelectObject(&BlueBrush); dc.Rectangle(Recto); Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls © FunctionX, Inc. 429 dc.SelectObject(pOldBrush); } After executing the program and moving the dialog box somewhere to the middle center of the screen and clicking the button, the result is as follows: After moving the dialog box close to the top-left section of the screen and clicking the button again, the result is the following: This demonstrates that, although the control is a child of the dialog box, the rectangle returned by the GetWindowRect() method is based on the screen and not the client coordinates of the parent window. This is not an anomaly. It is purposely done so you can specify what origin you want to consider. As seen in previous lessons, the origin of the screen is positioned on the top-left corner of the monitor. This is referred to as, or is said that the location uses, screen coordinates. The origin of a client area is placed on its top-left corner. This is referred to as, or is said that the location uses, client coordinates. For example, the origin used by the above GetWindowRect() method is based on the screen. If you want the rectangle resulting from a call to either the GetClientRect() or the GetWindowRect() methods to be based on the client area (on client coordinates) of the control that called it, you can transfer the origin from the screen to the client. This is conveniently done with a call to the CWnd::ClientToScreen() method. It is overloaded as follows: void ClientToScreen(LPPOINT lpPoint) const; void ClientToScreen(LPRECT lpRect) const; If the location you had requested is a point, pass its POINT or its CPoint variable to the ClientToScreen() method. If the value you requested is a rectangle, pass its RECT or its CRect variable. Here is an example: void CTabDlg::OnBtnInfo() { // TODO: Add your control notification handler code here Chapter 15: Fundamental Controls Visual C++ and MFC Fundamentals 430 © FunctionX, Inc. CRect Recto; m_Panel.GetWindowRect(&Recto); CClientDC dc(this); CBrush BlueBrush(RGB(0, 128, 192)); CBrush *pOldBrush = dc.SelectObject(&BlueBrush); ScreenToClient(Recto); dc.Rectangle(Recto); dc.SelectObject(pOldBrush); } This time, even if the dialog box moves, the GetWindowRect() method returns the same rectangle. If the location and/or dimension are given in client coordinates, to convert them to screen coordinates, call the ScreenToClient() method. It is overloaded as follows: void ScreenToClient(LPPOINT lpPoint) const; void ScreenToClient(LPRECT lpRect) const; This method follows the opposite logic of the ClientToScreen() method. Practical Learning: Using Client and Screen Coordinates 1. The Geometry application should still be opened. From the Resource View tab open the IDD_CIRCULAR dialog box 2. On the Controls toolbox, click the Picture control and draw a rectangular shape on the left side of the dialog box Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls © FunctionX, Inc. 431 3. Change the ID of the new control to IDC_SHP_CIRCULAR and Add a Control Variable for it named m_ShapeCircular 4. Access the OnPaint event of the CCircular class and implement it as follows: void CCircular::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here // Do not call CPropertyPage::OnPaint() for painting messages // The location and dimension variable for the control CRect ShapeRect; // Create a cream color brush CBrush BrushCream(RGB(255, 230, 205)); // Create an orange brush CBrush BrushOrange(RGB(255, 128, 64)); // Create a brown pen CPen PenBrown(PS_SOLID, 2, RGB(128, 0, 0)); // Get the location and dimension of the control m_ShapeCirc.GetWindowRect(&ShapeRect); // Convert the location and dimensions to client coordinates ScreenToClient(&ShapeRect); // Select the cream brush to use CBrush *pOldBrush = dc.SelectObject(&BrushCream); // Paint the control's background to light blue dc.Rectangle(ShapeRect); // Select the brown pen to paint CPen *pOldPen = dc.SelectObject(&PenBrown); // Select an orange brush pOldBrush = dc.SelectObject(&BrushOrange); // Draw the circle dc.Ellipse(40, 30, 120, 110); Chapter 15: Fundamental Controls Visual C++ and MFC Fundamentals 432 © FunctionX, Inc. // Draw the ellipse dc.Ellipse(20, 170, 140, 240); // Set the back mode to transparent for the text dc.SetBkMode(TRANSPARENT); // Display indicative labels dc.TextOut(60, 115, "Circle"); dc.TextOut(55, 250, "Ellipse"); // Dismiss the GDI objects and restore the originals dc.SelectObject(pOldBrush); dc.SelectObject(pOldPen); } 5. Test the application 6. Close it and return to MSVC 14.2.4 The Window: Its Location and Dimensions We have reviewed various ways of specifying a control’s location and its dimensions, eitther at design or run time. Once a window or a control has been positioned on the screen or in its confined client area, it keeps these attributes until specified otherwise. When dealing with a main window, such as the frame of an application, a dialog box, a property sheet, or a wizard, the user can move it around the screen as necessary and if possible. This is usually done by dragging the title bar. When the user grabs the title bar of a window and starts dragging to move it, the window sends the WM_MOVING message as we saw in Lesson 4. The WM_MOVING event fires the OnMoving() event. This event is usually left alone as it allows the user to use an application as regularly as possible. The syntax of the OnMoving() event is: afx_msg void OnMoving(UINT nSide, LPRECT lpRect); The OnMoving() event fires while the window is being moved. The nSide argument specifies the side of window that is moving. As the window is moving, this event returns its location and dimensions as the values of the lpRect member variables. Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls © FunctionX, Inc. 433 If you create a certain type of window and you do not want the user to move it around, you can write code for the WM_MOVING message. In the following example, the user cannot move the window as its location and dimensions are restored with any attempt to move it (if you want to write the OnMoving event for a dialog box in MSVC 6, you may have to manually declare and define the event as follows): class CTabDlg : public CDialog { // Construction public: CTabDlg(CWnd* pParent = NULL); // standard constructor . . . // Implementation protected: // Generated message map functions //{{AFX_MSG(CTabDlg) virtual BOOL OnInitDialog(); afx_msg void OnMoving(UINT nSide, LPRECT lpRect); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; . . . BEGIN_MESSAGE_MAP(CTabDlg, CDialog) //{{AFX_MSG_MAP(CTabDlg) ON_WM_MOVING() //}}AFX_MSG_MAP END_MESSAGE_MAP() . . . void CTabDlg::OnMoving(UINT nSide, LPRECT lpRect) { CRect CurRect; // Find out the location and the dimensions of the window GetWindowRect(&CurRect); // You ain't moving nothin' lpRect->left = CurRect.left; lpRect->top = CurRect.top; lpRect->right = CurRect.right; lpRect->bottom = CurRect.bottom; } To programmatically move a window, call the CWnd::SetWindowPos() method. Its syntax is: BOOL SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags); The pWndInsertAfter argument is used to specify the window that will positioned in the Z coordinate on top of the window that called this method. If you have the class name or the CWnd name of the other window, pass it as the pWndInsertAfter argument. Otherwise, this argument can have one of the following values: Chapter 15: Fundamental Controls Visual C++ and MFC Fundamentals 434 © FunctionX, Inc. Value Description wndBottom This window will be positioned under all the other windows, unless it is already at the bottom. If this window is a topmost window, it will not be anymore wndTop This window will be positioned on top of all the other windows, unless it is already on top wndTopMost This window becomes positioned on top of all other window as if it were created with the WS_EX_TOPMOST extended style. In other words, even if its parent window is sent under other window, this particular one stays on top. wndNoTopMost If this window is not a top most window, it becomes positioned on top of all other windows, except the window that is top most. If this window was top most when it called this method, it is not top most anymore. If there is another top most window on the screen, that one becomes top most but this one becomes positioned under that one. If you are not trying to reposition the window in the Z coordinate, pass this argument as NULL or include the SWP_NOZORDER value for the nFlags argument. The nFlags argument is used to define how the location arguments (x and y) and the dimensions (cx and cy) will be dealt with. These other arguments have the following roles: Argument Description The argument is ignored if nFlags has the following value x This specifies the new distance from the left border of the parent to the left border of this window. This depends on the type of window and the type of parent. SWP_NOMOVE y This specifies the new distance from the top border of the parent to the top border of this window. This depends on the type of window and the type of parent. SWP_NOMOVE cx This is the new width of this window SWP_NOSIZE cy The argument is the new height of this window SWP_NOSIZE Additionally, the nFlags argument can have one of the following values or one of the above nFlags values can be combined with the following values: Value Description SWP_DRAWFRAME Draws a frame around the window SWP_FRAMECHANGED This value sends a WM_NCCALCSIZE message to the window SWP_HIDEWINDOW Hides this window SWP_NOACTIVATE If the pWndInsertAfter value specified that the window should be reposositioned and activated, which is done if the window is to be positioned on top of another, this Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls © FunctionX, Inc. 435 value lets the pWndInsertAfter be performed but the window will not be activated SWP_NOCOPYBITS Normally, after a window has been repositioned, its controls are restored to their corresponding relative locations and dimensions. It you want this validation to be ignored, pass this value SWP_NOOWNERZORDER SWP_NOREPOSITION If this value is passed, this method will not reposition the windows in the z coordinate SWP_NOREDRAW When this value is set, the client area of the window will not be redrawn SWP_NOSENDCHANGING When this value is set, the window cannot receive a WM_WINDOWPOSCHANGING message SWP_SHOWWINDOW Displays the window In the following example, a window named m_Panel is repositioned and resized: void CTestDialog::OnBtnMovePanel() { // TODO: Add your control notification handler code here m_Panel.SetWindowPos(NULL, 40, 72, 100, 86, SWP_NOZORDER); } 14.2.5 The Handle or Pointer to a Window Once a control has been created, its identifier set, its location and its dimensions specified, you and your users can exploit it. On one hand, the user can type a value, select text, scroll or control or click something. One of your jobs as a programmer is to predict as many actions as the user may want to perform on your control(s) and take appropriate actions. We have learned that one good way you can refer to a control in your code consists of first providing it with an identifier. Another prerequisite you can take is to declare and associate a control and/or a value variable for your control. Sometimes you will not have declared a control variable for a control but at one time you need to refer to it. One way you can do this is to use the control’s identifier and cast it to its corresponding class. This can be taken care of by calling the CWnd::GetDlgItem() method. It comes in two versions as follows: CWnd* GetDlgItem(int nID) const; void CWnd::GetDlgItem(int nID, HWND* phWnd) const; By providing the nID argument as the identifier of the control to this method, you can get a pointer to its class. To do this, you can declare a pointer to the class of the control, then call the GetDlgItem() method. Because GetDlgItem() returns a CWnd pointer, using the features of inheritance, cast this return value to the class of the control. Practical Learning: Accessing a Window’s Handle 1. The Geometry application should still be opened. Open the OnClickedBnUcalc() event of the CGeom3D class 2. To get handles to the edit boxes on the dialog, implement the event as follows: void CGeome3D::OnBnClickedBtnUcalc() { // TODO: Add your control notification handler code here // Related Calculations of the cube [...]... FunctionX, Inc Visual C++ and MFC Fundamentals DWL_USER © FunctionX, Inc DWLP_USER Chapter 15: Fundamental Controls Allows changing additional information 451 Chapter 16: Text -Based Controls 452 Visual C++ and MFC Fundamentals © FunctionX, Inc Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls Chapter 15: Fundamental Controls ? Static Controls ? Animation Controls ? Group Boxes ? Command Buttons... user to click a menu item that changes the title of the frame window: void CMainFrame::OnEditChangeTitle() © FunctionX, Inc 4 37 Chapter 15: Fundamental Controls { Visual C++ and MFC Fundamentals // TODO: Add your command handler code here char NewTitle[] = "Introduction to Windows Programming" ; SendMessage(WM_SETTEXT, NULL, reinterpret_cast(NewTitle)); } To retrieve the name of a window (always... 9 Because of the way bitmaps are dealt with in MSVC 7, the following program will not work as expected in MSVC 7 1 5 Note Resize the dialog box as you see fit and test the application: © FunctionX, Inc 4 57 Chapter 16: Text -Based Controls Visual C++ and MFC Fundamentals 10 Close the dialog and return to MSVC 15.2 Animation Controls 15.2.1 Overview An animation is a series of pictures put together to... create it Visual C++ is not the place to create an animation You may need a graphics software to do this To use a regular animation, the video must be a standard Microsoft Windows audio/video format: Audio Video Interleaved or AVI Therefore, it must be a file with the avi extension If the file has both audio and video, only the video part would be considered 458 © FunctionX, Inc Visual C++ and MFC Fundamentals. .. property page by providing numeric values in the Side, the Length, and the Height edit boxes before clicking their corresponding button © FunctionX, Inc Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls 4 Also test the calculations of the 3-Dimensions property page 5 After using it, close the application and return to MSVC 14.2 .7 Controls Values Update The controls used in your application... CreateWindow("EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 20, 100, 140, 200, m_hWnd, NULL, AfxGetInstanceHandle(), NULL); CWnd *NewWnd; NewWnd->FromHandle(ThisWnd); return TRUE; // return TRUE unless you set the focus to a control } 14.4 Getting Access to a Control 448 © FunctionX, Inc Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls 14.4.1 Retrieving Control Information To get information... calling this function and specifying the type of information you need, it returns a (constant) value you can use as you see fit Here are two methods of getting a handle to the instance of the application The second example uses the GetWindowLong() function: BOOL CDialog1Dlg::OnInitDialog() { CDialog::OnInitDialog(); © FunctionX, Inc 449 Chapter 15: Fundamental Controls Visual C++ and MFC Fundamentals //... Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls CDialog::OnInitDialog(); // TODO: Add extra initialization here SetWindowText("Windows Fundamentals" ); } return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE Another technique you can use consist of first declaring a null-terminated string variable, assign it a value, and. .. static control are: 454 © FunctionX, Inc Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls Colored border: You can surround the borders of the control with a black, a gray or a white color During design, specify the Type as Frame and set the color accordingly using the Color combo box These characteristics are set as SS_BLACKFRA ME, SS_GRAYFRAM E, and SS_WHITEFRA ME respectively The control... Controls Visual C++ and MFC Fundamentals Practical Learning: Using a Static Control 1 Open the Geometry application If you do not have it, open the Geometry3 application that accompany this book 2 On the main menu, click either Insert -> Resource or Project -> Add Resource… 7 In the Add Resource dialog box, click the Import button 8 Locate the folder that hold the exercises for this book and display . Fundamental Controls Visual C++ and MFC Fundamentals 438 © FunctionX, Inc. { // TODO: Add your command handler code here char NewTitle[] = "Introduction to Windows Programming& quot;;. Quadrilateral.cpp source file and change its OnPaint() event as follows: Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls © FunctionX, Inc. 4 27 void CQuadrilateral::OnPaint(). dc.Rectangle(Recto); Visual C++ and MFC Fundamentals Chapter 15: Fundamental Controls © FunctionX, Inc. 429 dc.SelectObject(pOldBrush); } After executing the program and moving the dialog