1.思路的产生
起初是想在一个Dialog内加载一幅图片,而这幅图片又较大,使用Dialog需要手动加滚动条,似乎比较麻烦(没有深入探究,如果大家有较方便的办法,请留言)。而CScrollView是一个自动带滚动条的窗体,于是在Dialog内嵌入一个CScrollView的想法就产生了。
2.实现过程。
关于CScrollView在Dialog内的位置,大概有两种办法确定,一种是通过获取CDialog的位置做相对变换。第二种是先在Dialog内用工具箱添加一个静态文本框控件,而这个控件的位置和大小就调整为CScrollView准备放的位置。这样就能通过较直观的方式设置CScrollView的位置了。下面就以第二种方法为例,解析一下重点代码。
//CCreateViewDlg 即为放置CScrollView的CDialog类的衍生类
//CMyView为CScrollView的衍生类
BOOL CCreateViewDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: 在此添加额外的初始化
UINT TargetCtrlID =IDC_STATIC_VIEW; //这个控件ID就是静态文本框的ID
CWnd *pWnd = this->GetDlgItem(IDC_STATIC_VIEW);
CRect RectTargetCtrl;
pWnd->GetWindowRect(&RectTargetCtrl);
this->ScreenToClient(RectTargetCtrl);
m_pView = (CMyView*)RUNTIME_CLASS(CMyView)->CreateObject();
m_pView->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW|WS_VSCROLL|WS_HSCROLL,RectTargetCtrl,this,TargetCtrlID);
m_pView->MyInit(); //对象初始化函数(自定义的)
return TRUE; // return TRUE unless you set the focus to a control
//异常: OCX属性页应返回FALSE
}
注意:
1.为什么使用m_pView = (CMyView*)RUNTIME_CLASS(CMyView)->CreateObject();
而不是使用new呢,这是因为CScrollView的构造函数是保护类的,不允许直接构造。
2.为什么我会在上面写一个MyInit()的初始化函数呢?
起初,我不是这样写的,我是将MyInit()里面的初始化内容放到了CMyView类的OnInitUpdate()函数中,结果我发现总是出现各种断言错误。最后发现,系统就根本没有调用OnInitUpdate()函数。结果我就查询了msdn。是这样描述的“Called by the framework after the view is first attached to the document, but before the view is initially displayed.”就是(该函数)在视图第一次绑定到文档后调用的,而不是在初始显示之前(调用)。(个人翻译,如果有错误请留言)。其实msdn说清楚了,Dialog类是不关联文档的,那么在Dialog类上建立的View也就不会关联文档,所以就不会调用OnInitUpdate()。
解决办法有两种:第一种,在Dialog中建立一套框架程序,将View与Doc绑定。
第二种,不使用OnInitUpdate()函数,
我就是按照第二种方法做的,个人认为第一种方法太复杂,没有多大用处。有人会问如果不调用在使用View时不调用OnInitUpdate()函数的父类会不会出错,这个问题我也时犹豫不决,毕竟OninitUpdate函数时View的初始化函数。但是目前我按第二种方法是没有问题的。
如此就将CScrollView创建了。
下面为滚动条的处理:
根据msdn对CScollView的描述“You must call either SetScrollSizes orSetScaleToFitSize before the scroll view is usable”。在ScrollView可用之前必须调用SetScrollSizes orSetScaleToFitSize ,SetScrollSizes()函数作用就是设置视图逻辑尺寸、映射模式、滚动条大小。其实这时SetScollSizes就可以放在之前说明的MyInit()或者是CMyView的构造函数里。
CMyView::CMyView()
{
CSize sizeTotal(6000, 5000);// 20 by 30 cm
CSize sizePage(sizeTotal.cx / 20, sizeTotal.cy / 20);
CSize sizeLine(sizeTotal.cx / 500, sizeTotal.cy / 500);
SetScrollSizes(MM_LOENGLISH, sizeTotal, sizePage, sizeLine); m_pdcMemory =new CDC;
m_pBitmap = new CBitmap;
}
此时CScollView对象基本就算创建完成了,可以调试运行了,此时显示的为一个对话框内部有带滚动条的View。如图
这时还有一点瑕疵,当鼠标点击View时,会出现断言错误ASSERT(pParentFrame == pDesktopWnd || pDesktopWnd->IsChild(pParentFrame))
我想这应该也是找不到父框架导致的。于是通过调试发现问题出现在OnMouseActivate相应函数中。
原函数
int CMyView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
{
// TODO:在此添加消息处理程序代码和/或调用默认值
return CScrollView::OnMouseActivate(pDesktopWnd, nHitTest, message);
}
改为
int CMyView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
{
// TODO:在此添加消息处理程序代码和/或调用默认值
return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
}
问题解决。
接下来也算个验证,就是在ScrollView内填充了一幅图。
关键代码:
void CMyView::MyInit(void)
{
BITMAP bm;
if (m_pdcMemory->GetSafeHdc() == NULL)
{
CClientDC dc(this);
OnPrepareDC(&dc);// necessary
m_pBitmap->LoadBitmap(IDB_BITMAP1);
m_pdcMemory->CreateCompatibleDC(&dc);
m_pdcMemory->SelectObject(m_pBitmap);
m_pBitmap->GetObject(sizeof(bm), &bm);
m_sizeSource.cx = bm.bmWidth;
m_sizeSource.cy = bm.bmHeight;
m_sizeDest = m_sizeSource;
dc.DPtoLP(&m_sizeDest);
}
}
void CMyView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO:在此添加绘制代码
pDC->SetStretchBltMode(COLORONCOLOR);
if(m_pdcMemory->GetSafeHdc() == NULL)
{
return ;
}
pDC->StretchBlt(0, -0, m_sizeSource.cx, -m_sizeSource.cy,
m_pdcMemory, 0, 0,
m_sizeSource.cx, m_sizeSource.cy, SRCCOPY);
}
结果
到此结束.
源码下载http://dl.dbank.com/c0x1xa09dh
(网盘)