我想做一个类似Windows画图,但功能简单的多的小程序,这个程序在鼠标移动时画下鼠标移动的痕迹,想用双缓冲绘图。
在OnMouseMove中将图画到内存DC,OnDraw中将内存DC上画的图拷到屏幕上,这是我OnMouseMove中的代码:
CDC memDC; CRect rect;
CDC *pDC;
// 获取绘制坐标的文本框
CWnd* pWnd = GetDlgItem(IDC_STC_PIC);
pWnd->GetClientRect(&rect);
// 指针
pDC = pWnd->GetDC();
pWnd->Invalidate();
pWnd->UpdateWindow();
if((point.x>=Startx)&&(point.x<Startx+wid)&&(point.y>=Starty)
&&(point.y<Starty+lon))
{
HCURSOR m_HCross;
m_HCross=AfxGetApp()->LoadCursor(IDC_CURSOR1);
SetCursor(m_HCross);
} if((mouseDown==1)&&(point.x>=Startx)&&(point.x<Startx+wid)
&&(point.y>=Starty)&&(point.y<Starty+lon))
{
//内存绘图
CPen pen;
pen.CreatePen(PS_SOLID, 10, RGB (0, 0 , 0));
memDC.CreateCompatibleDC(pDC);
CPen* pOldPen = memDC.SelectObject (&pen);
pOldPen = memDC.SelectObject(&pen);
memDC.MoveTo(m_cpOldPoint);
memDC.LineTo(point); memDC.BitBlt(Startx,Starty,Startx+wid,Starty+lon, pDC,0,0,SRCCOPY);
pDC->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&memDC,0,0,SRCCOPY);
m_cpOldPoint.x = point.x;
m_cpOldPoint.y = point.y;
memDC.SelectObject(pOldPen);
memDC.DeleteDC();
}
实际上,我在OnMouseMove中调用了BitBlt,想试试能不能画出来,但是失败了,请高人指点,不胜感激!
在OnMouseMove中将图画到内存DC,OnDraw中将内存DC上画的图拷到屏幕上,这是我OnMouseMove中的代码:
CDC memDC; CRect rect;
CDC *pDC;
// 获取绘制坐标的文本框
CWnd* pWnd = GetDlgItem(IDC_STC_PIC);
pWnd->GetClientRect(&rect);
// 指针
pDC = pWnd->GetDC();
pWnd->Invalidate();
pWnd->UpdateWindow();
if((point.x>=Startx)&&(point.x<Startx+wid)&&(point.y>=Starty)
&&(point.y<Starty+lon))
{
HCURSOR m_HCross;
m_HCross=AfxGetApp()->LoadCursor(IDC_CURSOR1);
SetCursor(m_HCross);
} if((mouseDown==1)&&(point.x>=Startx)&&(point.x<Startx+wid)
&&(point.y>=Starty)&&(point.y<Starty+lon))
{
//内存绘图
CPen pen;
pen.CreatePen(PS_SOLID, 10, RGB (0, 0 , 0));
memDC.CreateCompatibleDC(pDC);
CPen* pOldPen = memDC.SelectObject (&pen);
pOldPen = memDC.SelectObject(&pen);
memDC.MoveTo(m_cpOldPoint);
memDC.LineTo(point); memDC.BitBlt(Startx,Starty,Startx+wid,Starty+lon, pDC,0,0,SRCCOPY);
pDC->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&memDC,0,0,SRCCOPY);
m_cpOldPoint.x = point.x;
m_cpOldPoint.y = point.y;
memDC.SelectObject(pOldPen);
memDC.DeleteDC();
}
实际上,我在OnMouseMove中调用了BitBlt,想试试能不能画出来,但是失败了,请高人指点,不胜感激!
2 应该把目标DC的拷贝到内存DC,绘制操作,绘制完毕后 再拷贝回目标DC
3 注意BitBlt的参数(int x, int y, int nWidth, int nHeight
4 建议鼠标移动到处理中记录需要绘制的点 在WM_PAINT响应中绘制,否则重新刷新后什么也没有了
非常感谢~~~~~~~~我先试试。
“4 建议鼠标移动到处理中记录需要绘制的点 在WM_PAINT响应中绘制,否则重新刷新后什么也没有了”
这个意思是说BitBlt在WM_PAINT响应中调用吗,还是整个的绘制过程在WM_PAINT响应中调用啊?
{
CSkf_MapDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
GetClientRect(&rect); //获取当前客户区域的大小
//在内存中开辟一块与当前DC相同的DC然后在其上作图
CDC mDC;
mDC.CreateCompatibleDC(pDC);
CBitmap MemBitmap;
MemBitmap.CreateCompatibleBitmap(pDC,rect.right ,rect.bottom );
CBitmap *pOldBitmap=mDC.SelectObject(&MemBitmap);
//改变背景颜色
CBrush Brush_Bak(BKColor);
CBrush *pOldBrush=mDC.SelectObject(&Brush_Bak);
mDC.SelectObject(Brush_Bak);
mDC.FillRect(&rect,&Brush_Bak);
mDC.SelectObject(pOldBrush);
//在以下绘图函数调用中,语句的先后决定了图层的先后,即先绘的在最下层。
for (int i=0;i<3;i++)
SKFDrawMap(&mDC,i);
SKFDrawBitmap(&mDC,rect.right-190,rect.bottom-528,IDB_BMPME);
SKFDrawText(&mDC);
SKFDrawYellowriver(&mDC);
SKFDrawChinese(&mDC);
//将内存DC上所绘内容一次性拷贝到当前DC
pDC->BitBlt(0,0,rect.right ,rect.bottom ,&mDC,0,0,SRCCOPY);
}
我把绘图的代码放到OnPaint的else中了:
if (IsIconic())
{
......
}
else
{
//在这里绘图
//OnDraw(&dc); CDC memDC;
CRect rect;
CDC *pDC;
CBitmap memBitmap;
CBitmap* pOldBmp = NULL;
// 获取绘制坐标的文本框
CWnd* pWnd = GetDlgItem(IDC_STC_PIC);
pWnd->GetClientRect(&rect);
// 指针
pDC = pWnd->GetDC();
pWnd->Invalidate();
pWnd->UpdateWindow();
memDC.CreateCompatibleDC(pDC);
memBitmap.CreateCompatibleBitmap(pDC,rect.right,rect.bottom);
pOldBmp = memDC.SelectObject(&memBitmap);
memDC.BitBlt(rect.left,rect.top,rect.right,rect.bottom,pDC,0,0,SRCCOPY);
if((mouseDown==1))
{
//内存绘图
CPen pen;
pen.CreatePen(PS_SOLID, 10, RGB (0, 0 , 0));
CPen* pOldPen = memDC.SelectObject (&pen);
pOldPen = memDC.SelectObject(&pen);
memDC.MoveTo(m_cpOldPoint);
memDC.LineTo(m_cpNewPoint);
m_cpOldPoint.x = m_cpNewPoint.x;
m_cpOldPoint.y = m_cpNewPoint.y;
memDC.SelectObject(pOldPen);
}
//把内存绘图拷贝到屏幕
pDC->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&memDC,0,0,SRCCOPY);
memDC.DeleteDC();
memBitmap.DeleteObject(); CDialog::OnPaint();
}在OnMouseMove中改成这样的实现:
void CPatternDlg::OnMouseMove(UINT nFlags, CPoint point)
{
m_cpNewPoint.x = point.x;
m_cpNewPoint.y = point.y; SendMessage(WM_PAINT, 0, 0);
}现在有两个问题:
1 切换窗口后绘图区域还是变成空白的;
2 绘图是出现卡的情况,估计是SendMessage引起的,但是不知道该怎么解决希望能指点一下,谢谢了
改成Invalidate();
SendMessage 要等到响应完成的, 你鼠标的处理本来就是在消息循环中的,等于卡自己脖子
换成Invalidate,在窗口上移动鼠标时,呼呼滴刷新,就给风吹动水面似的;
换成PostMessage和使用SendMessage效果是一样的
“如果你希望在鼠标拖动的时候实时显示,那么在鼠标处理事件中也要GetDC然后双缓冲绘图”
你的意思是说
在OnMouseMove中也要和OnDraw中一样实现吗?
先绘到内存DC,然后拷贝到屏幕上?
在里面返回true
类似Windows自带的画图工具
只支持鼠标绘图就可以
现在感觉越来越乱了
我试了,窗口虽然不闪了,但是整个窗口背景成了白的
http://download.csdn.net/source/603538例子很多吧
这是干嘛?看不懂
3.内存DC memDC要载入位图之后才能绘图
HBITMAP hBmp = CreateCompatibleBitmap(pDC);
HBITMAP hOldBmp = memDC.SelectObject(hBmp);
是由内存DC拷贝到屏幕上,不知道除了拷贝区域的范围可能不准确外,还有别的错误吗?3. “内存DC memDC要载入位图之后才能绘图”这段代码和你写的一样吧?
memDC.CreateCompatibleDC(pDC);
memBitmap.CreateCompatibleBitmap(pDC,rect.right,rect.bottom);
pOldBmp = memDC.SelectObject(&memBitmap);
非常感谢你的热心帮助,但是“有道理,这里有个好例子http://download.csdn.net/source/2687885”这个例子的下载页面里面是空的,什么都没有
1. 我想实现鼠标绘图,是那种伴随鼠标移动而动态出现鼠标移动痕迹的绘图,不是只绘制鼠标按下和弹起两个点之间的先的绘图。为了响应WM_PAINT消息时可以重绘图片,我是不是需要在鼠标移动处理函数中用数组记录下每个点的坐标?
2. 如果记录的话怎么记录,三维数组?还有没有别的方法?
3. 以上1, 2的思路是不是有问题?
每一条线就是一个数组
记录了这条线经过的点
可以考虑用CArray
——————————————————————————————————————
| 标题栏 |
——————————————————————————————————————
| A区域(非保存区域) |
——————————————————————————————————————
| |
| B区域(绘图区域,保存区域) |
| |
| |
| |
——————————————————————————————————————我想把B区域保存为BMP文件,但是保存出来之后是A区域和B区域,我怀疑这部分代码有问题,请高人给看一下:
CDC *dcDrawClient = NULL;
CDC dcMemDC;
CBitmap cbBitmap;
GetDlgItem(IDC_STC_PIC)->GetWindowRect(&rect);
pCWnd = GetDlgItem(IDC_STC);
dcDrawClient = pCWnd->GetDC();
cbBitmap.CreateCompatibleBitmap(dcDrawClient, rect.right, rect.bottom);
dcMemDC.CreateCompatibleDC(dcDrawClient);
CBitmap *pcbOldBitmap = (CBitmap *)dcMemDC.SelectObject(&cbBitmap);
dcMemDC.FillRect(&rect, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
cpPen.CreatePen(PS_SOLID, m_nLineWidth, RGB (0, 0 , 0));
pOldPen = dcMemDC.SelectObject(&cpPen);
for (int i = 0; i < m_Array.GetSize(); i++)
{
dcMemDC.MoveTo(((CLines *)m_Array.GetAt(i))->m_ptOrigin);
dcMemDC.LineTo(((Lines *)m_Array.GetAt(i))->m_ptEnd);
}
dcMemDC.SelectObject (pOldPen);
dcMemDC.SelectObject(pcbOldBitmap);
::OpenClipboard(this->m_hWnd);
::EmptyClipboard();
::SetClipboardData(CF_BITMAP, cbBitmap);
::CloseClipboard();