在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;}

         }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的实现: 首先,在MFC创建一个对话框应用程序,然后在对话框添加一个列表件(ID为IDC_LIST1)。 接下来,在对话框类的头文件(比如MyDlg.h)添加以下成员变量和成员函数: ```cpp // 成员变量 CString m_strFilePath; // 文件路径 CListCtrl m_listCtrl; // 列表件 // 成员函数 afx_msg void OnBnClickedButtonAdd(); // 添加按钮的响应函数 afx_msg void OnBnClickedButtonRead(); // 读取按钮的响应函数 ``` 在OnInitDialog()函数添加以下代码: ```cpp // 初始化文件路径为空 m_strFilePath.Empty(); // 初始化列表件 m_listCtrl.Attach(GetDlgItem(IDC_LIST1)->GetSafeHwnd()); m_listCtrl.InsertColumn(0, _T("Content"), LVCFMT_LEFT, 200); ``` 这里,我们使用Attach()函数将m_listCtrl与IDC_LIST1件关联,并使用InsertColumn()函数为列表添加一列,列标题为“Content”,宽度为200像素,对齐方式为左对齐。 然后,在对话框类的源文件(比如MyDlg.cpp)实现OnBnClickedButtonAdd()和OnBnClickedButtonRead()函数: ```cpp void CMyDlg::OnBnClickedButtonAdd() { // 打开文件对话框,获取文件路径 CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_READONLY, _T("Text Files (*.txt)|*.txt|All Files (*.*)|*.*||"), this); if (dlg.DoModal() == IDOK) { m_strFilePath = dlg.GetPathName(); // 保存文件路径 // 打开文件,读取数据并添加到列表 CStdioFile file; if (file.Open(m_strFilePath, CFile::modeRead)) { CString strLine; while (file.ReadString(strLine)) { m_listCtrl.InsertItem(0, strLine); } file.Close(); } } } void CMyDlg::OnBnClickedButtonRead() { // 清空列表件 m_listCtrl.DeleteAllItems(); // 打开文件,读取数据并添加到列表 CStdioFile file; if (file.Open(m_strFilePath, CFile::modeRead)) { CString strLine; while (file.ReadString(strLine)) { m_listCtrl.InsertItem(0, strLine); } file.Close(); } } ``` 这里,我们使用CFileDialog类打开文件对话框,让用户选择要添加或读取的数据文件。然后,我们使用CStdioFile类打开文件,并逐行读取数据,将其添加到列表。注意,我们在添加之前要先清空列表件,以免重复添加数据。 在OnBnClickedButtonRead()函数,我们先清空列表件,然后再将数据添加到列表。这里,我们使用InsertItem()函数将每一行数据都插入到列表件的第一行。 最后,在对话框类的头文件添加以下宏定义: ```cpp #define IDC_LIST1 1000 ``` 这里,我们给列表件一个ID号,以便在对话框创建列表件时使用。 这样,我们就完成了一个简单的基于对话框添加和读取文本文件数据的程序,并将数据显示在CListCtrl件上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值