您的位置:首页 > 其它

VC 实现文件对话框的图像预览功能

2010-08-28 17:00 531 查看
很多图像处理方面的软件,都支持文件对话框的图片预览功能,极大的方便了我们选择所需的图片.那么如何在自己的软件中加入这一功能呢?

我们知道,MFC中的CFileDialog类封装了文件对话框的功能.它的成员m_ofn是OPENFILENAME类型的结构.我们要想定制文件对话框,只需从CFileDialog中派生一个新类,然后如下设置m_ofn的内部成员:

m_ofn.Flags |=(OFN_EXPLORER | OFN_ENABLETEMPLATE);

m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEOPENPREVIEW);

IDD_FILEOPENPREVIEW是我们创建的对话框资源的ID,包含了我们想要在定制的文件对话框中加入的控件和它们的定位信息.设置了OFN_EXPLORER属性后,系统将创建一个标准文件对话框的子对话框,其中不仅包含了原先的标准控件,还加入了我们在IDD_FILEOPENPREVIEW中包含的控件,并且它们两者的位置是由IDD_FILEOPENPREVIEW中的定位信息所决定的.这个定位信息就是一个ID为stc32的静态文本框.stc32是系统预定义的标号,用来代表标准文件对话框中的控件,我们以它为参照物来自由安排自己想添加的控件的位置.

设置了对话框资源后,还需重载如下函数来响应消息.

重载OnFileNameChange来处理用户从文件列表中选择了一个新的文件或目录的情形,重载OnFolderChange来处理用户打开一个新目录的情形,重载OnTypeChange来处理用户选择了一种新文件类型的情形.

下面我们来实际演示一下.

1.首先创建一个单文档程序BmpPreviewDlg.接下来我们要先创建一个位图类CDib.由于本程序的演示性质,我实现的这个位图类功能比较简单,仅有图像的读取和显示功能.方法BOOL
Load(LPCTSTR lpszPathName)载入

参数表示的文件,void
Draw(HDC, CRect* pDstRect,CRect* pSrcRect=NULL)显示位图,BOOL
IsEmpty()返回位图是否已装载.具体的代码附于文后.

2.然后我们创建一个能显示位图的图像框类CBmpStatic.选择"Insert/New class"加入新类CBmpStatic,基类为CStatic.在头文件"BmpStatic.h"中加入如下包含语句:

#include "Dib.h"

加入如下成员:

private:

CDib m_Dib;

// Operations

public:

BOOL ShowImage(LPCTSTR lpszPathName);

BOOL HideImage();

void DoPaint(BOOL bImage);

函数ShowImage显示位图lpszPathName:

BOOL CBmpStatic::ShowImage(LPCTSTR lpszPathName)

{

BOOL bSuccess=m_Dib.Load(lpszPathName);

DoPaint(bSuccess);

return TRUE;

}

函数HideImage清除图像的显示:

BOOL CBmpStatic::HideImage()

{

DoPaint(FALSE);

return TRUE;

}

辅助函数DoPaint当参数bImage为真时,显示位图,为假时用白色填充:

void CBmpStatic::DoPaint(BOOL bImage)

{

CRect ClientRect;

GetClientRect(&ClientRect);

CClientDC dc(this);

//若bImage为真,绘制位图;

if(bImage)

{

m_Dib.Draw(dc.GetSafeHdc(),&ClientRect);

}

else //否则,填充白色;

{

CBrush* pBrush;

pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH));

dc.FillRect(&ClientRect,pBrush);

}

}

重载WM_PAINT消息的响应函数:

void CBmpStatic::OnPaint()

{

CPaintDC dc(this); // device context for painting

DoPaint(!m_Dib.IsEmpty());

}

3.打开资源编辑器,插入一个对话框资源IDD_FILEOPENPREVIEW.在它的属性对话框中单击"styles"标签,设置对话框的类型(style)为Child,边界(Border)为None,选择Clip
siblings属性.单击"More Styles"标签,选择"Visible","3D-look","Control"属性.接下来删除"OK","CANCEL"按钮,添加一个静态文本框(static
text),令其ID为stc32.在其右边添加图像框(Picture)IDC_IMAGE,类型选择为Bitmap,选择"Sunken","Center image"属性.结果如图一所示:

4.选择"Insert/New Class"菜单加入新类CPreviewFileDlg,其基类为CFileDialog.在头文件"PreviewFileDlg.h"中加入包含语句:

#include "BmpStatic.h"

加入成员变量

protected:

CBmpStatic m_BmpStaticCtrl;

在CPreviewFileDlg的构造函数中加入如下语句:

m_ofn.Flags |=(OFN_EXPLORER | OFN_ENABLETEMPLATE);

m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEOPENPREVIEW);

添加WM_INITDIALOG的响应函数:

BOOL CPreviewFileDlg::OnInitDialog()

{

CFileDialog::OnInitDialog();

m_BmpStaticCtrl.SubclassDlgItem(IDC_IMAGE,this);

return TRUE;

}

