当前位置: 首页 > news >正文

在CFileDialog对话框中添加控件

关键字:CFileDialog扩展类 ,OFNHookProc

需求描述 : 昨天遇到一个用户需求,在CFileDialog对话框(SAVE)中加入一个Check , 一个Edit, 一个Spin控件,dlg.Domodal()==IDOK返回时要同时获得Edit控件中的数据.

实现方法: 如果只需要控制控件,用方法一即可,但如果需要获取数据,则只能用方法二。我最终用的就是方法二.

方法一: 首先查找MSDN关于CFileDialog扩展的实现描述,上网查到实现预览图片式的CFILEDIALOG的例子。按照其思路从CFileDialog派生了一个新的类CFileDialogEX.

在类中添加以下代码

#define WM_CHECKZOOMIN WM_USER+1856

public:
    BOOL bZoomIn;
    UINT nMul; //[1~100]

 

//前置声明---------------
BOOL NEAR CALLBACK HandleNotify(HWND hDlg, LPOFNOTIFY pofn);
UINT_PTR CALLBACK OFNHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

// 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 |=  OFN_ENABLETEMPLATE |OFN_HIDEREADONLY |OFN_EXPLORER;  //OFN_EXPLORER | OFN_ENABLEHOOK
    m_ofn.lpstrTitle   =  _T("高级保存对话框");
    m_ofn.hInstance = AfxGetInstanceHandle();
    m_ofn.lpstrFilter  =  _T("*.bmp\0*.BMP\0所有文件 \0 *.*\0 ");
    m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEDIALOG_EX);
    m_ofn.lpfnHook =  (LPOFNHOOKPROC)OFNHookProc;   
}

 

//Hook function for the Comm Dlg
//在这里处理我们感兴趣的消息,想要哪个,截哪个!
UINT_PTR CALLBACK OFNHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_INITDIALOG:   //初始化对话框上的控件

        if(SendDlgItemMessage(hDlg, IDC_CHECK_ZOOMIN, BM_GETCHECK,0,0) == BST_UNCHECKED)
        {             

            ::EnableWindow(GetDlgItem(hDlg,IDC_EDIT_ZOOMNUM),FALSE);
            ::EnableWindow(GetDlgItem(hDlg,IDC_SPIN_ZOOMNUM),FALSE);
            ::SetWindowText(GetDlgItem(hDlg, IDC_EDIT_ZOOMNUM),_T("1"));
            //ShowWindow(button,SW_HIDE);  

        }
        break;

    case WM_DESTROY:    //消毁对话框
        {
            LPOPENFILENAME lpOFN = (LPOPENFILENAME)GetWindowLong(hDlg, DWL_USER);

        }
        break;

    case WM_COMMAND:   //这里处理,IDC_CHECK_ZOOMIN命令
        {   
        if ((HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDC_CHECK_ZOOMIN))
        {
            BOOL bZoomIn = TRUE;
            if(SendDlgItemMessage(hDlg, IDC_CHECK_ZOOMIN, BM_GETCHECK, 0, 0) == BST_CHECKED)
            {
                 bZoomIn = TRUE;               
                ::EnableWindow(GetDlgItem(hDlg,IDC_EDIT_ZOOMNUM),TRUE);
                ::EnableWindow(GetDlgItem(hDlg,IDC_SPIN_ZOOMNUM),TRUE);
             }
            else
            {
                bZoomIn = FALSE;
                //::SetWindowText(GetDlgItem(hDlg, IDC_EDIT_ZOOMNUM),"");
                ::EnableWindow(GetDlgItem(hDlg,IDC_EDIT_ZOOMNUM),FALSE);
                ::EnableWindow(GetDlgItem(hDlg,IDC_SPIN_ZOOMNUM),FALSE);
            }
            HWND hParent = GetParent(hDlg);        // 注意hDlg是新加的模板对话框句柄,它是CFileDialog对话框的子部分,要获取CFileDialog对话框的句柄需要用GetParent函数 
            PostMessage(hParent,WM_CHECKZOOMIN,(WPARAM)bZoomIn,(LPARAM)0);
            bZoomIn = FALSE;
        }

        break;
    case WM_NOTIFY:
        HandleNotify(hDlg, (LPOFNOTIFY)lParam);
        break;
    }
    return 0;
}

