WTL:如何利用滚动窗口ScrollWnd查看图片Image

这个问题说起来简单,做起来难。

虽然说是WTL,但我想MFC应该没有太大差别。

关键点:ScrollWindow,MoveWindow。

首先看ScrollWnd。

class ScrollWnd : public CWindowImpl<ScrollWnd,CWindow>  //MFC中直接继承CWnd,WTL的精髓就是模板
{
private:
	const int LINE;  //定义移动的距离
public:
	BEGIN_MSG_MAP(ScrollWnd)
		MSG_WM_VSCROLL(OnVScroll)
		MSG_WM_HSCROLL(OnHScroll)
	END_MSG_MAP()
public:
	ScrollWnd() : LINE(12) {  }
	void OnVScroll(UINT nSBCode,UINT,CScrollBar)
	{
		SCROLLINFO sif = { sizeof(SCROLLINFO),SIF_ALL };
		GetScrollInfo(SB_VERT,&sif);

		int oldPos = sif.nPos;
		switch(nSBCode)
		{
		case SB_TOP:	sif.nPos = sif.nMin;	break;
		case SB_BOTTOM:	sif.nPos = sif.nMax;	break;
		case SB_LINEUP:		sif.nPos -= LINE;	break;
		case SB_LINEDOWN:	sif.nPos += LINE;	break;
		case SB_PAGEUP:		sif.nPos -= sif.nPage;	break;
		case SB_PAGEDOWN:	sif.nPos += sif.nPage;	break;
		case SB_THUMBTRACK:	sif.nPos = sif.nTrackPos;	break;
		default:	break;
		}
		if(sif.nPos > sif.nMax)
			sif.nPos = sif.nMax;
		else if(sif.nPos < sif.nMin)
			sif.nPos = sif.nMin;
		sif.fMask = SIF_POS;
		SetScrollInfo(SB_VERT,&sif);

		GetScrollInfo(SB_VERT,&sif);
		if(sif.nPos != oldPos)
			ScrollWindow(0,oldPos - sif.nPos);	//这里是重点
	}
	void OnHScroll(UINT nSBCode,UINT,CScrollBar)
	{
		SCROLLINFO sif = { sizeof(SCROLLINFO),SIF_ALL };
		GetScrollInfo(SB_HORZ,&sif);

		int oldPos = sif.nPos;
		switch(nSBCode)
		{
		case SB_LEFT:	sif.nPos = sif.nMin;	break;
		case SB_RIGHT:	sif.nPos = sif.nMax;	break;
		case SB_LINELEFT:	sif.nPos -= LINE;	break;
		case SB_LINERIGHT:	sif.nPos += LINE;	break;
		case SB_PAGELEFT:	sif.nPos -= sif.nPage;	break;
		case SB_PAGERIGHT:	sif.nPos += sif.nPage;	break;
		case SB_THUMBTRACK:	sif.nPos = sif.nTrackPos;	break;
		default:	break;
		}
		if(sif.nPos > sif.nMax)
			sif.nPos = sif.nMax;
		else if(sif.nPos < sif.nMin)
			sif.nPos = sif.nMin;
		sif.fMask = SIF_POS;
		SetScrollInfo(SB_HORZ,&sif);

		GetScrollInfo(SB_HORZ,&sif);
		if(sif.nPos != oldPos)
			ScrollWindow(oldPos - sif.nPos,0);
	}
	void ResetThumbHeight(HWND wndChild)
	{
		SCROLLINFO sif = { sizeof(SCROLLINFO),SIF_ALL }, sif2 = sif;
		GetScrollInfo(SB_VERT,&sif);	GetScrollInfo(SB_HORZ,&sif2);

		CRect rc_client,rc_child;
		::GetWindowRect(wndChild,&rc_child);
		GetClientRect(&rc_client);

		if(rc_client.Height() >= rc_child.Height())	//不需要垂直滚动条的情况
		{
			ShowScrollBar(SB_VERT,FALSE);
			::SetWindowPos(wndChild,NULL,0,0,rc_client.Width(),rc_child.Height(),SWP_NOMOVE);
			return;
		}

		if(rc_client.Width() >= rc_child.Width())	//不需要水平滚动条的情况
		{
			ShowScrollBar(SB_HORZ,FALSE);
			::SetWindowPos(wndChild,NULL,0,0,rc_client.Width(),rc_child.Height(),SWP_NOMOVE);
			return;
		}

		sif.nPage = rc_client.Height();		sif2.nPage = rc_client.Width();
		sif.nMin = 0;						sif2.nMin = 0;
		sif.nMax = rc_child.Height();		sif2.nMax = rc_child.Width();
		sif.nPos = 0;						sif2.nPos = 0;

		SetScrollInfo(SB_VERT,&sif);		SetScrollInfo(SB_HORZ,&sif2);
	}
};

不知道为什么,添加MOUSEWHEEL消息却一直不响应,所以此处就略去了。

下面是ImageCtrl:

 采用gdi+绘制图片。记得ERASEBKGND返回TRUE

class ImageCtrl : public CWindowImpl<ImageCtrl>
{
private:
	CString m_strImagePath;
public:
	BEGIN_MSG_MAP(ImageCtrl)
		MSG_WM_PAINT(OnPaint)
	END_MSG_MAP()
public:
	ImageCtrl()
	{
		m_strImagePath = L"";
	}
	void DrawImage(CString str_image_path)
	{
		m_strImagePath = str_image_path;
		RedrawWindow();
	}
	void OnPaint(CDCHandle)
	{	
		CPaintDC dc(m_hWnd);
		if(m_strImagePath.IsEmpty())
			return;
		CRect rc;		GetClientRect(&rc);
		Graphics g(dc);
		Image img(m_strImagePath)
		g.DrawImage(&img,0,0,rc.Width(),rc.Height());	
	}
};

使用方法:

ScrollWnd scrWnd;

scrWnd.Create(m_hWnd,CRect(26,72,494,319),NULL,WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL);

Image img(L"res/3qqq.png");

ImageCtrl icc;
icc.Create(scrWnd.m_hWnd,CRect(0,0,img.GetWidth(),img.GetHeight()),NULL,WS_CHILD|WS_VISIBLE);
icc.DrawImage(L"res/3qqq.png"););
   

scrWnd.ResetThumbHeight(icc.m_hWnd);

总结:其实,可以这么来思考。我们有一块布ImageCtrl,有很多幅画,任意选择一幅,然后调整布的大小和画一样,把画放到布上去。ScrollWnd就是一个相框,我们把布塞到相框里面,通过上下左右设定布显示区域。其实布的移动是最困扰我们的,我最初以为要自己移动,结果发现ScrollWnd的ScrollWindow已经帮我们做好了,因为ImageCtrl是他的子窗口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章