关于画十字线的难题 本帖最后由 hill_qd 于 2010-01-09 06:14:12 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 用SetROP2是出现这种情况建议用双缓冲绘制, 不会闪烁, 而且绝对不会出现你这种情况 楼上两个人仔细看看代码,帮我解决实际问题,sandyandy说的跟我的问题不一样 afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); ON_WM_GETMINMAXINFO()void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { // TODO: Add your message handler code here and/or call default lpMMI->ptMinTrackSize.x = 640 ; lpMMI->ptMinTrackSize.y = 456 ; CFrameWnd::OnGetMinMaxInfo(lpMMI);} 我运行了一下你的程序,那个Cross(十字线怎么是跟着鼠标变化的,不是固定大小的?) OnLButtonDblClk(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CDC* pDC = GetDC(); if(m_rectCross.PtInRect(point)) { if(m_bDispCross) { if(m_rectCross.PtInRect(m_ptCrossLast) && m_bNeedEraseCross) DrawSelectCross(pDC, m_ptCrossLast); m_bNeedEraseCross = FALSE; m_bDispCross = FALSE; ReleaseCapture(); } else { //DrawSelectCross(pDC, m_ptCrossLast); DrawSelectCross(pDC, point); m_bDispCross = TRUE; m_bNeedEraseCross = TRUE; m_ptCrossLast = point; SetCapture( ); } } ReleaseDC(pDC); CView::OnLButtonDblClk(nFlags, point);} schlafenhamster:m_rectCross是随窗口大小而变化的,他是窗口的一部分,可以说是小于最小窗口的尺寸的 zgl7903:按照你的方法,当进入画十字状态后,不能点别的地方了,我本来的意思是,鼠标离开绘图区域后,还可以干别的,回来后继续画十字,除非在绘图区双击鼠标后才能退出这种状态。schlafenhamster:那个画十字就是跟随鼠标的 “m_rectCross是随窗口大小而变化的,他是窗口的一部分,可以说是小于最小窗口的尺寸的“,保证他随窗口改变而改变,并小于窗口一些,你的程序就没问题, 你可以定义一个m_rectCross试试 CXxxxView::CXxxxView(){ // TODO: add construction code herem_rectCross.left=60;m_rectCross.right=360;// 当窗口right小于时,cross就不擦除了!m_rectCross.top=60;m_rectCross.bottom=160;m_bDispCross=TRUE;} 绘图区的大小是变化的,但一定要小于几个点,看看WM_SIZE用户改变窗口大小时,检查绘图区的大小。 void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { // TODO: Add your message handler code here and/or call default lpMMI->ptMinTrackSize.x = 220 ; lpMMI->ptMinTrackSize.y = 320 ; CFrameWnd::OnGetMinMaxInfo(lpMMI);}//是这个吗?关键是鼠标不能落在绘图区域内! CXxxxView::CXxxxView(){ // TODO: add construction code here m_rectCross.left=20; m_rectCross.right=60; m_rectCross.top=60; m_rectCross.bottom=160; m_bDispCross=TRUE;}//试试再也不会留cross了!void CXxxxView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); if(cx==0) return; m_rectCross.right=cx-20;//Only horizondle processed// afxDump << cx << "," << cy <<"\n"; // TODO: Add your message handler code here } 不太理解楼主的做法,我简单用CWnd实现了一下,不知道是否是楼主的意思,如果不是也可以做一下参考class CXXWnd : public CWnd{ DECLARE_DYNAMIC(CXXWnd)public: CXXWnd(); virtual ~CXXWnd();public: BOOL m_bMouseIn; BOOL m_bOpenDrawCross;protected: void DrawCross(CDC* pDC);protected: virtual BOOL PreCreateWindow(CREATESTRUCT& cs);public: DECLARE_MESSAGE_MAP() afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnPaint(); afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);};// TransparentWnd.cpp : implementation file//#include "stdafx.h"#include "XXWnd.h"// CXXWndIMPLEMENT_DYNAMIC(CXXWnd, CWnd)CXXWnd::CXXWnd(){ m_bMouseIn = FALSE; m_bOpenDrawCross = FALSE;}CXXWnd::~CXXWnd(){}BEGIN_MESSAGE_MAP(CTransparentWnd, CWnd) ON_WM_CREATE() ON_WM_PAINT() ON_WM_LBUTTONDBLCLK() ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSELEAVE, &CXXWnd::OnMouseLeave)END_MESSAGE_MAP()// CXXWndmessage handlersBOOL CXXWnd::PreCreateWindow(CREATESTRUCT& cs){ return CWnd::PreCreateWindow(cs);}int CXXWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){ if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; return 0;}void CXXWnd::OnPaint() // 视图在OnDraw中处理{ CPaintDC dc(this); // device context for painting DrawCross(&dc);}void CXXWnd::OnLButtonDblClk(UINT nFlags, CPoint point){ CWnd::OnLButtonDblClk(nFlags, point); m_bOpenDrawCross = !m_bOpenDrawCross; Invalidate();}void CXXWnd::OnMouseMove(UINT nFlags, CPoint point){ CWnd::OnMouseMove(nFlags, point); TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.hwndTrack = m_hWnd; tme.dwFlags = TME_LEAVE; ::TrackMouseEvent(&tme); m_bMouseIn = TRUE; Invalidate();}LRESULT CXXWnd::OnMouseLeave(WPARAM wParam, LPARAM lParam){ m_bMouseIn = FALSE; Invalidate(); return TRUE;}void CXXWnd::DrawCross(CDC* pDC){ ASSERT(pDC); CDC memDC; CBitmap bitmap, *pOldBitmap = NULL; CRect rcClient; GetClientRect(rcClient); if ( memDC.CreateCompatibleDC(pDC) && bitmap.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height()) ) { pOldBitmap = memDC.SelectObject(&bitmap); COLORREF clrBk = pDC->GetBkColor(); memDC.FillRect(rcClient, &CBrush(clrBk)); if ( m_bOpenDrawCross && m_bMouseIn ) { CPoint ptMouse; GetCursorPos(&ptMouse); ScreenToClient(&ptMouse); memDC.MoveTo(rcClient.left, ptMouse.y); memDC.LineTo(rcClient.right, ptMouse.y); memDC.MoveTo(ptMouse.x, rcClient.top); memDC.LineTo(ptMouse.x, rcClient.bottom); } pDC->BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memDC, 0, 0, SRCCOPY); memDC.SelectObject(pOldBitmap); }} memDC.FillRect(rcClient, &CBrush(clrBk));不能重画背景 用CBitmap类是你在画的时候要在dc上画一幅图片也可以理解直接在dc画位图,CBitmap类实际就是HBITMAP,mfc将这个HBITMAP句柄抽象成一个类的形式。不能重绘,是不是你看到的是白色的内容啊,如果是白色的内容,可能是我的背景画刷设置的是白色,你那m_clrBk的颜色改一下看看,可能是因为这个原因吧。 写错了COLORREF clrBk = pDC->GetBkColor();memDC.FillRect(rcClient, &CBrush(clrBk));这句话是获取默认的背景颜色,你用clrBk = RGB(255, 0, 0)看看是否重绘背景了。 pDC->BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memDC, 0, 0, SRCCOPY);绘图完毕后,这个应该是吧绘制的图拷贝到屏幕上吧?我感觉我主要是因为没处理好WM_SIZE事件,其实我根本就没处理 int CXXWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){ if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; BITMAP bitinfo; m_bitmap.LoadBitmap(IDB_XXX); // 加载图片资源 m_bitmap.GetBitmap(&bitinfo); m_szImage = CSize(bitinfo.bmWidth, bitinfo.bmHeight); return 0;}void CXXWnd::DrawCross(CDC* pDC){ ASSERT(pDC); // 这里用双缓冲 CDC memDC1, memDC2; CBitmap bitmap, *pOldBitmap1 = NULL, *pOldBitmap2 = NULL; CPen pen(PS_SOLID, 2, RGB(255, 0, 0)), *pOldPen = NULL; CRect rcClient; GetClientRect(rcClient); if ( memDC1.CreateCompatibleDC(pDC) && memDC2.CreateCompatibleDC(pDC) && bitmap.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height()) ) { // 选入背景资源的内存DC pOldBitmap1 = memDC1.SelectObject(&m_bitmap); // 完整内容的内存DC pOldBitmap2 = memDC2.SelectObject(&bitmap); pOldPen = memDC2.SelectObject(&pen); memDC2.StretchBlt(0, 0, rcClient.Width(), rcClient.Height(), &memDC1, 0, 0, m_szImage.cx, m_szImage.cy, SRCCOPY); if ( m_bOpenDrawCross && m_bMouseIn ) { CPoint ptMouse; GetCursorPos(&ptMouse); ScreenToClient(&ptMouse); memDC2.MoveTo(rcClient.left, ptMouse.y); memDC2.LineTo(rcClient.right, ptMouse.y); memDC2.MoveTo(ptMouse.x, rcClient.top); memDC2.LineTo(ptMouse.x, rcClient.bottom); } pDC->BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memDC2, 0, 0, SRCCOPY); memDC2.SelectObject(pOldPen); memDC2.SelectObject(pOldBitmap2); memDC1.SelectObject(pOldBitmap1); }} 学到了很多东西,hahaking119,你把下面的代码复制到你的程序中试试afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); ON_WM_GETMINMAXINFO() void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { // TODO: Add your message handler code here and/or call default lpMMI->ptMinTrackSize.x = 640 ; lpMMI->ptMinTrackSize.y = 456 ; CFrameWnd::OnGetMinMaxInfo(lpMMI); } 如果不处理背景图重绘,那么你画是十字线就无法用在背景图上实现,因为你十字线在你鼠标移动的时候是会发生变化的,这样毕竟在背景中的位置会发生改变,还有如果你鼠标位置不发生改变,那么就不会产生ON_MOUSEMOVE消息,也就不会重绘。个人觉得重绘不会太影响效率。你减少重绘量好像不容易实现,你可以试试。 MFC的小问题,关于TEXTDRAW函数的。 请问关于VC的调试问题 想问关于VC++2005的一个小问题 C++和VC 进来看看啊,非常有趣的网站!!! 为什么我用CTreeCtrl时得不到鼠标点击的Item的handle? 一个有关调试的问题 MS HTML 帮助制作工具问题:为什么我的图片不能总是嵌进去,有时能,有时不能。 clistctrl用图片增大行高后,其中的COMBOX控件下拉选项为什么不显示了?该如何解决啊?请教各位!!十分感谢 为什么我打印预览时每页的内容都相同 如何将将注册表中的数据转换成CString? 快来看看,很神奇的结果
ON_WM_GETMINMAXINFO()void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
// TODO: Add your message handler code here and/or call default
lpMMI->ptMinTrackSize.x = 640 ;
lpMMI->ptMinTrackSize.y = 456 ;
CFrameWnd::OnGetMinMaxInfo(lpMMI);
}
OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CDC* pDC = GetDC(); if(m_rectCross.PtInRect(point))
{
if(m_bDispCross)
{
if(m_rectCross.PtInRect(m_ptCrossLast) && m_bNeedEraseCross)
DrawSelectCross(pDC, m_ptCrossLast);
m_bNeedEraseCross = FALSE;
m_bDispCross = FALSE; ReleaseCapture();
}
else
{
//DrawSelectCross(pDC, m_ptCrossLast);
DrawSelectCross(pDC, point);
m_bDispCross = TRUE;
m_bNeedEraseCross = TRUE;
m_ptCrossLast = point; SetCapture( );
}
}
ReleaseDC(pDC);
CView::OnLButtonDblClk(nFlags, point);
}
schlafenhamster:那个画十字就是跟随鼠标的
{
// TODO: add construction code here
m_rectCross.left=60;
m_rectCross.right=360;// 当窗口right小于时,cross就不擦除了!
m_rectCross.top=60;
m_rectCross.bottom=160;
m_bDispCross=TRUE;
}
{
// TODO: Add your message handler code here and/or call default
lpMMI->ptMinTrackSize.x = 220 ;
lpMMI->ptMinTrackSize.y = 320 ;
CFrameWnd::OnGetMinMaxInfo(lpMMI);
}
//是这个吗?
关键是鼠标不能落在绘图区域内!
{
// TODO: add construction code here
m_rectCross.left=20;
m_rectCross.right=60;
m_rectCross.top=60;
m_rectCross.bottom=160;
m_bDispCross=TRUE;
}
//试试再也不会留cross了!
void CXxxxView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
if(cx==0) return;
m_rectCross.right=cx-20;//Only horizondle processed
// afxDump << cx << "," << cy <<"\n";
// TODO: Add your message handler code here
}
{
DECLARE_DYNAMIC(CXXWnd)public:
CXXWnd();
virtual ~CXXWnd();public:
BOOL m_bMouseIn;
BOOL m_bOpenDrawCross;protected:
void DrawCross(CDC* pDC);protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
public:
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnPaint();
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
};// TransparentWnd.cpp : implementation file
//#include "stdafx.h"
#include "XXWnd.h"
// CXXWndIMPLEMENT_DYNAMIC(CXXWnd, CWnd)CXXWnd::CXXWnd()
{
m_bMouseIn = FALSE;
m_bOpenDrawCross = FALSE;
}CXXWnd::~CXXWnd()
{
}
BEGIN_MESSAGE_MAP(CTransparentWnd, CWnd)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_LBUTTONDBLCLK()
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSELEAVE, &CXXWnd::OnMouseLeave)
END_MESSAGE_MAP()// CXXWndmessage handlersBOOL CXXWnd::PreCreateWindow(CREATESTRUCT& cs)
{
return CWnd::PreCreateWindow(cs);
}int CXXWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}void CXXWnd::OnPaint() // 视图在OnDraw中处理
{
CPaintDC dc(this); // device context for painting
DrawCross(&dc);
}void CXXWnd::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CWnd::OnLButtonDblClk(nFlags, point);
m_bOpenDrawCross = !m_bOpenDrawCross;
Invalidate();
}void CXXWnd::OnMouseMove(UINT nFlags, CPoint point)
{
CWnd::OnMouseMove(nFlags, point);
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE;
::TrackMouseEvent(&tme);
m_bMouseIn = TRUE;
Invalidate();
}LRESULT CXXWnd::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
m_bMouseIn = FALSE;
Invalidate();
return TRUE;
}void CXXWnd::DrawCross(CDC* pDC)
{
ASSERT(pDC);
CDC memDC;
CBitmap bitmap, *pOldBitmap = NULL;
CRect rcClient;
GetClientRect(rcClient);
if ( memDC.CreateCompatibleDC(pDC) && bitmap.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height()) )
{
pOldBitmap = memDC.SelectObject(&bitmap);
COLORREF clrBk = pDC->GetBkColor();
memDC.FillRect(rcClient, &CBrush(clrBk));
if ( m_bOpenDrawCross && m_bMouseIn )
{
CPoint ptMouse;
GetCursorPos(&ptMouse);
ScreenToClient(&ptMouse);
memDC.MoveTo(rcClient.left, ptMouse.y);
memDC.LineTo(rcClient.right, ptMouse.y);
memDC.MoveTo(ptMouse.x, rcClient.top);
memDC.LineTo(ptMouse.x, rcClient.bottom);
}
pDC->BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memDC, 0, 0, SRCCOPY);
memDC.SelectObject(pOldBitmap);
}
}
不能重画背景
memDC.FillRect(rcClient, &CBrush(clrBk));这句话是获取默认的背景颜色,你用clrBk = RGB(255, 0, 0)看看是否重绘背景了。
绘图完毕后,这个应该是吧绘制的图拷贝到屏幕上吧?
我感觉我主要是因为没处理好WM_SIZE事件,其实我根本就没处理
int CXXWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
BITMAP bitinfo;
m_bitmap.LoadBitmap(IDB_XXX); // 加载图片资源
m_bitmap.GetBitmap(&bitinfo);
m_szImage = CSize(bitinfo.bmWidth, bitinfo.bmHeight);
return 0;
}void CXXWnd::DrawCross(CDC* pDC)
{
ASSERT(pDC);
// 这里用双缓冲
CDC memDC1, memDC2;
CBitmap bitmap, *pOldBitmap1 = NULL, *pOldBitmap2 = NULL;
CPen pen(PS_SOLID, 2, RGB(255, 0, 0)), *pOldPen = NULL;
CRect rcClient;
GetClientRect(rcClient);
if ( memDC1.CreateCompatibleDC(pDC)
&& memDC2.CreateCompatibleDC(pDC)
&& bitmap.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height()) )
{
// 选入背景资源的内存DC
pOldBitmap1 = memDC1.SelectObject(&m_bitmap);
// 完整内容的内存DC
pOldBitmap2 = memDC2.SelectObject(&bitmap);
pOldPen = memDC2.SelectObject(&pen);
memDC2.StretchBlt(0, 0, rcClient.Width(), rcClient.Height(), &memDC1, 0, 0, m_szImage.cx, m_szImage.cy, SRCCOPY);
if ( m_bOpenDrawCross && m_bMouseIn )
{
CPoint ptMouse;
GetCursorPos(&ptMouse);
ScreenToClient(&ptMouse);
memDC2.MoveTo(rcClient.left, ptMouse.y);
memDC2.LineTo(rcClient.right, ptMouse.y);
memDC2.MoveTo(ptMouse.x, rcClient.top);
memDC2.LineTo(ptMouse.x, rcClient.bottom);
}
pDC->BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memDC2, 0, 0, SRCCOPY);
memDC2.SelectObject(pOldPen);
memDC2.SelectObject(pOldBitmap2);
memDC1.SelectObject(pOldBitmap1);
}
}
afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI);
ON_WM_GETMINMAXINFO() void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
// TODO: Add your message handler code here and/or call default
lpMMI->ptMinTrackSize.x = 640 ;
lpMMI->ptMinTrackSize.y = 456 ;
CFrameWnd::OnGetMinMaxInfo(lpMMI);
}
如果不处理背景图重绘,那么你画是十字线就无法用在背景图上实现,因为你十字线在你鼠标移动的时候是会发生变化的,这样毕竟在背景中的位置会发生改变,还有如果你鼠标位置不发生改变,那么就不会产生ON_MOUSEMOVE消息,也就不会重绘。个人觉得重绘不会太影响效率。你减少重绘量好像不容易实现,你可以试试。