2010-07-28 126 views
3

我一直試圖在MFC中顯示一個jpg圖像,但是我無法繪製它。我是一個完整的MFC新手,一直到現在爲止我所做的一切大部分都是從我在網上找到的東西改編而來的。目前,我有這樣的:在MFC中繪製JPG

Picture.h:

#pragma once 
#include <afxwin.h> 

class Picture 
{ 
public: 
    Picture(); 

    bool load(LPCTSTR filePath); 

    bool draw(CDC* deviceContext 
      , CRect clientRect 
      , LPCRECT prcMFBounds); 

    CSize getSize(CDC* pDC); 

private: 
    LPPICTURE m_picture; 
}; 

Picture.cpp:

#include "Picture.h" 

Picture::Picture() 
    : m_picture(0) 
{ 
} 

bool Picture::load(LPCTSTR szFile) 
{ 
    HANDLE hFile = CreateFile(szFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); 
    if (hFile == INVALID_HANDLE_VALUE) 
     return false; 

    DWORD dwFileSize = GetFileSize(hFile, NULL); 
    if (dwFileSize == (DWORD)-1) 
    { 
     CloseHandle(hFile); 
     return false; 
    } 

    LPVOID pvData = NULL; 

    // alloc memory based on file size 
    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize); 
    if (hGlobal == NULL) 
    { 
     CloseHandle(hFile); 
     return false; 
    } 

    pvData = GlobalLock(hGlobal); 

    if (pvData == NULL) 
    { 
     GlobalUnlock(hGlobal); 
     CloseHandle(hFile); 
     return false; 
    } 

    DWORD dwBytesRead = 0; 

    // read file and store in global memory 
    bool bRead = ReadFile(hFile, pvData, dwFileSize, &dwBytesRead, NULL) != 0; 

    GlobalUnlock(hGlobal); 
    CloseHandle(hFile); 

    if (!bRead) 
     return false; 

    LPSTREAM pstm = NULL; 

    // create IStream* from global memory 
    HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pstm); 
    if (!(SUCCEEDED(hr))) 
    { 
     if (pstm != NULL) 
     pstm->Release(); 
     return false; 
    } 

    else if (pstm == NULL) 
     return false; 

    // Create IPicture from image file 
    if (m_picture) 
     m_picture->Release(); 

    hr = ::OleLoadPicture(pstm, dwFileSize, FALSE, IID_IPicture, (LPVOID *)&(m_picture)); 
    if (!(SUCCEEDED(hr))) 
    { 
     pstm->Release(); 
     return false; 
    } 

    else if (m_picture == NULL) 
    { 
     pstm->Release(); 
     return false; 
    } 
    pstm->Release(); 

    return true; 
} 

bool Picture::draw(CDC* deviceContext, CRect clientRect, LPCRECT prcMFBounds) 
{ 
    if (clientRect.IsRectNull()) 
    { 
     CSize imageSize = getSize(deviceContext); 
     clientRect.right = imageSize.cx; 
     clientRect.bottom = imageSize.cy; 
    } 

    long pictureWidth = 0; 
    long pictureHeigth = 0; 

    m_picture->get_Width(&pictureWidth); 
    m_picture->get_Height(&pictureHeigth); 

    m_picture->Render(*deviceContext 
        , clientRect.left 
        , clientRect.top 
        , clientRect.Width() 
        , clientRect.Height() 
        , 0 
        , pictureHeigth 
        , pictureWidth 
        , -pictureHeigth 
        , prcMFBounds); 
    return true; 
} 

CSize Picture::getSize(CDC* deviceContext) 
{ 
    if (!m_picture) 
     return CSize(0,0); 

    LONG width, height; // HIMETRIC units 
    m_picture->get_Width(&width); 
    m_picture->get_Height(&height); 
    CSize size(width, height); 
    if (deviceContext==NULL) 
    { 
     CWindowDC dc(NULL); 
     dc.HIMETRICtoDP(&size); // convert to pixels 
    } 
    else 
    { 
     deviceContext->HIMETRICtoDP(&size); 
    } 
    return size; 
} 

PictureView.h:

#pragma once 

#include <afxwin.h> 
#include <string> 

class Picture; 

class PictureView : public CStatic 
{ 
public: 
    PictureView(std::string path); 

protected: 
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); 

private: 
    Picture* m_picture; 
}; 

PictureView.cpp:

#include "PictureView.h" 
#include "Picture.h" 

PictureView::PictureView(std::string path) 
{ 
    m_picture = new Picture(); 
    m_picture->load(path.c_str()); 
} 

void PictureView::DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/) 
{ 
    CRect rect; 
    GetClientRect(&rect); 
    m_picture->draw(GetDC(), rect, rect); 
} 

構造函數調用:

CWnd* GenericChildWidget::addImage(std::string path, int horizontalPos, int width, int verticalPos, int height, int childId) 
{ 
    PictureView* image = new PictureView(path); 
    image->Create("", SS_OWNERDRAW, CRect(horizontalPos, verticalPos, width + horizontalPos, height + verticalPos), this, childId); 
    return image; 
} 

的問題是,我不能讓DRAWITEM函數被調用。我究竟做錯了什麼? 任何幫助將不勝感激。

+0

你需要一個按鈕或菜單項來保存圖像,並調用PictureView :: DrawItem? – 2010-07-28 14:01:11

+0

想法是這樣的:另一個過程有一個攝像頭並拍攝事物的照片。它將這些圖片存儲爲JPG格式。當某種情況發生時,它會通知我的過程並提供與該條件相對應的圖像的路徑。我需要向包含圖像的用戶顯示一個對話框,用戶現在必須選擇如何繼續。 – Tekar 2010-07-28 14:54:38

回答

0

我從來沒有使用MFC,但快速細讀CStatic::DrawItem documentation說,它必須創建與SS_OWNERDRAW樣式爲DrawItem被調用。您沒有爲您的PictureView顯示Create行,因此可能是這樣嗎?

+0

事實並非如此,我現在已經更改了代碼。但是這並沒有改變這個問題。我添加的代碼如下所示: PictureView * image = new PictureView(path);我們可以通過下面的例子來說明如何使用這種方法來創建一個新的圖像: - 創建(「」,SS_OWNERDRAW,CRect(horizo​​ntalPos,verticalPos,width + horizo​​ntalPos,height + verticalPos),this,childId); 有沒有什麼辦法可以在這裏以更具可讀性的格式發佈? – Tekar 2010-07-28 14:49:46

+0

@Tom:您可以通過編輯原始問題來添加此信息。 – Troubadour 2010-07-28 15:38:51

1

我不確定GetDC在調用m_picture-> draw時必然會引用CREATESTRUCT中給出的相同DC。我所做的是:

 CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); 

編輯:由於我不能評論,希望編輯就足夠了。我認爲你的同事是錯誤的,因爲我剛剛使用SS_OWNERDRAW實現了一個CStatic控件。我猜測添加了WS_CHILD |創建呼叫上的WS_VISIBLE是關鍵。

+0

可能,但我不能得到DrawItem函數被調用,所以我不能測試這個呢。 – Tekar 2010-07-29 06:35:11

+0

我的壞 - 顯然我可以評論我自己的答案。 Livin'學習'。 – rlduffy 2010-07-29 22:02:52

+0

你是正確的,當WS_CHILD和WS_VISIBLE被添加它作爲一個CStatic。 – Tekar 2010-08-03 10:10:07

1

在我的一位同事的幫助下,我找到了答案。他告訴我,不可能擁有一個自己的CStatic。所以當我現在從CButton繼承PictureView並使其BS_OWNERDRAW呈現我的圖像時。

就我個人而言,我認爲這是一個醜陋的解決方案,但我現在很厭倦這個問題,所以我並不在乎那麼多。這些都是我做,使其工作的變化:

構造函數調用:

CWnd* GenericChildWidget::addImage(std::string path, int horizontalPos, int width, int verticalPos, int height, int childId) 
{ 
    PictureView* image = new PictureView(path); 
    image->Create("", BS_OWNERDRAW | WS_CHILD | WS_VISIBLE, CRect(horizontalPos, verticalPos, width + horizontalPos, height + verticalPos), this, childId); 
    return image; 
} 

PictureView.h:

#pragma once 

#include <afxwin.h> 
#include <string> 

class Picture; 

class PictureView : public CButton 
{ 
public: 
    PictureView(std::string path); 

protected: 
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); 

private: 
    Picture* m_picture; 
}; 

感謝各位的所有幫助。

2

下面是一個MFC對話框繪製圖像的簡單方法:

鏈路與gdiplus.dll

#include "atlimage.h> 
#include "gdiplus.h> 
using namespace Gdiplus 
. 
. 
. 

CImage ci; 

ci.Load((CString)"D:\\Pictures\\mycat.jpg"); 

CDC *dc = AfxGetMainWnd()->GetDC(); 

HDC hdc = *dc; 

ci.Draw(hdc,10,10); 

希望工程!