WindowsMFC 5.5 但是CAD
绘图 就是画画
第一次尝试划线
划线就是左键按下 动一动 然后弹起
CDC 给了API 分别是MoveTo 和LineTo分别代表了 划线开始和结束 所以 说 我们只需要这几点
- CDC::MoveTo (int x , int y) 开始
- CDC::LineTo (POINT point) 二者相通 结尾
- WM_CLICKUP
- WM_CLICKDOWN
如何使用
先设好 保存点
private:
Cpoint m_ptBegin;
Cpoint m_ptEnd;
}
这样就可以保存好
然后讲point 里面的坐标 存入这两个里面 开始和结尾保存好
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 划线
void CCADView::OnDraw(CDC* pDC)
{
CCADDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
pDC->MoveTo(m_ptBegin);
pDC->LineTo(m_ptEnd);
}
这样就可以划线 但是 只能画一条不太好
把刚才那个捕获删除 定时删除 我们可以在 鼠标抬起时候 刷新 不刷背景
void CCADView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptEnd = point;
InvalidateRect(NULL, FALSE); // 保存之前画的
CView::OnLButtonUp(nFlags, point);
}
这样就能画直线了
鼠标效果 使用例
我们刚才使用的时候发现没有效果不知道画哪里所以呢 完善这个操作 在MouseMove里进行操作
if (nFlags & MK_LBUTTON) { // 按位域结果为 1 就是 目标操作者对得上 也可以===
m_ptEnd = point;
InvalidateRect(NULL, FALSE);
CView::OnMouseMove(nFlags, point);
}
}
这样就能按下的时候画 不按的时候不画 但是一股放射味道 肯定不是能这么写
过于生草 所以我觉得 还是用老板比较好
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 这个函数来进行操作
HWND SetCapture(
[in] HWND hWnd //当前线程中窗口的句柄,用于捕获鼠标
);
这个使用来捕获鼠标 当然了还有 不再不捕获鼠标
BOOL ReleaseCapture; // 直接用 函数成功返回非0
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 链表
当然了 MFC 贴心的加上了CList 链表
//链表初始化
// 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 < list > MyList;, 这样的初始化 然后 开20个空间 (举例)
for (int i = 0; i < 20; i++) {
MyList.AddTail(i); // 链表新建尾部节点
}
然后查询头部元素
POSITION pos = MyList.GetHeadPosition(); // 获取头部元素 空则返回NULL
POSITION pos = MyList.GetHeadPosition(); // 获取头部元素 空则返回NULL POSITION是规定 结构体指针
while (pos) {
int val = MyList.GetNext(pos);
// 遍历 获取值
}
正式使用
首先得定义吧 这是完整定义
private:
CPoint m_ptBegin;
CPoint m_ptEnd;
typedef struct PointLines {
CPoint m_ptBegin; // 起点终点 封装
CPoint m_ptEnd;
}Lines, * PLines; // 结构体传参防止 再看一眼就会爆炸 栈爆了
CList <Lines> m_CLine; //<-- 链表 保存
然后就是保存输出了
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到客户区
WindowsGDI 的DC 里的 CreateCompatibleDC(HDC hdc) // 兼容设备上下文
和大象放进冰箱是一样的 按部就行 其实没难的
- 我要创建DC!!!!
CDC DC; 经典套路
DC.CreateCompatibleDC(pDC); //pDC自带的
- 我要创建一个位图!!!
CRect Rc; // 获取Rc 为了宽高
GetClientRect(&Rc); // 获取
CBitmap Bitmaps; // 创建位图
Bitmaps.CreateCompatibleBitmap(pDC, Rc.Width(), Rc.Height()); // DC , 长宽
- 我需要枪才能把弹夹压入 对吧 所以是时候选择枪了
//选择目标
DC.SelectObject(&Bitmaps);
- 子弹的类型 选择装填的目标 我们画线那么就把刚才的线装进去
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 发射 的方法 我们是创建图片 把画的东西都以位图形式出现了
//我们是pDC输出的
pDC->BitBlt(0, 0, Rc.Width(), Rc.Height(), &DC, 0, 0, SRCCOPY); // 懵逼请看 3 3是选择图片 2是把pDC的内容以位图形式保存
调试 出现一大块黑色发现背景是黑的 所以 我们要刷白 选择完再刷白
DC.SelectObject(&Bitmaps);
DC.FillSolidRect(&Rc, RGB(255, 255, 255)); // 重画背景色
怎么还闪啊? 仔细观看 咱们可是覆盖位图啊 所以不用刷背景
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就没事了 ,这个思想挺重要的