汗,一个平移图像的问题,始终得不到想要的效果,在论坛里都问了好多次了,惭愧啊!
先把问题讲清楚,我是在一个CMyStatic类里面画图,然后画好的曲线图像能够在鼠标拖动的情况下移动,现在情况是可以移动,但效果很不理想,一拖动整个图像跟个漏水的袋子似的,弄得整个区域都是它移动的痕迹,而且,把窗口一缩小再还原,图像又跑回到出发点了。问题介绍完了,下面讲一下我的思路(在另一个帖子里我已经讲过了),当鼠标单击时记下m_downpoint,拖动时记下m_movepoint,算出移动的距离: x=m_movepoint.x-m_downpoint.x;
y=m_movepoint.y-m_downpoint.y;然后得到绘制的图像的原来的位置m_oldrect,计算出移动后的新的位置m_newrect: m_newrect.left=m_oldrect.left+x;
m_newrect.top=m_oldrect.top+y;
m_newrect.right=m_oldrect.right+x;
m_newrect.bottom=m_oldrect.bottom+y;然后把波形图重新贴到新的位置 dc.BitBlt(0 ,0,m_newrect.Width(),m_newrect.Height() ,&MemDC,0,0,SRCCOPY);下面是我的部分代码
先把问题讲清楚,我是在一个CMyStatic类里面画图,然后画好的曲线图像能够在鼠标拖动的情况下移动,现在情况是可以移动,但效果很不理想,一拖动整个图像跟个漏水的袋子似的,弄得整个区域都是它移动的痕迹,而且,把窗口一缩小再还原,图像又跑回到出发点了。问题介绍完了,下面讲一下我的思路(在另一个帖子里我已经讲过了),当鼠标单击时记下m_downpoint,拖动时记下m_movepoint,算出移动的距离: x=m_movepoint.x-m_downpoint.x;
y=m_movepoint.y-m_downpoint.y;然后得到绘制的图像的原来的位置m_oldrect,计算出移动后的新的位置m_newrect: m_newrect.left=m_oldrect.left+x;
m_newrect.top=m_oldrect.top+y;
m_newrect.right=m_oldrect.right+x;
m_newrect.bottom=m_oldrect.bottom+y;然后把波形图重新贴到新的位置 dc.BitBlt(0 ,0,m_newrect.Width(),m_newrect.Height() ,&MemDC,0,0,SRCCOPY);下面是我的部分代码
dc.BitBlt(m_oldrect.left, m_oldrect.top, m_oldrect.Width(), m_oldrect.Height() ,&MemDC,0,0,SRCCOPY);
void CMyStatic::OnPaint()
{
CPaintDC dc(this);//这里定义的是一个CPaintDC
DrawCurve(dc);//调用DrawCurve(CPaintDC &dc)}
void CMyStatic::DrawCurve(CPaintDC &dc)
{
CRect rect;
GetWindowRect(&rect);
m_oldrect=rect;//没有拖动的时候把原位置赋值给m_oldrect
-------绘图部分略-----------
dc.BitBlt(0 ,0,rect.Width(),rect.Height(),&MemDC,0,0,SRCCOPY);//从内存中贴到显示设备
}void CMyStatic::OnLButtonDown(UINT nFlags, CPoint point) //单击
{
m_downpoint=point;
}void CMyStatic::OnMouseMove(UINT nFlags, CPoint point) //拖动
{
CClientDC dc(this);
m_movepoint=point;
int x = point.x-m_downpoint.x ;
int y = point.y-m_downpoint.y ;
//位图新的位置
m_newrect.left=m_oldrect.left+x;
m_newrect.top=m_oldrect.top+y;
m_newrect.right=m_oldrect.right+x;
m_newrect.bottom=m_oldrect.bottom+y;
DrawCurve(dc);//这里调用的是后面那个DrawCurve(CClientDC &dc),不是前面那个,说来惭愧,这个地方不知道该怎么弄了,因为前面那个的参数是CPaintDC类型的,而这里只能定义成CClientDC型的,所以我就只改了个参数,其实函数跟原来那个差别不大,都是绘制图像
}void CMyStatic::DrawCurve(CClientDC &dc)
{
CRect rect;
//////////////////////把新的位图位置赋值给rect
rect.left=m_newrect.left;
rect.top=m_newrect.top;
rect.right=m_newrect.right;
rect.bottom =m_newrect.bottom;
m_oldrect=m_oldrect;
MemBitmap.CreateCompatibleBitmap(&dc,rect.Width() ,rect.Height() );
-------------绘图部分略----------------------
dc.BitBlt(0 ,0,rect.Width(),rect.Height(),&MemDC,0,0,SRCCOPY); //能拖动的那个只是这里改动了一下//dc.BitBlt(0 ,0,rect.Width(),rect.Height() ,&MemDC,-x,-y,SRCCOPY);
}
此类中 DrawItem
响应鼠标消息
使用橡皮筋类 移动或改变大小
在此之前应该先在m_oldrect中刷新背景。
另外,应另外定义一个标志变量,在OnMouseMove中判断该变量,决定是否移动图象。
dc.BitBlt(0, 0, m_newrect.Width(), m_newrect.Height() ,&MemDC,0 ,0 ,SRCCOPY);
如果改成
dc.BitBlt(m_oldrect.left, m_oldrect.top, m_oldrect.Width(), m_oldrect.Height() ,&MemDC,0,0,SRCCOPY);
图像拖动可以超出控件的范围,而我想让它在控件范围内拖动
CRect rect;控件大小dc.BitBlt(m_oldrect.left,
m_oldrect.top,
(m_oldrect.left+m_oldrect.Width())>rect.Width()?(rect.Width()-m_oldrect.left):m_oldrect.Width(),
(m_oldrect.top+m_oldrect.Height())>rect.Height()?(rect.Height()-m_oldrect.top):m_oldrect.Height() ,
&MemDC,0,0,SRCCOPY);
dc.BitBlt(目标区域,)
这个目标区域就不要变了,只要改成后面的那个原区域就可以了。可能前面的思路有问题,所以,我把它改成了
dc.BitBlt(0, 0, m_newrect.Width(),m_newrect.Height(),&MemDC,-x ,-y ,SRCCOPY);
其中x,y就是鼠标移动的距离,所以也就没有必要计算新的位图的位置了。
x = m_movepoint.x-m_downpoint.x ;
y = m_movepoint.y-m_downpoint.y ;
但是这样的问题就是我开头说的:
可以移动,但效果很不理想,一拖动整个图像跟个漏水的袋子似的,弄得整个区域都是它移动的痕迹,而且,把窗口一缩小再还原,图像又跑回到出发点了。(这一点我想应该是有DrawCurve(CPaintDC &dc)的原因,但是我不知该怎么解决。 )
不知道自己的思路是不是正确,恳请大家指教,谢谢
然后在OnPaint() 里面加了一个判断
if(m_mouseState2==FALSE)
{
DrawCurve(dc);//如果鼠标拖动,关闭DrawCurve(CPaintDC &dc)的运行
}
但是运行之后发现,窗口一动,图像就都没有了!我没有关闭DrawCurve(CClientDC &dc)a啊?
倒数第三个参数就是X轴偏移值正数向右 负数向左;
用双缓冲来做你的例子 否则会很闪 调用invalidaterect刷新即可去掉痕迹
给你提供一个思路:
1.标要移动图形前,将屏幕重画,但不要画你要移动的图形(当然重画最好按照图形最后修改时间的先后顺序),将此时的屏幕图象保存到内存中,且将你要画的图形也在内存中保存起来,在图形移动的时候,不断Bitblt原来的屏幕和你保存的图形就可以了
void CMyStatic::DrawCurve(CPaintDC &dc)
{
CBitmap MemBitmap;
MemDC.CreateCompatibleDC(&dc);
//建立一个与屏幕显示兼容的位图
CRect rect;
GetWindowRect(&rect); m_oldrect=rect;
//this->GetParent() ->GetDocument();
//MemBitmap.CreateCompatibleBitmap(&dc,300,300);
MemBitmap.CreateCompatibleBitmap(&dc,rect.Width (),rect.Height ());
//将位图选入到内存显示设备中
CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
MemDC.FillSolidRect(0,0,rect.Width(),rect.Height(),RGB(230,230,230));
dc.BitBlt(0 ,0,m_newrect.Width(),m_newrect.Height() ,&MemDC,-x,-y,SRCCOPY); //这一句为什么要改成dc.BitBlt(0 ,0,m_newrect.Width(),m_newrect.Height() ,&MemDC,0,0,SRCCOPY); ?
//InvalidateRect(m_newrect);添加这一句刷新效果还不如不刷新的呢
MemDC.SelectObject(pOldPen);
MemBitmap.DeleteObject();
MemDC.DeleteDC();
}
dc.SetROP2(R2_XORPEN);
CPen pen(PS_SOLID,0,RGB(255,255,255)); //开始画曲线...先在原始位置画,当你有新的位置的时候,先在原来的位置再画一遍,这样原来位置的图像就不见了,然后在新位置画一遍,再有新位置时,在刚才的位置画一遍,再在新位置画一遍。这样拖动就不会闪屏,因为不用invalidate不知你用不用的上,这是个简单的方法
{
// TODO: Add your message handler code here and/or call default
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CClientDC dc(this);
OnPrepareDC(&dc);
if(point.x>=50)
{
if(LMouseDrag)
{
if(point.x<pDoc->CursorPt3.x)//光标1不能在光标2右面
{
if(point.x!=pDoc->m_ptLast.x)
{
pDoc->CursorPt1.x=point.x;
int nSave=dc.SaveDC();
dc.SetROP2(R2_XORPEN);
CPen pen(PS_SOLID,0,RGB(255,255,255));
dc.SelectObject(pen);
dc.MoveTo(pDoc->m_ptLast.x,429); 先在上次的位置画
dc.LineTo(pDoc->m_ptLast.x,25);
dc.MoveTo(point.x,429); 在新位置画
dc.LineTo(point.x,25);
pDoc->m_ptLast=point;
}
}
这是在鼠标拖动时的代码。我拖动的是两根直线。