Skip to content

Commit

Permalink
5.5MFC
Browse files Browse the repository at this point in the history
  • Loading branch information
too1-666 committed Dec 3, 2024
1 parent c95cce6 commit 7b65600
Show file tree
Hide file tree
Showing 2 changed files with 390 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ export default defineConfig({
{text:'WindowsMFC_4.0',link :'/study/MFC/WindowsMFC_4.0'},
{text:'WindowsMFC_4.5',link :'/study/MFC/WindowsMFC_4.5'},
{text:'WindowsMFC_5.0',link :'/study/MFC/WindowsMFC_5.0'},
]},
{text:'WindowsMFC_5.5(双缓)',link :'/study/MFC/WindowsMFC_5.5'},
},
]

},
Expand Down
388 changes: 388 additions & 0 deletions study/MFC/WindowsMFC_5.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,388 @@
# WindowsMFC 5.5 但是CAD

-----

绘图 就是画画

### 第一次尝试划线

划线就是左键按下 动一动 然后弹起

CDC 给了API 分别是MoveTo 和LineTo分别代表了 划线开始和结束 所以 说 我们只需要这几点

1. CDC::MoveTo (int x , int y) 开始
2. CDC::LineTo (POINT point) 二者相通 结尾
3. WM_CLICKUP
4. WM_CLICKDOWN

------

### 如何使用

先设好 保存点

```c++
private:
Cpoint m_ptBegin;
Cpoint m_ptEnd;
}

```

这样就可以保存好

---

然后讲point 里面的坐标 存入这两个里面 开始和结尾保存好

```c++

void CCADView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptBegin = point;
CView::OnLButtonDown(nFlags, point);
}


void CCADView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptEnd = point;
CView::OnLButtonUp(nFlags, point);
}

```
使用Move 和Line 划线
```c++
void CCADView::OnDraw(CDC* pDC)
{
CCADDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
pDC->MoveTo(m_ptBegin);
pDC->LineTo(m_ptEnd);
}
```

这样就可以划线 但是 只能画一条不太好

----

把刚才那个捕获删除 定时删除 我们可以在 鼠标抬起时候 刷新 不刷背景

```c++
void CCADView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptEnd = point;
InvalidateRect(NULL, FALSE); // 保存之前画的
CView::OnLButtonUp(nFlags, point);
}
```
这样就能画直线了
---
### 鼠标效果 使用例
我们刚才使用的时候发现没有效果不知道画哪里所以呢 完善这个操作 在MouseMove里进行操作
```c++
if (nFlags & MK_LBUTTON) { // 按位域结果为 1 就是 目标操作者对得上 也可以===
m_ptEnd = point;
InvalidateRect(NULL, FALSE);
CView::OnMouseMove(nFlags, point);
}
}
```

这样就能按下的时候画 不按的时候不画 但是一股放射味道 肯定不是能这么写

过于生草 所以我觉得 还是用老板比较好

```c++
void CCADView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值

m_ptEnd = point;
InvalidateRect(NULL,TRUE );
CView::OnMouseMove(nFlags, point);

}



void CCADView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptBegin = point;
CView::OnLButtonDown(nFlags, point);
}


void CCADView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (nFlags & MK_LBUTTON) { // 按位域结果为 1 就是 目标操作者对得上
m_ptEnd = point;
InvalidateRect(NULL, TRUE);

}
CView::OnLButtonUp(nFlags, point);
}

```
------
### 我的鼠标放到外面怎么没反应了? SetCapture捕获鼠标 | | releaseCapture 不在捕获鼠标
挪出窗口外就会没有用所以我们使用setCapture 这个函数来进行操作
```c++
HWND SetCapture(
[in] HWND hWnd //当前线程中窗口的句柄,用于捕获鼠标
);
```

这个使用来捕获鼠标 当然了还有 不再不捕获鼠标

```c++
BOOL ReleaseCapture(); // 直接用 函数成功返回非0
```

-----

```c++


void CCADView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (nFlags & MK_LBUTTON) { // 移动但是要判断按没按下 否则他会一直移动
m_ptEnd = point;
InvalidateRect(NULL, TRUE);
CView::OnMouseMove(nFlags, point);
}
}



void CCADView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptBegin = point;
SetCapture(); // 设置捕获

}


void CCADView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_ptEnd = point;
InvalidateRect(NULL, TRUE);
ReleaseCapture();
}



```
使用方法
---------
### 画来画去只能画一条
不能忍,数据结构启动!!!!!!
##### 使用链表保存
当然了 MFC 贴心的加上了CList 链表
```c++
//链表初始化
// This code defines myList as a list of strings
// such that memory gets allocated in chunks of
// 16 strings.
CList<CString, CString &> myList(16);
// This code defines myList2 as a list of ints
// such that memory gets allocated in chunks of
// 128 ints.
CList<int, int> myList2(128);
```

