【问题标题】:Drawing a jpg in MFC在 MFC 中绘制 jpg
【发布时间】:2010-07-28 13:57:44
【问题描述】:

我一直在尝试在 MFC 中显示 jpg 图像,但无法将其绘制出来。我是一个完整的 MFC 新手,我到现在为止的所有内容大部分都改编自我在网上找到的东西。目前我有这个:

图片.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;
};

图片.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 函数。我究竟做错了什么? 任何帮助将不胜感激。

【问题讨论】:

  • 您是否需要一个按钮或菜单项来保存图像,并调用 PictureView::DrawItem?
  • 这个想法是这样的:另一个进程有一个摄像头并为事物拍照。它将这些图片存储为jpg。当某个条件发生时,它会通知我的进程并提供与该条件对应的图像的路径。我需要向包含图像的用户显示一个对话框,用户现在必须选择如何继续。

标签: c++ mfc


【解决方案1】:

这是在 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);

希望它有效!

【讨论】:

    【解决方案2】:

    在我的一位同事的帮助下,我找到了答案。他告诉我不可能有一个所有者绘制的 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;
    };
    

    感谢大家的帮助。

    【讨论】:

      【解决方案3】:

      我不确定调用 m_picture->draw 中的 GetDC 是否一定会引用 CREATESTRUCT 中给出的同一个 DC。我所做的是:

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

      编辑:由于我无法发表评论,希望编辑就足够了。我认为您的同事弄错了,因为我最近使用 SS_OWNERDRAW 实现了 CStatic 控件。我猜想添加 WS_CHILD | Create 调用上的 WS_VISIBLE 是关键。

      【讨论】:

      • 可能,但我无法调用 DrawItem 函数,因此我还无法测试。
      • 我的错 - 显然我可以评论我自己的答案。生活和学习。
      • 你是对的,当添加 WS_CHILD 和 WS_VISIBLE 时,它作为 CStatic 工作。
      【解决方案4】:

      我从未使用过 MFC,但快速阅读 CStatic::DrawItem documentation 说它必须使用 SS_OWNERDRAW 样式创建,以便 DrawItem 被调用。您还没有为您的PictureView 显示Create 行,所以可能是这样?

      【讨论】:

      • 确实不是这样,我现在已经更改了代码。然而,这并没有改变问题。我添加的代码如下所示: PictureView* image = new PictureView(path); image->Create("", SS_OWNERDRAW, CRect(horizo​​ntalPos, verticalPos, width + Horizo​​ntalPos, height + verticalPos), this, childId);有什么办法可以在这里以更易读的格式发布吗?
      • @Tom:您只需编辑原始问题即可添加此信息。
      猜你喜欢
      • 2012-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-17
      相关资源
      最近更新 更多