在用VC开发应用程序的时候,经常要在对话框上显示位图。如果把位图加入资源中,当然是省时省力,但程序却也增肥不少,并且失去了灵活性。而如果你要动态地显示一大堆图片,各个图片大小不一,这岂不…本文就是介绍如何在对话框上显示位图,并且如何让对话框自动适应位图的大小的。
---- VC对位图的操作比较烦琐,要显示一个位图到对话框上去,很麻烦。我在开发的过程中走通了两条路:一是使用Kodak图象编辑控件;二是利用Microsoft提供的例子中的一个类,并稍加改造。两种方法各有优缺点。我把它写下来,以避免其他人多走弯路。
一、利用控件
利用 WINDOWS98中带的Kodak图象编辑控件来在对话框上显示一个位图,虽然有点儿杀鸡用牛刀的感觉,但却不失为一个极方便快捷的方法。顾名思义,这个控件不但可以显示,它更强大的功能还是在编辑图象,它可以对图象进行放大、缩小、标注等操作。而且,使用起来很方便。但它毕竟是别人的东东,不太清楚它的底细,用起来就不免…我就吃了它的苦头。在本机上调试通过,安装了其他几台机器也很正常,但是有一台却颜色失真了,变成了水粉画。不知是不是那台机器的显卡有问题。还有就是据我初步实验,在95下好象行不通。不过现在大家都是WIN98,这似乎已经不算一个问题了。下面就把我的过程写下来:
首先应该保证系统中有这个控件。注意,它不能单独使用,必须和其他几个控件(特别是Imgcmn.dll)一同使用。如果没有,从别的机器上copy过来即可。这几个文件是Imgadmin.ocx,Imgcmn.dll,Imgedit.ocx,Imgscan.ocx,Imgshl.dll,Imgthumb.ocx,Imgutil.dll,把它们copy到 windows\system目录下,然后用regsvr32.exe将它们分别注册。
打开VC,新建一个基于对话框的工程(主要是为了说明方便),删除掉对话框上其他的东西(按钮和LABEL),在对话框上单击右键,单击Insert Activex control… 选择Kodak图象编辑控件,大小任意。
在对话框上选中该控件,打开view|classwizard,单击Member Variables,点击Add Variable…按钮,系统会弹出一个对话框,大体上是提示你它要把控件加入工程中了,确定即可。在接下来的对话框上继续点击OK,此时,会出现一个对话框,提示你输入变量名,输入你想要的名字即可。我们输入m_ctrlPicture。单击确定。
此时你的工程中已经有了一个名字为m_ctrlPicture的控件,接下来就可以利用它来显示图片了,我们把它加到对话框的初始化中。单击ClassWizard,选择OnInitDialog,单击Edit Code按钮。
在OnInitDialog中,找到// TODO: Add extra initialization here,在下面加入如下代码:
m_ctrlPicture.SetImage("c:\\ windows\Clouds.bmp");
m_ctrlPicture.Display();
编译运行,看到了吗?就这么简单。
但是它的大小却是固定的,要看全图只能利用滚动条。下面我们再来得到图象的尺寸,然后使对话框自动适应图象的大小。还是在初始化中,代码如下:
m_ctrlPicture.SetImage("c:\\ windows\\Clouds.bmp");
const int nAddConst=40;
//图象尺寸不会正合适,需要加点增量。
long lPictureWidth=m_ctrlPicture.GetImageWidth();
long lPictureHeight=m_ctrlPicture.GetImageHeight();
MoveWindow(0,0,lPictureWidth,lPictureHeight,true);
//改变对话框大小
//改变控件的大小
m_ctrlPicture.MoveWindow(0,0,lPictureWidth,
lPictureHeight+nAddConst,true);
m_ctrlPicture.Display();
成功了。
注意,这个控件不但只能显示bmp,还可显示许多其他的格式,你可以自己试一下。
二、利用Cdib类
这个方法比较烦琐,并且只能显示bmp,但它不依赖特定的系统,也比较实用。这个类在MSDN提供的例子中有,名字为ex10c.dsw,找到cdib.cpp和cdib.h,加入你的工程即可。如果你找不到,也可以到我的网页去看看http://dlgis.topcool.net或者给我写信ytdl@263.net。
---- 下面是过程:
新建一个基于对话框的工程,单击Add Files to Project,加入上面所说的两个文件。
在对话框的头文件中加入#include "cdib.h",然后给对话框类加入一个成员变量,代码如下: Cdib m_dibFile;
在对话框的初始化函数中,加入如下代码:
#ifdef MEMORY_MAPPED_FILES
if (m_dibFile.AttachMapFile
("c:\\ windows\\clouds.bmp",TRUE)==TRUE)
{ // share
Invalidate();
}
#else
CFile file;
file.Open("c:\\ windows\\clouds.bmp",
Cfile::modeRead);
if (m_dibFile.Read(&file) == TRUE)
{
Invalidate();
}
#endif // MEMORY_MAPPED_FILES
CClientDC dc(this);
m_dibFile.SetSystemPalette(&dc);
BeginWaitCursor();
m_dibFile.UsePalette(GetDC());
CSize sizeFileDib = m_dibFile.GetDimensions();
m_dibFile.Draw(GetDC() ,CPoint(0,0), sizeFileDib);
EndWaitCursor();
运行程序,是不是看到蓝天白云了?!下面继续加入让对话框自动适应图片大小的代码,还是在初始化中,紧接这上一次的代码,加入如下两行:
CSize sizeFileDib = m_dibFile.GetDimensions();
MoveWindow(0,0,sizeFileDib.cx,sizeFileDib.cy,true);
(3)书籍标准版
在OnPaint()中加入以下代码 //在对话框中直接显示图像 BITMAP bm; CBitmap bmp;//定义CBitmap 类的对象 bmp.LoadBitmap(IDB_BITMAP1);//装入ID号为IDB_BITMAP1的位图 CDC memdc;//定义CDC类的对象 CRect rect; memdc.CreateCompatibleDC(&dc);//创建与显示DC相兼容的内存DC bmp.GetBitmap(&bm); CBitmap *bmpold=memdc.SelectObject(&bmp);//将选定的位图选入内存DC this->GetClientRect(&rect); //从内存DC向显示DC复制,rect.left,rect.top为图像左上角的坐标,SRCCOPY表示直接将源位图拷贝到目的位图,不作修改 dc.BitBlt(rect.left,rect.top,bm.bmWidth,bm.bmHeight,&memdc,0,0,SRCCOPY); memdc.SelectObject(bmpold); memdc.DeleteDC(); bmp.DeleteObject();(4)摘自网络
步骤/方法
-
//在对话框内显示位图
CBitmap hbmp;
HBITMAP hbitmap;
//装载图片文件MM.bmp
hbitmap=(HBITMAP)::LoadImage(::AfxGetInstanceHandle(),"MM.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
hbmp.Attach(hbitmap);
//获取图片格式
BITMAP bm;
hbmp.GetBitmap(&bm);
CDC dcMem;
dcMem.CreateCompatibleDC(GetDC());
CBitmap * poldBitmap=(CBitmap*)dcMem.SelectObject(hbmp);
CRect lRect;
GetClientRect(&lRect);
lRect.NormalizeRect();
//显示位图
-
GetDC()->StretchBlt(lRect.left,lRect.top,lRect.Width(),lRect.Height(),&dcMem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
dcMem.SelectObject(&poldBitmap);
//在Static控件内显示位图
CBitmap hbmp;
HBITMAP hbitmap;
//将pStatic指向要显示的地方
CStatic *pStatic;
pStatic=(CStatic*)GetDlgItem(IDC_STATIC); //IDC_STATIC是你的Staic控件名
//装载图片文件MM.bmp
hbitmap=(HBITMAP)::LoadImage(::AfxGetInstanceHandle(),"MM.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
hbmp.Attach(hbitmap);
-
//获取图片格式
BITMAP bm;
hbmp.GetBitmap(&bm);
CDC dcMem;
dcMem.CreateCompatibleDC(GetDC());
CBitmap * poldBitmap=(CBitmap*)dcMem.SelectObject(hbmp);
CRect lRect;
pStatic->GetClientRect(&lRect);
lRect.NormalizeRect();
//显示位图
pStatic->GetDC()->StretchBlt(lRect.left,lRect.top,lRect.Width(),lRect.Height(),&dcMem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
dcMem.SelectObject(&poldBitmap);
//弄了半天终于是picturecontrol上能显示位图了,离逻辑bitblt还远
void Ctest1Dlg::OnStnClickedPic()
{ HBITMAP hBitmap;
//获得指向静态控件的指针
CStatic *pStatic=(CStatic *)GetDlgItem(IDC_PIC);
//获得位图句柄
hBitmap = (HBITMAP)LoadImage(
AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDB_BITMAP2),
IMAGE_BITMAP,
0,
0,
LR_LOADMAP3DCOLORS);
//设置静态控件的样式,使其可以使用位图,并试位标显示使居中
pStatic->ModifyStyle(0xF,SS_BITMAP|SS_CENTERIMAGE);
//设置静态控件显示位图
pStatic->SetBitmap(hBitmap);
// TODO: Add your control notification handler code here
}
在VC中,标准的WINDOWS控件如TREEVIEW,EDITBOX,COMBOBOX和LISTBOX等控件都不支持选择背景位图的属性,所以如果要使这些标准控件达到这种效果,必须有些非常规的方法。本文介绍一个CEDIT类如何实现背景位图,并且可以更换背景的例子。可能实现的方法还有其它种,如果有兴趣可以大家探讨。
本文程序运行效果图
下面介绍CMYEDITCTRL类几个关键变量和函数。
第一步在该类中增加几个变量;
1.
public
:
2.
CBitmap m_bmp;
3.
protected
:
4.
CBrush m_brHollow;
5.
CBitmap *m_pbmCurrent;
第二步 重载部分函数:
1.
afx_msg
HBRUSH
CtlColor(CDC* pDC,
UINT
nCtlColor);
2.
afx_msg
void
OnLButtonUp(
UINT
nFlags, CPoint point);
3.
afx_msg
void
OnChange();
4.
afx_msg
BOOL
OnEraseBkgnd(CDC* pDC);
各个函数的具体作用:
2.1 OnChange();
如果没有这个函数,你敲几个字符如 ABCDEDFG,然后删除两个FG,但是EDITBOX并未更新。添加这个函数主要是这个原因。
1.
void
CMyEditCtrl::OnChange()
2.
{
3.
Invalidate();
///强制进行更新
4.
}
2.2 OnLButtonUp();
也类似,是你鼠标选择时候的刷新问题,如果你有兴趣,可以先把它注释掉,看看BUG是怎么出现的。
1.
void
CMyEditCtrl::OnLButtonUp(
UINT
nFlags, CPoint point)
2.
{
3.
Invalidate();
///强制进行更新
4.
CEdit::OnLButtonUp(nFlags, point);
5.
}
2.3 CtlColor(CDC* pDC, UINT nCtlColor)
一般的文字的默认背底是白色的,这儿选择了透明的形式,所以底图可以显示。
1.
HBRUSH
CMyEditCtrl::CtlColor(CDC* pDC,
UINT
nCtlColor)
2.
{
3.
pDC->SetBkMode(TRANSPARENT);
///选择透明背景模式
4.
pDC->SetTextColor(RGB(0xff,0xff,0xff));
///设置文字颜色为白色
5.
return
m_brHollow;
6.
}
2.4 OnEraseBkgnd(CDC* pDC)
主要把选好的背景位图显示出来。
01.
BOOL
CMyEditCtrl::OnEraseBkgnd(CDC* pDC)
02.
{
03.
BITMAP bm;
04.
m_bmp.GetBitmap(&bm);
05.
m_pbmCurrent = &m_bmp;
06.
CDC dcMem;
07.
dcMem.CreateCompatibleDC(pDC);
08.
CBitmap* pOldBitmap = dcMem.SelectObject(m_pbmCurrent);
///选择位图
09.
pDC->BitBlt(0,0,bm.bmWidth,bm.bmHeight,&dcMem,0,0,SRCCOPY);
///画出位图
10.
dcMem.SelectObject(pOldBitmap);
11.
return
TRUE;
12.
}
说明:其中代码有些部分简化了,有些部分还可以优化。对于底图的选择,在这里我选择是与我EDITBOX一样大小的底图,如果两者不一样大小,需要修改部分OnEraseBkgnd(CDC* pDC)代码。
基本上这个类的功能就这样实现了。