2012-07-19 47 views
4

我在MFC对话框中创建了一个只读编辑框。我试图让它使用户点击编辑框,它是只读的,它打开一个文件对话框,然后使用UpdateData将该值放入文本框中。我正在捕获ON_EN_SETFOCUS消息,但在文件对话框上按下“确定”重新生成它,所以我陷入了无限循环。单击MFC编辑框

UpdateData(TRUE); 
CFileDialog fileDialog(TRUE,NULL, NULL,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, _T("Text Files(*.txt)|*.txt||")); 
if(fileDialog.DoModal() == IDOK) 
{ 
    configFile=fileDialog.GetPathName(); //Note to self, this includes filename, getPathName includes filename and path. 

} 
else 
{ 
    return; 
} 

UpdateData(FALSE); 

如果您对如何完成这件事有任何想法,我将非常感激。

+2

为什么不使用按钮?一个名为'...'的小CButton用文件对话框浏览是很常见的。 – AJG85 2012-07-19 16:26:50

+0

如果您希望在对话框中使用某些可用性,请使用AJG85的建议。没有用户会永远点击一个只读的CEdit框。 – CppChris 2012-07-19 16:41:06

+0

做到了这一点,它的工作,有两个控制似乎是无关的,并想知道是否有一个更有效的方法来做到这一点? – James 2012-07-19 16:42:55

回答

3

好的李斯特先生我想我会添加一个答案。

首先,我会在此前面介绍一下,我可能只是简单地添加一个按钮名称“...”来启动文件对话框,在编辑框右侧打开文件对话框,因为这是最简单的解决方案,用户会期待。

但是,另一种选择是扩展MFC控件。当决定扩展一个控件时,你希望选择一个主要具有所需行为的控件,并且该控件具有一个虚拟析构函数,该虚拟析构函数可以作为子类。既然你想按钮行为CButton可能是一个不错的选择。

你的类接口可能是这个样子:

class CPathButton : public CButton 
{ 
public: 
    enum { ID /*= IDC_BUTTON1*/ }; 

    const CString GetPath() const; 
    const CString GetFileName() const; 
    const CString GetDirectory() const; 
    const CString GetExtension() const; 
    // other useful methods for setting file filters etc 

protected: 
    // add ON_CONTROL(BN_CLICKED, ID, &OnClick) or ON_BN_CLICKED(ID, &OnClick) 
    DECLARE_MESSAGE_MAP() 

    // CFileDialog fdlg.DoModal(), m_path = fdlg.GetPathName(), SetWindowText(fdlg.GetFileTitle()), etc 
    afx_msg void OnClick(); 

    // additional message handlers etc 

private: 
    CString m_path; // save full path for after dialog is closed 
}; 

,你依靠,如果控制将动态创建想,你可以添加任意多或尽可能少的定制,通过资源文件,或什么的。其基本思想是在按钮上显示当前选定的文件名,同时将其他用途的完整路径存储为成员,这样用户就不需要看到具有嵌套目录的长路径的混乱。

如果您不喜欢默认情况下的显示方式,则可以覆盖OnPaint并处理WM_PAINT消息,并为长文件标题使用自定义字体,大小或添加省略号。您也可以通过使用文本指标和GetTextExtent来处理重新调整按钮的大小以适合文件标题,以确保该名称符合或仅当显示CToolTipCtrl时将鼠标悬停在按钮上方,以便他们可以看到全名。从VS2008 + MFC的功能包的CMFCButton具有内置的,所以如果你的而不是CButton继承中显示工具提示会是这么简单调用SetTooltip(m_path)

如果你想获得真正看中的,你可以使用一些工具提示功能的uxtheme API或新的windows animation API

1

您可以在对话框类中重写PreTranslateMessage(),并确定编辑控件被点击的方式:

CEdit m_CEditCtrl; 
// ... 

BOOL YourDialogClass::PreTranslateMessage(MSG *pMsg) 
{ 
    if((pMsg->wParam == VK_LBUTTON) && (m_CEditCtrl.m_hWnd == pMsg->hwnd)) 
    { 
     // open your file dialog 
     return TRUE; // Return that the message was translated and doesn't need to be dispatched 
    } 
    return CDialog::PreTranslateMessage(pMsg); 
} 

更新:你也可以(并且它可能是一个更好的主意)来覆盖你的CEdit控件的CWnd::PreTranslateMessage()函数。这需要从CEdit派生一个类。

+1

不推荐重写PreTranslateMessage,除非你真的必须这样做。 – AJG85 2012-07-19 16:59:23

+0

@ AJG85:为什么不推荐?只要遵循惯例,我就不会看到任何问题。 – 2012-07-19 17:01:18

+0

PreTranslateMessage可以在派送消息到达之前更改它们。在处理所有消息之前,处理所有消息都很诱人,但是这会导致可读性较差的代码容易出错并且难以调试。任何时候你在PreTranslateMessage中检查id或hwnds是你的提示,你应该在别处处理消息。正如你所说的源自CEdit并将其扩展到自定义行为在这种情况下可能会更好。 – AJG85 2012-07-19 17:31:19

1

如果您使用的是VS2008 SP1或更高版本,请求路径的最简单方法是使用CMFCEditBrowseCtrl。它显示一个带有按钮的编辑控件。使用它的步骤是:

  • 更改您的编辑控件的类CMFCEditBrowseCtrl
  • 呼叫EnableFileBrowseButton告诉它你想浏览的文件,而不是文件夹(你可以设置一个过滤器,默认扩展名)
  • 当用户单击该按钮时,将出现一个文件对话框,并在其中单击确定时,所选路径将写入编辑控件中。
+0

+1为最佳答案。我没有意识到该功能包中的MFC类扩展。 – AJG85 2012-07-23 16:51:43