重载虚拟函数OnFileNameChange():

void CPreviewFileDlg::OnFileNameChange()

{

CFileDialog::OnFileNameChange();

m_BmpStaticCtrl.ShowImage(GetPathName());

}

重载虚拟函数OnFolderChange():

void CPreviewFileDlg::OnFolderChange()

{

CFileDialog::OnFolderChange();

m_BmpStaticCtrl.HideImage();

}

5.在类CBmpPreviewDlgApp的实现文件BmpPreviewDlg.cpp中加入包含语句:

#include "PreviewFileDlg.h"

添加ID_FILE_OPEN的响应函数OnFileOpen:

void CBmpPreviewDlgApp::OnFileOpen()

{

CString szFilter="BMP Files(*.bmp)|*.bmp||";

CString szDefExt=".bmp";

CPreviewFileDlg dlg(TRUE,szDefExt,NULL,OFN_HIDEREADONLY,szFilter,NULL);

if(dlg.DoModal()==IDOK)

{

OpenDocumentFile(dlg.GetPathName());

}

}

6.在类CBmpPreviewDlgDoc的头文件BmpPreviewDlgDoc.h中添加包含语句:

#include "Dib.h"

在类CBmpPreviewDlgDoc中添加公开成员

CDib m_Dib;

重载虚拟函数OnOpenDocument():

BOOL CBmpPreviewDlgDoc::OnOpenDocument(LPCTSTR lpszPathName)

{

BOOL bSuccess;

BeginWaitCursor();

bSuccess=m_Dib.Load(lpszPathName);

EndWaitCursor();

if(bSuccess)

{

SetPathName(lpszPathName);

SetModifiedFlag(FALSE); //开始时置未修改标记;

}

return bSuccess;

}

7.如下处理CBmpPreviewDlgView的OnDraw函数:

void CBmpPreviewDlgView::OnDraw(CDC* pDC)

{

CBmpPreviewDlgDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

CDib *pCurDib=&pDoc->m_Dib;

if(!pCurDib->IsEmpty())

{

CRect rect;

GetClientRect(&rect);

pCurDib->Draw(pDC->GetSafeHdc(),&rect);

}

}

编译,运行程序.选择"文件/打开"菜单,是不是出现了如图二所示的图像预览文件对话框?

本文仅仅演示了如何定制文件对话框来实现图像预览功能,其实定制文件对话框的用处是很广泛的,但不管你定制的对话框形状如何,采用的方法都是一样的.大家可以根据自己的需要任意定制文件对话框.

本文演示程序在VC6.0,win98下运行通过.

附CDib类的源代码:

//Dib.h

#ifndef _DIB_H

#define _DIB_H

#define WIDTHBYTES(bits)
(((bits) + 31) / 32 * 4)

class CDib : public CObject

{

DECLARE_DYNAMIC(CDib)

// Constructors

public:

CDib();

// Attributes

protected:

WORD m_wWidth;

WORD m_wHeight;

WORD m_wColorNum;

BOOL m_bEmpty;

LPBYTE m_pBits;

LPBITMAPINFO m_pBi;

public:

CPalette* m_pPal;

// Operations

public:

void Draw(HDC, CRect* pDstRect,CRect* pSrcRect=NULL);

BOOL Load(LPCTSTR lpszPathName);

BOOL IsEmpty() { return m_bEmpty;}

// Implementation

public:

virtual ~CDib();

protected:

BOOL Read(CFile& file);

WORD NumColors(LPBITMAPINFOHEADER lpBih);

BOOL CreatePalette();

void Destroy();

public:

#ifdef _DEBUG

virtual void Dump(CDumpContext& dc) const;

#endif

};

#endif

//Dib.cpp

#include "stdafx.h"

#include "Dib.h"

IMPLEMENT_DYNAMIC(CDib, CObject)

CDib::CDib()

{

m_wWidth=0;

m_wHeight=0;

m_wColorNum=0;

m_bEmpty=TRUE;

m_pBi = NULL;

m_pBits = NULL;

m_pPal = NULL;

}

CDib::~CDib()

{

Destroy();

}

void CDib::Destroy()

{

m_wWidth=0;

m_wHeight=0;

m_wColorNum=0;

m_bEmpty=TRUE;

if (m_pBits)

{

GlobalFree((HANDLE)m_pBits);

m_pBits = NULL;

}

if (m_pBi)

{

GlobalFree((HANDLE)m_pBi);

m_pBi = NULL;

}

if (m_pPal)

{

delete m_pPal;

m_pPal = NULL;

}

}

void CDib::Draw(HDC hDC, CRect* pDstRect, CRect* pSrcRect)