//这里处理notify 消息
BOOL NEAR CALLBACK HandleNotify(HWND hDlg, LPOFNOTIFY pofn)
{
    CFileDialogEx dlg(TRUE);
    switch (pofn->hdr.code)
    {
    case CDN_SELCHANGE:
        {
            //char szFile[MAX_PATH];
            Get the path of the selected file.
            //if (CommDlg_OpenSave_GetFilePath(GetParent(hDlg), szFile, sizeof(szFile)) <= sizeof(szFile))
            //{

            //    if(GetFileAttributes(szFile) !=  FILE_ATTRIBUTE_DIRECTORY)
            //    {           
            //        //Should we load the Pic
            //        if(SendDlgItemMessage(hDlg, IDC_CHECK1, BM_GETCHECK,0,0) == BST_UNCHECKED)
            //            dlg.ShowImagepreview(hDlg, szFile);   
            //    }
            //}
        }
        break;

    case CDN_FILEOK:
        {           
            int num;
            GetDlgItemInt(hDlg,IDC_EDIT_ZOOMNUM,&num,FALSE);           
            if(SendDlgItemMessage(hDlg, IDC_CHECK_ZOOMIN, BM_GETCHECK, 0, 0) == BST_CHECKED)
            {
                dlg.bZoomIn = TRUE;
            }
            else
                dlg.bZoomIn = FALSE;

            return FALSE;
        }
        break;

    }

    return(TRUE);
}

原计划从回调函数得到触发消息,然后用PostMessage的方式将自定义的WM_CHECKZOOMIN消息发给主窗口,在主窗口中更新我新加的变量bZoomIn和

nMul的值。

但调试发现我新定义的CFileDialogEX类中的WM_CHECKZOOMIN的消息响应函数总是无法进入。进一步调式确定消息确实是发送成功了,而且窗口句柄也没有错,但就是进入不了我定义的响应函数。  经过资料查询和思索初步推理: CFileDialog的消息处理是封闭的,自动的,在没有用钩子的情况下我们是无法将自己的消息函数插入其中并能自己处理的。 从MSDN给的说明也可以看出,它推荐PostMessage传输的也只是系统定义消息如WM_COMMAND,也就是说你可以控制它的控件做某项动作或显示隐藏控件,移动控件的位置。

一切回到了原点,此路不通,继续寻找新的方法!!!!!!

 

方法二:看到一篇文章http://www.softist.com/programemo/cfiledialog/cfiledialog.htm,给我指了一条明路

CFileDialog的个性化(VC++)

本文是为标准的文件选择对话框添加控件以扩展它的功能。为了做到这点,要把CFileDialog类派生,还要准备粘贴控件用的对话框模板,把控件的消息响应入口追加到MESSAGE-MAP中。

例程。文件选择对话框在选择文本文件时,可以预览这个文件的内容。

1.生成对话框模板。作一个对话框的资源,比如ID为IDD_DIALOG1。其属性如下设定。

IDD_DIALOG1 DIALOG DISCARDABLE  0, 0, 187, 128
STYLE WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
FONT 9, "MS Sans Serif"
BEGIN
    LTEXT           "Static",stc32,7,7,173,114
    EDITTEXT        IDC_EDIT_PREVIEW,7,18,102,30,ES_MULTILINE | 
                    ES_AUTOHSCROLL | ES_WANTRETURN
    PUSHBUTTON      "Button1",IDC_BUTTON_PREVIEW,143,36,37,23
END

2.追加控件。首先追加一个ID为stc32的大一点的静态文字控件(Static)。然后在它的下面,追加预览用的多行编辑框(ID=IDC_EDIT_PREVIEW)和起动预览用的按钮(ID=IDC_BUTTON_PREVIEW)。

3.生成CFileDialog的派生类,比如叫CFileDlg。为了指定资源ID,追加如下的代码到CFileDlg里。这个追加还有一个意义,那就是可以用MFC的类精灵工具(MFC ClassWizard)来作相应的处理。

// Dialog Data
    //{{AFX_DATA(CFileDlg)
    enum { IDD = IDD_DIALOG1 };
    //}}AFX_DATA

4.把上面生成的对话框模板,安装到CFileDlg的类创建函数里,代码如下。

