View: Draw your game interface
Previously, the game board object has been initialized in our document object, and we need to display this information to the user.
The first step is to add code to reset the window size. The default window size is not what we want. We will rewrite the oninitialupdate method to achieve this. The View class inherits a default oninitialupdate method, and we want to rewrite it to redefine the size of our window. The oninitialupdate method is called when it is initialized and updated in the customer zone. First, let's look at how to add this method.
Switch to Class View, select csamegameview, and press Alt + enter
Click the override icon. For example, find the oninitialupdate method to rewrite it:
The following is the modified View Class header file. Note that the font focuses on the modified part.
#pragma onceclass CSameGameView : public CView{protected: // create from serialization only CSameGameView(); DECLARE_DYNCREATE(CSameGameView) // Attributespublic: CSameGameDoc* GetDocument() const; // Overridespublic: virtual void OnDraw(CDC* pDC); // overridden to draw this view virtual BOOL PreCreateWindow(CREATESTRUCT& cs);protected: // Implementationpublic: void ResizeWindow(); virtual ~CSameGameView();#ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const;#endif // Generated message map functionsprotected: DECLARE_MESSAGE_MAP()public: virtual void OnInitialUpdate();};#ifndef _DEBUG // debug version in SameGameView.cppinline CSameGameDoc* CSameGameView::GetDocument() const{ return reinterpret_cast<CSameGameDoc*>(m_pDocument); }#endif
While adding the resizewindow method, we also need to add the method for describing the game interface to the csamegameview class. The header file and source file of the View class already contain an ondraw method. Here is where we describe the interface code. The following are all the code for implementing the CPP class of the View class. Note that the new content is important to the font.
#include "stdafx.h"#include "SameGame.h"#include "SameGameDoc.h"#include "SameGameView.h"#ifdef _DEBUG#define new DEBUG_NEW#endif// CSameGameViewIMPLEMENT_DYNCREATE(CSameGameView, CView)BEGIN_MESSAGE_MAP(CSameGameView, CView)END_MESSAGE_MAP()// CSameGameView construction/destructionCSameGameView::CSameGameView(){}CSameGameView::~CSameGameView(){}BOOL CSameGameView::PreCreateWindow(CREATESTRUCT& cs){ return CView::PreCreateWindow(cs);}// CSameGameView drawingvoid CSameGameView::OnDraw(CDC* pDC) // MFC will comment out the argument name by default; uncomment it{ // First get a pointer to the document CSameGameDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(!pDoc) return; // Save the current state of the device context int nDCSave = pDC->SaveDC(); // Get the client rectangle CRect rcClient; GetClientRect(&rcClient); // Get the background color of the board COLORREF clr = pDoc->GetBoardSpace(-1, -1); //Draw the background first pDC->FillSolidRect(&rcClient, clr); // Create the brush for drawing CBrush br; br.CreateStockObject(HOLLOW_BRUSH); CBrush* pbrOld = pDC->SelectObject(&br); //Draw the squares for(int row = 0; row < pDoc->GetRows(); row++) { for(int col = 0; col < pDoc->GetColumns(); col++) { // Get the color for this board space clr = pDoc->GetBoardSpace(row, col); // Calculate the size and position of this space CRect rcBlock; rcBlock.top = row * pDoc->GetHeight(); rcBlock.left = col * pDoc->GetWidth(); rcBlock.right = rcBlock.left + pDoc->GetWidth(); rcBlock.bottom = rcBlock.top + pDoc->GetHeight(); // Fill in the block with the correct color pDC->FillSolidRect(&rcBlock, clr); // Draw the block outline pDC->Rectangle(&rcBlock); } } // Restore the device context settings pDC->RestoreDC(nDCSave); br.DeleteObject();}// CSameGameView diagnostics#ifdef _DEBUGvoid CSameGameView::AssertValid() const{ CView::AssertValid();}void CSameGameView::Dump(CDumpContext& dc) const{ CView::Dump(dc);}// non-debug version is inlineCSameGameDoc* CSameGameView::GetDocument() const{ ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSameGameDoc))); return (CSameGameDoc*)m_pDocument;}#endif //_DEBUGvoid CSameGameView::OnInitialUpdate(){ CView::OnInitialUpdate(); // Resize the window ResizeWindow();}void CSameGameView::ResizeWindow(){ // First get a pointer to the document CSameGameDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(!pDoc) return; // Get the size of the client area and the window CRect rcClient, rcWindow; GetClientRect(&rcClient); GetParentFrame()->GetWindowRect(&rcWindow); // Calculate the difference int nWidthDiff = rcWindow.Width() - rcClient.Width(); int nHeightDiff = rcWindow.Height() - rcClient.Height(); // Change the window size based on the size of the game board rcWindow.right = rcWindow.left + pDoc->GetWidth() * pDoc->GetColumns() + nWidthDiff; rcWindow.bottom = rcWindow.top + pDoc->GetHeight() * pDoc->GetRows() + nHeightDiff; // The MoveWindow function resizes the frame window GetParentFrame()->MoveWindow(&rcWindow);}
It is very simple to depict the game board, that is, draw each color brick to the screen in one row, one column and one column.
First, we fill the background color of the customer area in black. The customer area fill color is obtained by calling the getboardspace (-1,-1) method; the customer area size is obtained by calling the getclientrect method, finally, the filling task is implemented by calling the fillsolidrect method.
// Get the client rectangleCRect rcClient;GetClientRect(&rcClient);// Get the background color of the boardCOLORREF clr = pDoc->GetBoardSpace(-1, -1);// Draw the background firstpDC->FillSolidRect(&rcClient, clr);
Next, we will draw a small brick. We will draw a rectangle with a color and a black border. To achieve this, we will set the painting brush type to hollow_brush, in this way, when we call the rectangle () method, our small squares are not filled with the default white background.
The logic of the nested for loop is very simple, that is, a row, a column, and a column depict small blocks in the customer area. Through the document class, we can obtain the random color of each small brick Block, we can also get the size of the small brick, and then calculate the position that each small block should depict. We use the fillsolidrect () method to fill in the color of the small brick. Use the rectangle () method to draw the border of a small brick.
// Draw the squaresfor(int row = 0; row < pDoc->GetRows(); row++){ for(int col = 0; col < pDoc->GetColumns(); col++) { // Get the color for this board space clr = pDoc->GetBoardSpace(row, col); // Calculate the size and position of this space CRect rcBlock; rcBlock.top = row * pDoc->GetHeight(); rcBlock.left = col * pDoc->GetWidth(); rcBlock.right = rcBlock.left + pDoc->GetWidth(); rcBlock.bottom = rcBlock.top + pDoc->GetHeight(); // Fill in the block with the correct color pDC->FillSolidRect(&rcBlock, clr); // Draw the block outline pDC->Rectangle(&rcBlock); }}
Next, we will re-calculate the window size based on the number and size of the small bricks we depict.
// Get the size of the client area and the windowCRect rcClient, rcWindow;GetClientRect(&rcClient);GetParentFrame()->GetWindowRect(&rcWindow);
Note that we have obtained two window sizes, one is the frame window (including the customer area, menu, toolbar, and status bar), and the other is the size of the customer area. First, we need to calculate the height difference and the width difference between the frame window and the client window. Then, we need to add the height difference and the Row Height of all our bricks to get the final window height, the same is true for width calculation.
// Calculate the differenceint nWidthDiff = rcWindow.Width() - rcClient.Width();int nHeightDiff = rcWindow.Height() - rcClient.Height();// Change the window size based on the size of the game boardrcWindow.right = rcWindow.left + pDoc->GetWidth() * pDoc->GetColumns() + nWidthDiff;rcWindow.bottom = rcWindow.top + pDoc->GetHeight() * pDoc->GetRows() + nHeightDiff;// The MoveWindow function resizes the frame window
Finally, we call the movewindow method of the parent window, that is, the Framework Window, to reset the window size.
GetParentFrame()->MoveWindow(&rcWindow);
In the end, our program looks like this:
Conclusion
In this article, we first reviewed the basic knowledge of MFC and the basic concepts of the document view structure. Next, we abstracted a game board type, which contains our game data information, and constructed a view that depicts the Game Information in the interface. The next chapter, we will use the event-driven programming method to achieve interaction with users, such as mouse clicking events, to implement a playable game version.
The same game ": a simple game from start to finish3