MFC Learning (01) Rectangular Box Selects Moving Triangle (VC++6.0 Version)
Note: This is a computer graphics homework after class, homework original text: Given a triangle (vertex coordinates themselves given, not necessarily to draw triangles, more than three vertices of the plane graphics can also be drawn), using the mouse and mouse response function, select the rectangular area, determine whether the triangle is in the rectangular area, such as If the triangle falls completely into the rectangular area, the color of the triangle changes, and when the mouse is in the rectangular area to be judged, dragging the mouse can move the triangle.
For reference only, please spray if you don't like it.
0. Code address
- Visual C++ 6.0
Click View Code
1. Let's first look at the sample program provided by the teacher.
2. Analysis
- The triangle is initially black, with three vertices each having a small square.
- When dragging, the mouse style remains unchanged. The dragged rectangle is a solid green line.
- If all three points are in the rectangular box (which I think is the same as the line pressing), then the color of the triangle will change.
- When the triangle is red, the red triangle will follow when the left mouse button is pressed and the mouse is moved.
- At the end of the drag (when the left mouse button pops up), the triangle continues to turn black.
3. Pseudo-code
// Left mouse button press event Void OnLButton Down (click the coordinate point) { M_IsLButton Down = true; // Mark this time the left mouse button has been pressed if (can start moving) { Record the starting point p1; } Others// Can't move, start drawing rectangles { Record the upper left corner coordinate p0 = point of the rectangle. Initialize the lower right corner coordinate pm = point of the rectangle; } }
// Mouse movement events Void OnMouseMove { // We only consider the movement of the mouse when the left mouse button is pressed. if (true == m_IsLButtonDown) { if (can start moving) { Modify each vertex of the triangle by using the current mouse position and the position of the initial record; //Make the graph move with the mouse } Others// Can't move, just continue drawing rectangle { Record the lower right corner coordinate pm = point of the rectangle. } } }
// Left mouse button pop-up event Void OnLButton Up (pop-up coordinate point) { M_IsLButton Down = true; // Mark this time the left mouse button has been pressed if (can start moving) { At the end of this move, the mark can not be moved. Modify the brush color to black. } Others // Can't move, so start judging whether the current drawing rectangle contains a triangle or not. { if (the rectangle contains a triangle) { Markers can be moved; Modify the brush color to red. } Clear the rectangular information; } }
4. Handlebars begin to frame.
1. New projects
2. Basic Settings
- Single document, MFC standard, static library, and then click Finish
3. Adding class variables
- Find Class View
- Right-click CRectangleSelectTriangleView
- Click Add Member Variable...
- Add the following class variables in turn
bool m_IsLButtonDown; // Whether to press the left key or not
bool m_IsReadyToMove; // Can I start moving?
CPoint p0; // Record the upper-left coordinates of the rectangular box
CPoint pm; // Record the lower right corner coordinates of the rectangle
CPoint p1; // It's used when moving triangles.
CPen * m_CurrentPen; // Point to the current brush, initialize to point to the black brush
CPoint m_Points[3]; // Preserving the three vertices of a triangle
4. Adding custom message handlers
- ** Right-click on the CRectangleSelectTriangleView class
- Add the following message handlers in turn
WM_LBUTTONDOWN WM_MOUSEMOVE WM_LBUTTONUP
- This should be done as follows:
So far, we have completed the basic "framework"
Next comes the code section.
According to our pseudo-code idea, step by step
5. Step-by-step coding
- 1. Define three different color brushes in CRectangleSelectTriangleView.cpp
CPen BlackPen(BS_SOLID, 2, RGB(0, 0, 0));
CPen GreenPen(BS_SOLID, 2, RGB(0, 255, 0));
CPen RedPen(BS_SOLID, 2, RGB(255, 0, 0));
- 2. Define a macro for coordinate transformation at the beginning of CRectangleSelectTriangleView.cpp
#define Trans(p1, rect) CPoint(long((p1.x+0.5)/1) - rect.Width()/2, long((p1.y+0.5)/1) - rect.Height()/2)
- 3. Assignment of class variables in the CRectangleSelectTriangleView class constructor
//Initially immovable
m_IsReadyToMove = false;
m_IsLButtonDown = false;
p0 = pm = p1 = 0;
m_Points[0] = CPoint(143, 113);
m_Points[1] = CPoint(245, 64);
m_Points[2] = CPoint(205, 214);
//Initial point to black brush
m_CurrentPen = &BlackPen;
- 4. In the OnDraw function
void CRectangleSelectTriangleView::OnDraw(CDC* pDC)
{
CRectangleSelectTriangleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: Add drawing code for native data here
CRect rect;
GetClientRect(&rect);
pDC->SetWindowExt(rect.Width(), rect.Height());
pDC->SetViewportExt(rect.Width(), -rect.Height());
pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);
CDC memDC; // Declare memory DC
CBitmap NewBitmap, *pOldBitmap;
memDC.CreateCompatibleDC(pDC); // Create a memory DC compatible with the display DC
NewBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); // Creating Compatible Memory Bitmaps
pOldBitmap = memDC.SelectObject(&NewBitmap); // Select Compatible Bitmaps into Memory DC
memDC.FillSolidRect(rect, pDC->GetBkColor()); // Fill the client area with the original background color, otherwise it's black.
rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);
memDC.SetWindowExt(rect.Width(), rect.Height());
memDC.SetViewportExt(rect.Width(), -rect.Height());
memDC.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);
memDC.SetROP2(R2_COPYPEN); // Setting up the drawing mode
DrawObject(&memDC, rect); // Draw triangles, draw rectangular boxes in this function
// Copy bitmaps from memory DC to device DC
pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, -rect.Width() / 2, -rect.Height() / 2, SRCCOPY);
memDC.SelectObject(pOldBitmap);
}
- Declarations and Definitions of DrawObject Functions
// The public part declaration within the CRectangleSelectTriangleView class in CRectangleSelectTriangleView.h
void CRectangleSelectTriangleView::DrawObject(CDC* pDC, const CRect& rect);
// Implementation in CRectangleSelectTriangleView.cpp
void CRectangleSelectTriangleView::DrawObject(CDC* pDC, const CRect& rect)
{
int i = 0;
CPen * oldPen = pDC->SelectObject(m_CurrentPen);
// Draw a triangle
for (i = 0; i < 2; i++)
{
pDC->MoveTo(Trans(m_Points[i], rect));
pDC->LineTo(Trans(m_Points[i + 1], rect));
}
pDC->MoveTo(Trans(m_Points[2], rect)), pDC->LineTo(Trans(m_Points[0], rect));
// Draw a small square near the vertex
CPoint v1(6, 6); // The radius of a circle is six pixels
for (i = 0; i < 3; i++)
{
pDC->Rectangle(CRect(CPoint(Trans(m_Points[i], rect) - v1), CPoint(Trans(m_Points[i], rect) + v1)));
// If you don't like squares, you can change the following sentence into a small circle.
// pDC->Ellipse(CRect(CPoint(Trans(m_Points[i], rect) - v1), CPoint(Trans(m_Points[i], rect) + v1)));
}
// Next draw the rectangular box
HBRUSH hb = (HBRUSH)GetStockObject(NULL_BRUSH); // Get a transparent fill handle
CBrush* Brush = CBrush::FromHandle(hb); // Get an object from this handle
CBrush *pOldBrush = pDC->SelectObject(Brush); // Select the transparent brush into the device description table
pDC->SelectObject(&GreenPen);
pDC->Rectangle(CRect(Trans(p0, rect), Trans(pm, rect)));
pDC->SelectObject(oldPen);
}
At this point, we can compile and run to see the triangle effect map.
- 5. In OnLButton Down function
void CRectangleSelectTriangleView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add message handler code and/or call default values here
m_IsLButtonDown = true; // Mark this time the left mouse button has been pressed
if (m_IsReadyToMove) // If you can start moving
{
p1 = point;
}
else // If you can't move, start drawing rectangles.
{
p0 = point; // Record the upper-left coordinates of the rectangle
pm = point; // Initialize the lower right corner coordinates of the rectangle
}
CView::OnLButtonDown(nFlags, point);
}
- 6. In On OnOnMouseMove function
void CRectangleSelectTriangleView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add message handler code and/or call default values here
// We only consider the movement of the mouse when the left mouse button is pressed.
if (true == m_IsLButtonDown)
{
if (m_IsReadyToMove) // If you can start moving
{
// Modify each vertex of the triangle by using the current mouse position point and p1 to achieve the effect that the graph moves with the mouse
for (int i = 0; i < 3; i++)
{
m_Points[i] += point - p1;
}
p1 = point;
}
else // If you can't move, continue drawing rectangles.
{
pm = point; // Record the lower right corner coordinates of the rectangle
}
// Trigger OnDraw function, dynamic effect
Invalidate(FALSE);
}
CView::OnMouseMove(nFlags, point);
}
- 7. In the OnLButton Up function
void CRectangleSelectTriangleView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add message handler code and/or call default values here
m_IsLButtonDown = false; // Mark this time the left mouse button has popped up
if (m_IsReadyToMove) // If you can start moving
{
m_IsReadyToMove = false; // At the end of this move, the mark cannot be moved.
m_CurrentPen = &BlackPen; // Modify the brush color to black
}
else // If you can't move, start judging whether the rectangle currently drawn contains a triangle.
{
if (IsInside())
{
m_IsReadyToMove = true; // Markers can be moved
m_CurrentPen = &RedPen; // Modify the brush color to red
}
}
p0 = pm = 0; // Clear this rectangular information
// Trigger OnDraw function, dynamic effect
Invalidate(FALSE);
CView::OnLButtonUp(nFlags, point);
}
- Declarations and Definitions of IsInside Functions
// The public part declaration within the CRectangleSelectTriangleView class in CRectangleSelectTriangleView.h
bool CRectangleSelectTriangleView::IsInside();
// Implementation in CRectangleSelectTriangleView.cpp
bool CRectangleSelectTriangleView::IsInside()
{
for (int i = 0; i < 3; i++)
{
if (m_Points[i].x >= p0.x && m_Points[i].y >= p0.y &&
m_Points[i].x <= pm.x && m_Points[i].y <= pm.y
)
// If the current vertex is inside the rectangle, continue to determine the next vertex
continue;
// If the current vertex is not inside the rectangle, return false directly
return false;
}
// If all three points are inside the rectangle, then the center of the triangle is inside the rectangle.
return true;
}
6. Summary
- I have limited ability. In this article, I do not judge whether the mouse is in the triangle when I am ready to drag.
- If you need any friends, please comment below. I will send you the code.