CFileDlg::CFileDlg(BOOL bOpenFileDialog, ...) : CFileDialog(bOpenFileDialog, ...)
{
    m_ofn.Flags |= dwFlags;
    m_ofn.Flags |= OFN_EXPLORER;
    m_ofn.Flags |= OFN_ENABLETEMPLATE;
SetTemplate(0, IDD_DIALOG1);
}

5.填写按钮(ID=IDC_BUTTON_PREVIEW)的响应函数。从CFileDlg类的实体对话框取得文件的全路径,打开文件,把其内容显示在编辑框(ID=IDC_EDIT_PREVIEW)上。

void CFileDlg::OnPreview()
{
    CString strPathName = GetPathName();
    if (strPathName != "")
    {
        CFile file;
        file.Open(strPathName, CFile::modeRead);
        char buff[1024];
        memset(buff, 0, 1024);
        file.Read(buff, 1024);
        GetDlgItem(IDC_EDIT_PREVIEW)->SetWindowText(buff);
        file.Close();
    }
}

6.结果测试。

CFileDlg dlg(TRUE);
dlg.DoModal();

 

通过指定资源ID , 可以使用Wizard添加处理消息, OK 这正是我想要的, 按照它的方法,很快就实现了需求,调用如下

//.h

// Dialog Data
//{{AFX_DATA(CFileDlg)
enum { IDD = IDD_FILEDIALOG_EX };
//}}AFX_DATA

public:
    BOOL bZoomIn;
    UINT nMul; //[1~100]

afx_msg void OnBnClickedCheckZoomin();
afx_msg void OnDeltaposSpinZoomnum(NMHDR *pNMHDR, LRESULT *pResult);
virtual BOOL OnInitDialog();
afx_msg void OnEnChangeEditZoomnum();
afx_msg void OnEnKillfocusEditZoomnum();

 

//.cpp

CFileDialogEx::CFileDialogEx(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
        DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
        CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{
    //这个四个常用标识位
    m_ofn.Flags |=  OFN_ENABLETEMPLATE |OFN_HIDEREADONLY |OFN_EXPLORER;  //OFN_EXPLORER | OFN_ENABLEHOOK
    m_ofn.lpstrTitle   =  _T("高级保存对话框");
    m_ofn.hInstance = AfxGetInstanceHandle();
    m_ofn.lpstrFilter  =  _T("*.bmp\0*.BMP\0所有文件 \0 *.*\0 ");

    SetTemplate(0, IDD_FILEDIALOG_EX);
}

 

BEGIN_MESSAGE_MAP(CFileDialogEx, CFileDialog)
    //ON_COMMAND()
    ON_BN_CLICKED(IDC_CHECK_ZOOMIN, &CFileDialogEx::OnBnClickedCheckZoomin)
    ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_ZOOMNUM, &CFileDialogEx::OnDeltaposSpinZoomnum)
    ON_EN_CHANGE(IDC_EDIT_ZOOMNUM, &CFileDialogEx::OnEnChangeEditZoomnum)
    ON_EN_KILLFOCUS(IDC_EDIT_ZOOMNUM, &CFileDialogEx::OnEnKillfocusEditZoomnum)
END_MESSAGE_MAP()

 

void CFileDialogEx::OnBnClickedCheckZoomin()
{
    // TODO: 在此添加控件通知处理程序代码
    bZoomIn = !bZoomIn;
    GetDlgItem(IDC_EDIT_ZOOMNUM)->EnableWindow(bZoomIn);
    GetDlgItem(IDC_SPIN_ZOOMNUM)->EnableWindow(bZoomIn);
}

void CFileDialogEx::OnDeltaposSpinZoomnum(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    if (pNMUpDown->iDelta > 0)
    {
        if (nMul > 1)
            nMul--;
    }
    else
    {
        if (nMul <= 100)
            nMul++;
    }

    wchar_t buff[10];       
    _itow( nMul, buff, 10 );
    LPCTSTR lpstr = (LPCTSTR)buff;

    GetDlgItem(IDC_EDIT_ZOOMNUM)->SetWindowText(lpstr);
    *pResult = 0;
}

