程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 在你的MFC應用程序中顯示一個JPG文件

在你的MFC應用程序中顯示一個JPG文件

編輯:關於VC++

在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,而不是通過一般的靜態控件。要想了解更多的細節,可從本文開始處的鏈接下載源文件,使用它吧,我祝福你!

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved