一个文件预览对话框
说明
需要做个文件选择时的预览,发现MFC中原有的对话框功能有限,想起继承后自绘处理,找了一些资料,不能完美实现,最后结合一些资料,自我感觉良好,遂分享之。
实现步骤
资源文件
GROUPBOX的ID确定是1119,这个很重要!!!
/
//
// Dialog
//
IDD_FILEEX_DLG DIALOGEX 0, 0, 512, 230
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "",IDC_SC_DRAW,310,6,190,189
CONTROL "预览文件",IDC_CHECK_PREVIEW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,374,199,50,10
GROUPBOX "",1119,0,0,308,227
END
代码
FileDialogEx.h
//!< 这个类的目的是移除GroupBox的外边框
class CCustomGroupBox : public CButton
{
DECLARE_DYNAMIC(CCustomGroupBox)
public:
CCustomGroupBox();
virtual ~CCustomGroupBox();
protected:
DECLARE_MESSAGE_MAP()
afx_msg void OnPaint();
};
class CFileDialogEx : public CFileDialog
{
DECLARE_DYNAMIC(CFileDialogEx)
public:
CFileDialogEx(BOOL bOpenFileDialog, // 对于 FileOpen 为 TRUE,对于 FileSaveAs 为 FALSE
LPCTSTR lpszDefExt = NULL,
LPCTSTR lpszFileName = NULL,
DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
LPCTSTR lpszFilter = NULL,
CWnd* pParentWnd = NULL);
virtual ~CFileDialogEx();
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_FILEEX_DLG };
#endif
// 目的是选中文件后,解析生成BMP,让窗口调用,需要自己实现
// 1. path1 选中的文件路径
// 2. path2 需要保存到指定位置的图片路径
std::function<bool(CString,CString)> m_fnTask;
private:
float m_dbWidth, m_dbHeight;
BOOL m_bOpenFilePreview;
CString m_strViewImgPath, m_lstPath;
CImage m_PreViewImg;
CCustomGroupBox m_grp;
protected:
DECLARE_MESSAGE_MAP()
public:
virtual BOOL OnInitDialog();
virtual void OnFileNameChange();
virtual void OnTypeChange();
void UpdateScImage();
afx_msg void OnClose();
afx_msg void OnBnClickedCheckPreview();
afx_msg void OnStnClickedScFiledialog();
afx_msg void OnPaint();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
};
FileDialogEx.cpp
#include "FileDialogEx.h"
// CFileDialogEx
IMPLEMENT_DYNAMIC(CFileDialogEx, CFileDialog)
CFileDialogEx::CFileDialogEx(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{
m_ofn.Flags |= dwFlags;
m_ofn.Flags |= OFN_FILEMUSTEXIST;
m_ofn.Flags |= OFN_PATHMUSTEXIST;
m_ofn.Flags |= OFN_ALLOWMULTISELECT;
m_ofn.Flags |= OFN_EXPLORER;
m_ofn.Flags |= OFN_ENABLETEMPLATE;
DWORD dwMajorVer = NULL, dwMinorVer = NULL, dwBuildNumber = NULL;
m_ofn.hInstance = AfxGetInstanceHandle();
m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEEX_DLG);
m_bVistaStyle = FALSE; //可以vista以上运行
m_dwRef = 1;
m_bOpenFilePreview = TRUE;
m_dbWidth = m_dbHeight = 1000;
m_lstPath = m_strViewImgPath = _T("");
m_fnTask = NULL;
}
CFileDialogEx::~CFileDialogEx()
{
if (!m_PreViewImg.IsNull()) m_PreViewImg.Destroy();
if (GetFileAttributes(m_strViewImgPath) > 0) DeleteFile(m_strViewImgPath);
}
BEGIN_MESSAGE_MAP(CFileDialogEx, CFileDialog)
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_CHECK_PREVIEW, &CFileDialogEx::OnBnClickedCheckPreview)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
// CFileDialogEx 消息处理程序
BOOL CFileDialogEx::OnInitDialog()
{
CFileDialog::OnInitDialog();
m_grp.SubclassDlgItem(1119,this);
CRect rc, rcFileDialog, rcWnd;
GetDlgItem(IDC_SC_DRAW)->GetClientRect(rc);
ClientToScreen(rc);
int nDefault = rc.Width() < rc.Height() ? rc.Width() : rc.Height();
GetDlgItem(IDC_SC_DRAW)->SetWindowPos(NULL, 0, 0, nDefault, nDefault, SWP_NOZORDER | SWP_NOMOVE);
((CButton*)GetDlgItem(IDC_CHECK_PREVIEW))->SetCheck(m_bOpenFilePreview);
return TRUE; // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}
void CFileDialogEx::UpdateScImage()
{
CDC* pDc = GetDlgItem(IDC_SC_DRAW)->GetDC();
if (!m_PreViewImg.IsNull() && pDc)
{
/*
在使用 CImage 的Draw 输入一个图像时,有时候会造成图像失真严重,解决的方法如下
失真主要是由于变形造成的.只要设置一下变形的模式就可以了
*/
::SetStretchBltMode(*pDc, HALFTONE);
::SetBrushOrgEx(*pDc, 0, 0, NULL);
CRect rc;
GetDlgItem(IDC_SC_DRAW)->GetClientRect(rc);
m_PreViewImg.StretchBlt(pDc->GetSafeHdc(), 0, 0, rc.Width(), rc.Height(), SRCCOPY);
}
if (pDc) ReleaseDC(pDc);
}
void CFileDialogEx::OnTypeChange()
{
CString folderPath = GetFolderPath();
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, folderPath, NULL);
CFileDialog::OnTypeChange();
}
void CFileDialogEx::OnFileNameChange()
{
// TODO: 在此添加专用代码和/或调用基类
CFileDialog::OnFileNameChange();
CString path = GetPathName();
CString ext = GetFileExt();
if (!m_bOpenFilePreview || m_lstPath == path)
return;
if (m_fnTask)
{
if (!m_fnTask(path, m_strViewImgPath))
return;
if (!m_PreViewImg.IsNull()) m_PreViewImg.Destroy();
m_PreViewImg.Load(m_strViewImgPath);
m_lstPath = path;
}
UpdateScImage();
}
void CFileDialogEx::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CFileDialog::OnClose();
}
void CFileDialogEx::OnBnClickedCheckPreview()
{
// TODO: 在此添加控件通知处理程序代码
m_bOpenFilePreview = ((CButton*)GetDlgItem(IDC_CHECK_PREVIEW))->GetCheck();
if (!m_bOpenFilePreview)
{
if (!m_PreViewImg.IsNull()) m_PreViewImg.Destroy();
UpdateScImage();
}
}
void CFileDialogEx::OnStnClickedScFiledialog()
{
// TODO: 在此添加控件通知处理程序代码
}
void CFileDialogEx::OnPaint()
{
CPaintDC dc(this); // device context for painting
UpdateScImage();
}
BOOL CFileDialogEx::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
return TRUE;
//return CFileDialog::OnEraseBkgnd(pDC);
}
/
IMPLEMENT_DYNAMIC(CCustomGroupBox, CButton)
CCustomGroupBox::CCustomGroupBox()
{
}
CCustomGroupBox::~CCustomGroupBox()
{
}
BEGIN_MESSAGE_MAP(CCustomGroupBox, CButton)
ON_WM_PAINT()
END_MESSAGE_MAP()
void CCustomGroupBox::OnPaint()
{
CPaintDC dc(this); // device context for painting
}
效果预览
最后
感谢各位大佬的无私奉献。