分享

在你的MFC应用程序中显示一个JPG文件 - VC知识 - 界面程序资源 - DirectUI Skin UIPower专业界面开发与设计论坛 软件界面|界面开发 - Powered by Dis

 unununy 2010-03-21



      
      

在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:oad从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. 网站和 Paul 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多