所以我们初始化应该是

**CList <int> MyList;**, 这样的初始化 然后 开20个空间 (举例)

```c++
for (int i = 0; i < 20; i++) {
MyList.AddTail(i); // 链表新建尾部节点
}
```

然后查询头部元素

```c++
POSITION pos = MyList.GetHeadPosition(); // 获取头部元素 空则返回NULL
```

```c++
POSITION pos = MyList.GetHeadPosition(); // 获取头部元素 空则返回NULL POSITION是规定 结构体指针
while (pos) {
int val = MyList.GetNext(pos);
// 遍历 获取值
}
```

-------

#### 正式使用

首先得定义吧 这是完整定义

```c++
private:
CPoint m_ptBegin;
CPoint m_ptEnd;
typedef struct PointLines {
CPoint m_ptBegin; // 起点终点 封装
CPoint m_ptEnd;
}Lines, * PLines; // 结构体传参防止 再看一眼就会爆炸 栈爆了
CList <Lines> m_CLine; //<-- 链表 保存

```
然后就是保存输出了
```c++
pDC->MoveTo(m_ptBegin); // 绘制当前直线
pDC->LineTo(m_ptEnd);
POSITION a_pos = m_CLine.GetHeadPosition();
while (a_pos) {
Lines& line = m_CLine.GetNext(a_pos); // 把链表的值取出来 里面是POSITION
pDC->MoveTo(line.m_ptBegin);
pDC->LineTo(line.m_ptEnd);
}
```

这就是简单画画了

---

### 我寻思 不太对吧 ------>使用双缓冲绘图防止闪烁

确实保存之前画画的痕迹了

**BUT** 有没有一种可能 ? 我没画一次 他也画一下 实时的并不是严格意义的保存 你画画一下他不能一直抖吧 所以 我们使用双缓冲绘图来实现

↓ 兼容设备上下文 设置兼容位图 把位图塞进DC里 然后绘图 把DC图片COPY到客户区

```c++
WindowsGDI 的DC 里的 CreateCompatibleDC(HDC hdc) // 兼容设备上下文
```

> 和大象放进冰箱是一样的 按部就行 其实没难的

1. 我要创建DC!!!!

```c++
CDC DC; 经典套路
DC.CreateCompatibleDC(pDC); //pDC自带的
```

2. 我要创建一个位图!!!

```c++
CRect Rc; // 获取Rc 为了宽高
GetClientRect(&Rc); // 获取
CBitmap Bitmaps; // 创建位图
Bitmaps.CreateCompatibleBitmap(pDC, Rc.Width(), Rc.Height()); // DC , 长宽
```
3. 我需要枪才能把弹夹压入 对吧 所以是时候选择枪了
```c++
//选择目标
DC.SelectObject(&Bitmaps);
```

4. 子弹的类型 选择装填的目标 我们画线那么就把刚才的线装进去

```c++
POSITION a_pos = m_CLine.GetHeadPosition();
while (a_pos) {
Lines& line = m_CLine.GetNext(a_pos); // 把链表的值取出来 里面是POSITION
DC.MoveTo(line.m_ptBegin); // 记住不再是存在pDC输出了
DC.LineTo(line.m_ptEnd);
}
DC.MoveTo(m_ptBegin);
DC.LineTo(m_ptEnd);
```
5 发射 的方法 我们是创建图片 把画的东西都以位图形式出现了
```c++
//我们是pDC输出的
pDC->BitBlt(0, 0, Rc.Width(), Rc.Height(), &DC, 0, 0, SRCCOPY); // 懵逼请看 3 3是选择图片 2是把pDC的内容以位图形式保存
```

调试 出现一大块黑色发现背景是黑的 所以 我们要刷白 选择完再刷白

```c++
DC.SelectObject(&Bitmaps);
DC.FillSolidRect(&Rc, RGB(255, 255, 255)); // 重画背景色
```

怎么还闪啊? 仔细观看 咱们可是覆盖位图啊 所以不用刷背景

```c++
void CCADView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (nFlags & MK_LBUTTON) { // 移动但是要判断按没按下 否则他会一直移动
m_ptEnd = point;
InvalidateRect(NULL, FALSE);
CView::OnMouseMove(nFlags, point);
}

}



void CCADView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptBegin = point;
SetCapture(); // 设置捕获

}


void CCADView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_ptEnd = point;
m_CLine.AddTail(Lines{ m_ptBegin,m_ptEnd }); // 鼠标抬起时候是保存 所以 保存链表

InvalidateRect(NULL, FALSE);
ReleaseCapture();
}
```
每个调试一下 发现都会导致闪 因为刷新背景把图片刷没了 所以会闪
调成FALSE就没事了 ,这个思想挺重要的
-------
# END

0 comments on commit 7b65600

Please sign in to comment.