在VB中,我可以通过创建一个图像控件来显示一个JPG或GIF文件,但是我如何在我的MFC应用程序中显示一个JGP文件呢?
好问题!有时使用VB的程序员觉得这个很容易。只要往你的表中拖入一个图像控件,然后你就可以往下做了……然而C++程序员就不得不感到烦恼和头疼。那我们要做些什么呢,编写我们自己的JPG解压函数吗?
当然不是这样的!事实上,C/C++程序员能够使用与VB程序员所使用的非常类似(可以说是差不多)的图像控件。我并没有开玩笑。VB图像控件是基于一个叫"IPicture"的系统COM类(如 Figure 1 所示)。IPicture管理一个图像对象和它的特性。图像对象为位图提供一个抽象化的东西。Windows提供了一个知道如何处理BMP,JPG和GIF位图的标准操作。你所要做的只是使IPicture实例化,并调用Render。你可以调用一个叫做"OleLoadPicture"的特殊函数,来替代通常所要调用的"CoCreateInstance"。
IStream* pstm = // 需要一个信息流
IPicture* pIPicture;
hr = OleLoadPicture(pstm, 0, FALSE,
IID_IPicture, (void**)&pIPicture);
OleLoadPicture从信息流里加载图像,并创建一个你能够用来显示图像的新的IPicture对象。
rc = // 要在其中显示的矩形
// 转换rc为HIMETRIC
spIPicture->Render(pDC, rc);
IPicture包揽了所有的令人厌烦的用来推算图像是否是Windows位图,JPEG,或GIF文件的事, 它甚至还可以推算图像是否是图标和图元文件!自然,其中的细节是需要些技巧,所以我就写了一个将它们都包含其中的叫"ImgView"( 如 Figure 2 所示)的演示程序。
Figure 2 ImgView
ImgView是一个典型的MFC文档/视图结构的应用程序,它使用了一个我以前写的叫"CPicture"的类(如 Figure 3 所示)来封装IPicture。CPicture将一些麻烦的COM类型的参数映射为那些更容易被MFC程序员接受的类型。例如,CPicture可以让你直接从一个文件名加载图像,如CFile或CArchive,而不是处理信息流;而且CPicture::Render完成了所有的令人厌烦的而又是IPicture所需要的HIMETRIC坐标转换,这样,你就没必要去做这些了。CPicture甚至还有一个可以从你的资源数据中加载图像的加载函数,所以要显示一个资源图像,你所要做的就是像下面那样写:
CPicture pic(ID_MYPIC); // 加载pic
CRect rc(0,0,0,0); // 使用默认 rc
pic.Render(pDC, rc); // 显示它
什么能够使工作变得更加容易呢?CPicture::Render能获得一个你想在其中显示图像的矩形。IPicture可以适当地拉伸图像。如果你传递了一个空的矩形,CPicture就使用图像本来的尺寸,并不对其进行拉伸。对于图像本身,CPicture要寻找一个名为"IMAGE"的资源类型,所以你必须对你的RC文件进行如下的编写:
IDR_MYPIC IMAGE MOVEABLE PURE "res\\MyPic.jpg"
总的来说,CPicture相当没头脑。它有一个ATL CComQIPtr巧妙的指向IPicture界面的指针,其中不同的加载函数通过调用OleLoadPicture来初始化该界面。CPicture提供一般的封装函数来调用里面的IPicture。CPicture仅封装了我编写ImgView所需要的IPicture成员函数;这么做是因为我是这样的一个懒惰的程序员。如果你还需要调用IPicture::get_Handle或一些其它的较少用的IPicture成员函数,很抱歉,你就只好自己为其添加封装了。至少,这代码是件琐碎的事情。
顺便说一下,在我写完CPicture后,我就觉得有件事要提一下,那就是我发现一个鲜为人知的叫做"CPictureHolder"的MFC类也做了绝大部分的类似的事情。你可以在afxctl.h中找到它。
正如我先前提到的,ImgView是一个典型的MFC文档/视图结构的应用程序,其中CPictureDoc和CPictureView类分别对应于文档和视图结构。如 Figure 4 所示 中显示了该视图。CPictureDoc有些琐碎;它使用CPicture来保存图像--
class CPictureDoc : public CDocument {
protected:
CPicture m_pict; // 图像
};
,并且CPictureDoc::Serialize调用CPicture::Load从MFC所建立的存档中读取图像。
void CPictureDoc::Serialize(CArchive& ar)
{
if (ar.IsLoading()) {
m_pict.Load(ar);
}
}