BOOL CFileDialogEx::OnInitDialog()
{
    CFileDialog::OnInitDialog();

    // TODO:  在此添加额外的初始化
    GetDlgItem(IDC_EDIT_ZOOMNUM)->EnableWindow(FALSE);
    GetDlgItem(IDC_SPIN_ZOOMNUM)->EnableWindow(FALSE);
    GetDlgItem(IDC_EDIT_ZOOMNUM)->SetWindowText(_T("1"));

    bZoomIn = FALSE;
    nMul = 1;
    return TRUE;  // return TRUE unless you set the focus to a control
    // 异常: OCX 属性页应返回 FALSE
}

void CFileDialogEx::OnEnChangeEditZoomnum()
{
    // TODO:  如果该控件是 RICHEDIT 控件,它将不
    // 发送此通知,除非重写 CFileDialog::OnInitDialog()
    // 函数并调用 CRichEditCtrl().SetEventMask(),
    // 同时将 ENM_CHANGE 标志“或”运算到掩码中。

    // TODO:  在此添加控件通知处理程序代码
    CString strText;
    GetDlgItem(IDC_EDIT_ZOOMNUM)->GetWindowText(strText);

    nMul = _wtoi(strText);
    if ( (nMul < 1) || (nMul > 100) )
    {
        if (nMul < 1) nMul = 1;
        if (nMul > 100) nMul = 100;

        wchar_t buff[10];       
        _itow( nMul, buff, 10 );
        LPCTSTR lpstr = (LPCTSTR)buff;

        GetDlgItem(IDC_EDIT_ZOOMNUM)->SetWindowText(lpstr);
    }

}

void CFileDialogEx::OnEnKillfocusEditZoomnum()
{
    // TODO: 在此添加控件通知处理程序代码
    CString strText;
    GetDlgItem(IDC_EDIT_ZOOMNUM)->GetWindowText(strText);

    nMul = _wtoi(strText);   
}

 

// 调用实现代码

CString szFilter1 = _T("保存图象文件(*.bmp)|*.bmp;|所有文件(*.*)|*.*||");
CFileDialogEx dlg(FALSE, _T(".bmp"), NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,szFilter1);

if (dlg.DoModal()==IDOK)
        {
            CComBSTR str=dlg.GetPathName();
            if (!dlg.bZoomIn)
            {                            }
            else
            {   float Magnification = dlg.nMul;}

         }

相关文章:

  • PLC控制器在污水处理市场的应用分析——多普康自动化制作
  • Windows 2008 部署服务之WDS安装及配置
  • uva 12730(期望经典)
  • 关于 WebWork 中Action 的prepare方法调用多次的问题
  • c# 工具
  • 珍惜眼前
  • 【三维偏序】【分块】bzoj3262 陌上花开
  • Windows 7 Tips! --透明缓存(transparent caching)技术
  • tkinter之文件对话框
  • 不抛弃,不放弃,香巴拉半途之旅
  • 开启ylmf desktop ubuntu的pae支持
  • 日期转化为周次
  • 14套漂亮手机应用图标免费下载
  • Java学习路线图,Java学习计划建议
  • [转]谈谈个人网站建设和经营
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • ES6系统学习----从Apollo Client看解构赋值
  • input的行数自动增减
  • Java基本数据类型之Number
  • jquery cookie
  • jQuery(一)
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • spring cloud gateway 源码解析(4)跨域问题处理
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 简单基于spring的redis配置(单机和集群模式)
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 蓝海存储开关机注意事项总结
  • 深入浅出Node.js
  • 做一名精致的JavaScripter 01:JavaScript简介
  • 树莓派用上kodexplorer也能玩成私有网盘
  • 组复制官方翻译九、Group Replication Technical Details
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • #if #elif #endif
  • (arch)linux 转换文件编码格式
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (js)循环条件满足时终止循环
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (论文阅读30/100)Convolutional Pose Machines
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (十一)图像的罗伯特梯度锐化
  • (五)MySQL的备份及恢复
  • (一)Java算法:二分查找
  • (一)Linux+Windows下安装ffmpeg
  • (原創) 是否该学PetShop将Model和BLL分开? (.NET) (N-Tier) (PetShop) (OO)
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .Net Core 中间件验签
  • .NET Reactor简单使用教程
  • /boot 内存空间不够
  • @Autowired和@Resource的区别
  • [ vulhub漏洞复现篇 ] ThinkPHP 5.0.23-Rce
  • []FET-430SIM508 研究日志 11.3.31