在VB中,我可以通過創(chuàng)建一個圖像控件來顯示一個JPG或GIF文件,但是我如何在我的MFC應(yīng)用程序中顯示一個JGP文件呢? 許多讀者 好問題!有時使用VB的程序員覺得這個很容易。只要往你的表中拖入一個圖像控件,然后你就可以往下做了……然而C++程序員就不得不感到煩惱和頭疼。那我 們要做些什么呢,編寫我們自己的JPG解壓函數(shù)嗎?
當(dāng)然不是這樣的!事實上,C/C++程序員能夠使用與VB程序員所使用的非常類似(可以說是差不多)的圖像控件。我并沒有開玩笑。VB圖像控件 是基于一個叫"IPicture"的系統(tǒng)COM類(如 Figure 1 所示)。IPicture管理一個圖像對象和它的特性。圖像對象為位圖提供一個抽象化的東西。Windows提供 了一個知道如何處理BMP,JPG和GIF位圖的標(biāo)準(zhǔn)操作。你所要做的只是使IPicture實例化,并調(diào)用Render。你可以調(diào)用一個叫 做"OleLoadPicture"的特殊函數(shù),來替代通常所要調(diào)用的"CoCreateInstance"。 IStream* pstm = // 需要一個信息流 IPicture* pIPicture; hr = OleLoadPicture(pstm, 0, FALSE, IID_IPicture, (void**)&pIPicture); OleLoadPicture從信息流里加載圖像,并創(chuàng)建一個你能夠用來顯示圖像的新的IPicture對象。 rc = // 要在其中顯示的矩形 // 轉(zhuǎn)換rc為HIMETRIC spIPicture->Render(pDC, rc); IPicture包攬了所有的令人厭煩的用來推算圖像是否是Windows位圖,JPEG,或GIF文件的事, 它甚至還可以推算圖像是否是圖標(biāo)和圖元文件!自然,其中的細(xì)節(jié)是需要些技巧,所以我就寫了一個將它們都包含其中的叫"ImgView"( 如 Figure 2 所示)的演示程序。
Figure 2 ImgView
ImgView是一個典型的MFC文檔/視圖結(jié)構(gòu)的應(yīng)用程序,它使用了一個我以前寫的叫"CPicture"的類(如 Figure 3 所示)來封裝IPicture。CPicture將一些麻煩的COM類型的參數(shù)映射為那些更容易被MFC程序員接 受的類型。例如,CPicture可以讓你直接從一個文件名加載圖像,如CFile或CArchive,而不是處理信息流;而且 CPicture::Render完成了所有的令人厭煩的而又是IPicture所需要的HIMETRIC坐標(biāo)轉(zhuǎn)換,這樣,你就沒必要去做這些了。 CPicture甚至還有一個可以從你的資源數(shù)據(jù)中加載圖像的加載函數(shù),所以要顯示一個資源圖像,你所要做的就是像下面那樣寫:
CPicture pic(ID_MYPIC); // 加載pic CRect rc(0,0,0,0); // 使用默認(rèn) rc pic.Render(pDC, rc); // 顯示它 什么能夠使工作變得更加容易呢?CPicture::Render能獲得一個你想在其中顯示圖像的矩形。IPicture可以適當(dāng)?shù)乩靾D像。 如果你傳遞了一個空的矩形,CPicture就使用圖像本來的尺寸,并不對其進(jìn)行拉伸。對于圖像本身,CPicture要尋找一個名為"IMAGE"的資 源類型,所以你必須對你的RC文件進(jìn)行如下的編寫: IDR_MYPIC IMAGE MOVEABLE PURE "res\MyPic.jpg" 總的來說,CPicture相當(dāng)沒頭腦。它有一個ATL CComQIPtr巧妙的指向 IPicture界面的指針,其中不同的加載函數(shù)通過調(diào)用OleLoadPicture來初始化該界面。CPicture提供一般的封裝函數(shù)來調(diào)用里面的 IPicture。CPicture僅封裝了我編寫ImgView所需要的IPicture成員函數(shù);這么做是因為我是這樣的一個懶惰的程序員。如果你還 需要調(diào)用IPicture::get_Handle或一些其它的較少用的IPicture成員函數(shù),很抱歉,你就只好自己為其添加封裝了。至少,這代碼是 件瑣碎的事情。 順便說一下,在我寫完CPicture后,我就覺得有件事要提一下,那就是我發(fā)現(xiàn)一個鮮為人知的叫 做"CPictureHolder"的MFC類也做了絕大部分的類似的事情。你可以在afxctl.h中找到它。 正如我先前提到的,ImgView是一個典型的MFC文檔/視圖結(jié)構(gòu)的應(yīng)用程序,其中 CPictureDoc和CPictureView類分別對應(yīng)于文檔和視圖結(jié)構(gòu)。如 Figure 4 所示 中顯示了該視圖。CPictureDoc有些瑣碎;它使用CPicture來保存圖像-- class CPictureDoc : public CDocument { protected: CPicture m_pict; // 圖像 }; ,并且CPictureDoc::Serialize調(diào)用CPicture:oad從MFC所建立的存檔中讀取圖像。 void CPictureDoc::Serialize(CArchive& ar) { if (ar.IsLoading()) { m_pict.Load(ar); } } 僅僅是為了有趣,CPictureDoc::OnNewDocument從程序的資源數(shù)據(jù)中加載了一張漂亮的NASA圖像。為了顯示這圖 像,CPictureView::OnDraw調(diào)用了CPicture::Render。 void CPictureView::OnDraw(CDC* pDC) { CPictureDoc* pDoc = GetDocument(); CPicture* ppic = pDoc->GetPicture(); CRect rc; GetImageRect(rc); ppic->Render(pDC,rc); } GetImageRect是CPictureView的一個函數(shù),它依靠當(dāng)前ImgView縮放比例而返回一個適當(dāng)?shù)膱D像矩形。(ImgView可以 通過25%,33%,50%,75%,100%或"自適應(yīng)比例"這六種比例形式來顯示圖像)。GetImageRect調(diào)用 CPicture::GetImageSize獲得真實的圖像尺寸,隨后依據(jù)比例適當(dāng)?shù)乜s放。 現(xiàn)在,在CPictureView中剩下的就是典型的CScrollView部分,其中有用于視的初始化和 滾動條尺寸與句柄命令的設(shè)置之類的代碼。對于IPicture唯一有意思的是,正如之前我所提到的,IPicture::Render希望它的坐標(biāo)是 HIMETRIC單位的,然而一般的MFC應(yīng)用程序使用的是默認(rèn)的MM_TEXT映射模式。不要擔(dān)心,CPicture::Render和 CPicture::GetImageSize對其做了魔術(shù)般的轉(zhuǎn)換,所以你就沒必要為這樣世俗的和令人厭煩的瑣事而操過多的心了。 CPictureView有一個消息處理函數(shù)值得注意,它就是OnEraseBkgnd。它被要求在圖像比 視的客戶區(qū)小的情況時對空白的區(qū)域進(jìn)行填充(如圖5所示)。OnEraseBkgnd創(chuàng)建一個與圖像大小一樣的剪切的矩形,然后將客戶矩形填充為黑色。當(dāng) 你變化窗口尺寸的時候,這樣的剪切就避免了閃爍,其中的FillRect并沒有往被剪切的矩形中填充。這是標(biāo)準(zhǔn)的Windows圖形101。
圖 5 OnEraseBkgnd填充被剪切的圖像
IPicture/CPicture真正使得顯示圖像變得容易了。它甚至可以完成調(diào)色板的實現(xiàn)和所有令人厭煩的事情。你可以丟掉原先所有的用來加載調(diào) 色板,BitBlts和StretchBlts等的DIB的繪圖代碼了,IPicture是個很好的辦法。如果你還沒有使用IPicture來顯示圖像, 那么現(xiàn)在就開始用它吧! 所有的事情都是這么的簡單,這讓我想寫另一個類來試試。當(dāng)你想寫一個圖像瀏覽器 時,CPictureView是很好用的,但要是你想將一個圖像加到對話框或其它的一些窗口上,那該怎么辦呢?為了實現(xiàn)這,我寫了另一個 類,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(); } 這里假設(shè)在你的對話框中有一個靜態(tài)控件,它的ID是IDC_IMAGE,同時還有一個具有相同ID的IMAGE資源。我從我那很常用的 CStaticLink中派生了CPictureCtrl,這樣,如果你想的話就可以聲明一個URL超鏈接了(或僅僅創(chuàng)建一個與控件和圖像具有相同ID的 字符串資源)。如果你聲明了一個URL,在這圖像上點擊鼠標(biāo)將啟動你的瀏覽器并實現(xiàn)這個鏈接。令人驚奇的是,CPicture保存了一個CPicture 對象,并通過重載WM_PAINT來調(diào)用CPicture::Render,而不是通過一般的靜態(tài)控件。要想了解更多的細(xì)節(jié),可從本文開始處的鏈接下載源 文件,使用它吧,我祝福你!
使用 cppqa@microsoft.com 發(fā)送你的問題和評論給 Paul
|