在你的MFC应用程序中显示一个JPG文件

在你的MFC应用程序中显示一个JPG文件


原著:Paul DiLascia

翻译:flyzling



原文出处:MSDN Magazine October 2001(C++ Q&A)

原代码下载:CQA0110.exe (202KB)


在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);
  }
}
  仅仅是为了有趣,CPictureDoc::OnNewDocument从程序的资源数据中加载了一张漂亮的NASA图像。为了显示这图像,CPictureView::OnDraw调用了CPicture::Render。
void CPictureView::OnDraw(CDC* pDC)
{
  CPictureDoc* pDoc = GetDocument();
  CPicture* ppic = pDoc->GetPicture();
  CRect rc;
  GetImageRect(rc);
  ppic->Render(pDC,rc);
}
  GetImageRect是CPictureView的一个函数,它依靠当前ImgView缩放比例而返回一个适当的图像矩形。(ImgView可以通过25%,33%,50%,75%,100%或"自适应比例"这六种比例形式来显示图像)。GetImageRect调用CPicture::GetImageSize获得真实的图像尺寸,随后依据比例适当地缩放。
  现在,在CPictureView中剩下的就是典型的CScrollView部分,其中有用于视的初始化和滚动条尺寸与句柄命令的设置之类的代码。对于IPicture唯一有意思的是,正如之前我所提到的,IPicture::Render希望它的坐标是HIMETRIC单位的,然而一般的MFC应用程序使用的是默认的MM_TEXT映射模式。不要担心,CPicture::Render和CPicture::GetImageSize对其做了魔术般的转换,所以你就没必要为这样世俗的和令人厌烦的琐事而操过多的心了。
  CPictureView有一个消息处理函数值得注意,它就是OnEraseBkgnd。它被要求在图像比视的客户区小的情况时对空白的区域进行填充(如图5所示)。OnEraseBkgnd创建一个与图像大小一样的剪切的矩形,然后将客户矩形填充为黑色。当你变化窗口尺寸的时候,这样的剪切就避免了闪烁,其中的FillRect并没有往被剪切的矩形中填充。这是标准的Windows图形101。


图 5 OnEraseBkgnd填充被剪切的图像

  IPicture/CPicture真正使得显示图像变得容易了。它甚至可以完成调色板的实现和所有令人厌烦的事情。你可以丢掉原先所有的用来加载调色板,BitBlts和StretchBlts等的DIB的绘图代码了,IPicture是个很好的办法。如果你还没有使用IPicture来显示图像,那么现在就开始用它吧!
  所有的事情都是这么的简单,这让我想写另一个类来试试。当你想写一个图像浏览器时,CPictureView是很好用的,但要是你想将一个图像加到对话框或其它的一些窗口上,那该怎么办呢?为了实现这,我写了另一个类,CPictureCtrl(如 Figure 6 所示)。CPictureCtrl可以让你将一个图像作为一个子控件放在任何的对话框或窗口上。例如:
class CAboutDialog : public CDialog {
protected:
  CPictureCtrl m_wndPict;
  virtual BOOL OnInitDialog();
};
BOOL CAboutDialog::OnInitDialog()
{
  m_wndPict.SubclassDlgItem(IDC_MYIMAGE,this);
  return CDialog::OnInitDialog();
}
  这里假设在你的对话框中有一个静态控件,它的ID是IDC_IMAGE,同时还有一个具有相同ID的IMAGE资源。我从我那很常用的CStaticLink中派生了CPictureCtrl,这样,如果你想的话就可以声明一个URL超链接了(或仅仅创建一个与控件和图像具有相同ID的字符串资源)。如果你声明了一个URL,在这图像上点击鼠标将启动你的浏览器并实现这个链接。令人惊奇的是,CPicture保存了一个CPicture对象,并通过重载WM_PAINT来调用CPicture::Render,而不是通过一般的静态控件。要想了解更多的细节,可从本文开始处的链接下载源文件,使用它吧,我祝福你!

使用 cppqa@microsoft.com 发送你的问题和评论给 Paul
 
作者简介
  Paul DiLascia 是一个自由作家,顾问和 Web/UI 方面资深的设计师。他是 Windows++: Writing Reusable Windows Code in C++ (Addison-Wesley, 1992)一书的作者。你可以在 http://www.dilascia.com 网站和 Paul 联系上。
 
本文出自 MSDN MagazineOctober 2001 期刊,可通过当地 报摊获得,或者最好是 订阅
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 MFC 显示 jpg 图片可以通过以下步骤实现: 首先,需要在 MFC 应用程序添加一个 Picture Control 控件,用于显示图片。 接下来,需要导入相关的头文件,包括 "afx.h" 和 "afxwin.h"。 然后,在应用程序的消息映射,添加一个响应 Picture Control 控件更新消息的处理函数。 在该处理函数,可以使用 MFC 提供的 CImage 类来加载和显示 jpg 图片。可以使用 CImage 的 Load() 函数加载指定路径的 jpg 图片。例如,可以使用类似下面的代码加载图片: CImage image; image.Load(_T("路径/图片名.jpg")); 然后,可以使用 Picture Control 控件的 SetBitmap() 函数将加载的图片设置为要显示的位图。例如,可以使用下面的代码将图片设置为 Picture Control 控件的位图: m_pictureControl.SetBitmap(image.Detach()); 最后,应该确保在程序退出时,释放图片资源,可以在析构函数或销毁 Picture Control 控件的处理函数调用 CImage 的 Destroy() 函数释放图片资源: image.Destroy(); 通过以上步骤,就可以在 MFC 应用程序成功显示 jpg 图片了。 ### 回答2: 在MFC显示JPG图片需要使用GDI+库。 首先,需要添加GDI+的头文件和库文件: ``` #include <gdiplus.h> #pragma comment(lib,"gdiplus.lib") using namespace Gdiplus; ``` 然后,在MFC的窗口类重写OnPaint函数用于绘制图片: ``` void CYourWndClass::OnPaint() { CPaintDC dc(this); GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); Graphics graphics(dc.GetSafeHdc()); Image image(L"your_image.jpg"); // 替换为图片路径和名称 graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight()); GdiplusShutdown(gdiplusToken); } ``` 上述代码,使用`Image`类加载JPG图片,并使用`Graphics`类的`DrawImage`函数将图片绘制到窗口上。 最后,在窗口的初始化函数(如OnInitDialog调用Invalidate函数来触发窗口的重绘: ``` BOOL CYourWndClass::OnInitDialog() { CDialog::OnInitDialog(); Invalidate(); return TRUE; } ``` 以上就是使用MFC显示JPG图片的基本步骤。如果想要在其他控件显示图片,可以在对应的控件绘制函数使用相同的方法来绘制图片。 ### 回答3: 在MFC,我们可以使用CImage类来显示jpg图片。 首先,需要在程序引入相关的头文件和库,包括atlimage.h和comdef.h。 然后,我们可以创建一个CImage对象,并调用其Load函数加载jpg图片文件。例如,假设我们有一个名为image.jpgjpg图片文件,可以使用以下代码加载该图片: CImage image; image.Load(_T("image.jpg")); 接下来,我们需要将CImage对象图片绘制到显示窗口上。可以使用CDC类的相关函数来实现绘制操作。 首先,需要获取显示窗口的CDC对象。一种常见的方法是在窗口类重写OnPaint函数,然后在该函数获取CDC对象。例如: void CMyWindow::OnPaint() { CPaintDC dc(this); // 获取窗口的DC对象 // 在这里进行绘制操作 } 然后,在获取到CDC对象后,可以使用CDC的相关函数来绘制CImage对象图片。例如,可以使用CDC的BitBlt函数来实现简单的绘制操作。以下是一个示例代码: void CMyWindow::OnPaint() { CPaintDC dc(this); // 获取窗口的DC对象 // 绘制CImage对象图片 int width = image.GetWidth(); int height = image.GetHeight(); image.BitBlt(dc.GetSafeHdc(), 0, 0, width, height, 0, 0, SRCCOPY); } 在上述示例代码,我们首先获取了CImage对象的宽度和高度,并使用CDC的BitBlt函数将CImage对象图片绘制到窗口的DC对象上。 以上是一种简单的在MFC显示jpg图片的方法。当然,还有其他多种方式可以实现此功能,具体的方法可以根据实际需求进行选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值