{

HPALETTE hPal = NULL;

HPALETTE hOldPal = NULL;

if (m_pPal != NULL)

{

hPal = (HPALETTE) m_pPal->m_hObject;

hOldPal = SelectPalette(hDC, hPal, TRUE);

}

//若源矩形为空,则取整个位图;

if(pSrcRect==NULL)

{

CRect srcRect;

srcRect.left=srcRect.top=0;

srcRect.right=m_wWidth-1;

srcRect.bottom=m_wHeight-1;

pSrcRect=&srcRect;

}

::SetStretchBltMode(hDC, COLORONCOLOR);

if ((pDstRect->Width() == pSrcRect->Width()) &&

(pDstRect->Height()== pSrcRect->Height()))

SetDIBitsToDevice(hDC,pDstRect->left,pDstRect->top, pDstRect->Width(),pDstRect->Height(),

pSrcRect->left,pSrcRect->top,0,m_wHeight,m_pBits,m_pBi,DIB_RGB_COLORS);

else

StretchDIBits(hDC,pDstRect->left,pDstRect->top,pDstRect->Width(),pDstRect->Height(),

pSrcRect->left,pSrcRect->top,pSrcRect->Width(),pSrcRect->Height(),

m_pBits,m_pBi,DIB_RGB_COLORS,SRCCOPY);

if (hOldPal != NULL)

{

SelectPalette(hDC, hOldPal, TRUE);

}

}

BOOL CDib::CreatePalette()

{

//
颜色数不为零时,创建调色板;

if (m_wColorNum != 0)

{

HANDLE hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY)*m_wColorNum);

if (hLogPal == NULL)

return FALSE;

LPLOGPALETTE lpPal = (LPLOGPALETTE)GlobalLock(hLogPal);

lpPal->palVersion = 0x300;

lpPal->palNumEntries = m_wColorNum;

for (int i = 0; i < (int)m_wColorNum; i++)

{

lpPal->palPalEntry[i].peRed = m_pBi->bmiColors[i].rgbRed;

lpPal->palPalEntry[i].peGreen = m_pBi->bmiColors[i].rgbGreen;

lpPal->palPalEntry[i].peBlue = m_pBi->bmiColors[i].rgbBlue;

lpPal->palPalEntry[i].peFlags = 0;

}

if (m_pPal)

{

delete m_pPal;

}

m_pPal = new CPalette;

BOOL bResult = m_pPal->CreatePalette(lpPal);

GlobalUnlock((HGLOBAL) hLogPal);

GlobalFree((HGLOBAL) hLogPal);

return bResult;

}

return TRUE;

}

//计算颜色数的函数;

WORD CDib::NumColors(LPBITMAPINFOHEADER lpBih)

{

WORD wColorNum;

WORD wBitCount;

if(lpBih->biClrUsed!=0)

wColorNum = (WORD)lpBih->biClrUsed;

else

{

wBitCount = (WORD)lpBih->biBitCount;

if(wBitCount<=8)

wColorNum = 1<<wBitCount;

else

wColorNum = 0;

}

return wColorNum;

}

BOOL CDib::Load(LPCTSTR lpszPathName)

{

CFile file;

if(!file.Open(lpszPathName,CFile::modeRead))

return FALSE;

Destroy();

Read(file);

CreatePalette();

m_bEmpty=FALSE;

file.Close();

return TRUE;

}

BOOL CDib::Read(CFile& file)

{

BITMAPFILEHEADER bfh;

BITMAPINFOHEADER bih;

if (file.Read((LPSTR)&bfh, sizeof(bfh)) != sizeof(bfh))

return FALSE;

if (bfh.bfType != 0x4d42)

return FALSE;

if(file.Read((LPSTR)&bih,sizeof(bih))!= sizeof(bih))

return FALSE;

m_wWidth = (WORD)bih.biWidth;

m_wHeight= (WORD)bih.biHeight;

m_wColorNum = NumColors(&bih);

DWORD dwSizeBi = sizeof(BITMAPINFOHEADER)+m_wColorNum*sizeof(RGBQUAD);

DWORD dwSizeImage = WIDTHBYTES(m_wWidth*bih.biBitCount)*m_wHeight;

m_pBi = (LPBITMAPINFO)GlobalAlloc(GPTR,dwSizeBi);

if (m_pBi == NULL)

return FALSE;

file.Seek(sizeof(BITMAPFILEHEADER),CFile::begin);

if (file.Read(m_pBi, dwSizeBi) != dwSizeBi)

{

GlobalFree((HANDLE)m_pBi);

m_pBi = NULL;

return FALSE;

}

m_pBits = (LPBYTE)GlobalAlloc(GPTR,dwSizeImage);

if (m_pBits == NULL)

{

GlobalFree((HANDLE)m_pBi);

m_pBi = NULL;

return FALSE;

}

if (file.ReadHuge(m_pBits, dwSizeImage) != dwSizeImage)

{

GlobalFree((HANDLE)m_pBi);

m_pBi = NULL;

GlobalFree((HANDLE)m_pBits);

m_pBits = NULL;

return FALSE;

}

return TRUE;

}

#ifdef _DEBUG

void CDib::Dump(CDumpContext& dc) const

{

CObject::Dump(dc);

}

#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: