Introduction
When I need a user to select a file or folder, I would have to create two controls, an edit control for entering the text, and a browse button that would bring up a dialog for actually choosing the file or folder. So I thought, why not combine the two controls into one. The CFileEditCtrl
class is the result. The class definition and implementation are in the files FileEditCtrl.h and FileEditCtrl.cpp which are included in the demo project.
Testing
This code has not been tested for UNICODE builds. If any bugs are found and fixed, please drop me a note.
Acknowledgements
Michael Dunn for his article Introduction to COM - What It Is and How to Use It, for showing me how to handle shortcut (*.lnk and *.pif) files.
Me for my articles CPJAImage - Yet another image drawing class and Multiple Selection in a File Dialog.
Using an image on the button
If you want to place an image (HICON
or HBITMAP
), instead of the ellipses, on the button, you have to add the PJAImage.h and PJAImage.cpp files to your project. If you do not want to use an image, you do not have to add these files to your project, but you have to ensure that the PJAImage.h file is not included in the FileEditCtrl.h file, by commenting out the #include "PJAImage.h"
(line 41) line in FileEditCtrl.h.
top
Features
- The control is derived from
CEdit
. All CEdit
member functions are CFileEditCtrl
member functions. It can be created with any of the ES_*
edit control styles. It will respond just like any other edit control to any EM_*
commands, and sends all EN_*
notification messages.
- The ellipses button is drawn in the controls non-client area. It is a part of the control, not a separate button that has to be added onto the dialog template, or otherwise created or setup. It can be placed on either the left or the right side of the control.
- The control has its own
DDX_FileEditCtrl
and DDV_FileEditCtrl
dialog data exchange functions. Setting up the control for use is very easy.
- Using the
Create()
member function, the control can be created in any window, not just dialogs or forms.
- The control can be used to browse for files or folders. And it has a member function that can be used to switch between the two. When the
CFileDialog
or SHBrowseForFolder
dialogs are opened, they will be set to the directory currently entered in the control.
- The control accepts relative paths. Users can enter
..\..\anyfolder
and the control will return the absolute path relative to the current working directory. Entering '.
' will return the current working directory. If the FEC_MULTIPLE
flag is set, the first file entered will be relative to the current directory, and all subsequent files will be relative to the first file, unless the absolute path is entered.
- The control accepts wildcards ( '*' and/or '?' ) in the file name. Just set the
FEC_WILDCARDS
flag.
- The control will automatically dereference shortcut (*.lnk) files. To disable this feature, just set the
FEC_NODEREFERENCELINKS
flag.
- The control accepts Drag and Drop files and folders. Just create it with the
WS_EX_ACCEPTFILES
extended Windows style. When a drop action occurs, the control sends a WM_NOTIFY
message to its parent window.
- Member functions give access to the internal
BROWSEINFO
and OPENFILENAME
structures, so if the default settings are not satisfactory, there is complete control over how the CFileDialog
and SHBrowseForFolder
dialogs are implemented.
- The control is resizable. The button keeps its proportionate size relative to the height of the control. As the control gets taller, the button gets bigger, and so does the dots on the button.
- The
CFileDialog
has the text on its default button changed from 'Open'
to 'OK
'.
- When the ellipses button is clicked, the control sends a
WM_NOTIFY
message to its parent window, giving the parent window a chance to stop the SHBrowseForFolder
or CFileDialog
from popping up. The <Ctrl><.> keystroke has the same action as a click on the button.
- The button can have an icon or bitmap displayed on it instead of the ellipses.
- The control can be drawn as a flat, hot to mouse control.
top
Using the Control
To use this control in your application, Add the FileEditCtrl.h and FileEditCtrl.cpp files to your project. Then it is recommended to add the text strings defined at the top of the FileEditCtrl.cpp file to your string table resource, using the FEC_IDS_*
identifiers defined there.
#if !defined FEC_IDS_ALLFILES
#define FEC_NORESOURCESTRINGS so this class knows how to handle these strings
#define FEC_IDS_ALLFILES _T("All Files (*.*)|*.*||")
#define FEC_IDS_BUTTONTIP _T("Browse")
#define FEC_IDS_FILEDIALOGTITLE _T("Browse for File")
#define FEC_IDS_SEPERATOR _T(";")
#define FEC_IDS_NOFILE _T("Enter an existing file.")
#define FEC_IDS_NOTEXIST _T("%s does not exist.")
#define FEC_IDS_NOTFILE _T("%s is not a file.")
#define FEC_IDS_NOTFOLDER _T("%s is not a folder.")
#define FEC_IDS_OKBUTTON _T("OK")
#endif
To use the control on a dialog, using all the default settings, add an edit control to the dialog template, add a CString
member variable to the dialog class, and in DoDataExchange()
add the DDX_FileEditCtrl()
and DDV_FileEditCtrl()
functions. The default settings for the SHBrowseForFolder
dialog has the BIF_RETURNONLYFSDIRS
flag set. And the default settings for the CFileDialog
dialog has the OFN_HIDEREADONLY
, OFN_FILEMUSTEXIST
and OFN_NOCHANGEDIR
flags set, the file filter is set to the FEC_IDS_ALLFILES
resource string, and the dialog caption is set to the FEC_IDS_FILEDIALOGTITLE
resource string. If you want the control to be used for folders, set the flag in last parameter in DDX_FileEditCtrl()
to FEC_FOLDER
, and for files set it to FEC_FILEOPEN
to use the File Open dialog, and FEC_FILESAVEAS
to use the File Save As dialog.
If you want more control over the dialogs, such as choosing multiple files, then you have to add a CFileEditCtrl
variable to your dialog class. In DoDataExchange()
, add the second version of DDX_FileEditCtrl()
. And then get a pointer to the OPENFILENAME
or BROWSEINFO
structures, using the GetOpenFileName()
or GetBrowseInfo()
functions, and set them accordingly. In the demo app, I have an edit control with an ID of IDC_EDIT1
and a CFileEditCtrl
variable m_FileEditCtrl
.
void CFileEditDemoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
...
DDX_FileEditCtrl(pDX, IDC_EDIT1, m_FileEditCtrl, FEC_FILEOPEN);
...
}
Because these functions are not supported by Class Wizard, they have to be placed outside the AFX_DATA_MAP
code block. If you would like to add Class Wizard support, see MFC Technical Note 26 DDX and DDV routines and look under ClassWizard.
To retrieve the file names from the control, use the GetStartPosition()
and GetNextPathName()
member functions. In the demo app, I did this in the CDumpDialog::OnInitDialog()
function, in order to fill the list box with the files entered by the user.
BOOL CDumpDialog::OnInitDialog()
{
CDialog::OnInitDialog();
CFileEditDemoDlg *pDemo = (CFileEditDemoDlg *)GetParent();
int width = 0;
CString str;
CDC *pDC = m_List.GetDC();
int saved = pDC->SaveDC();
pDC->SelectObject(GetFont());
POSITION pos = pDemo->m_fileeditctrl.GetStartPosition();
while (pos)
{
str = pDemo->m_fileeditctrl.GetNextPathName(pos);
m_List.AddString(str);
CSize size(0, 0);
size = pDC->GetTextExtent(str);
width = width > size.cx ? width : size.cx;
}
pDC->RestoreDC(saved);
ReleaseDC(pDC);
m_List.SetHorizontalExtent(width + 5);
return TRUE;
}
top
FEC_NOTIFY structure
typedef struct tagFEC_NOTIFY {
NMHDR hdr;
CFileEditCtrl* pFEC;
CString *pNewText;
tagFEC_NOTIFY (CFileEditCtrl *FEC, UINT code);
} FEC_NOTIFY;
#define FEC_NM_PREBROWSE 1
#define FEC_NM_POSTBROWSE 2
#define FEC_NM_DROP 3
When a user clicks on the browse button, the control will send a WM_NOTIFY
message with a FEC_NM_PREBROWSE
notification code to its parent window before it brings up the SHBrowseForFolder
or CFileDialog
dialogs. The NMHDR*
pointer will point to a FEC_NOTIFY
structure. The pFEC
member will point to the CFileEditCtrl
that sent the message. You can use this pointer to modify the OPENFILENAME
or BROWSEINFO
structures. If you set the LRESULT
parameter of the OnNotify
handler to a nonzero value, you will stop the dialogs from executing.
If you want to use the browse button to start a dialog, or other functions, other than the CFileDialog
or SHBrowseForFolder
, simply call and handle your dialog in the FEC_NM_PREBROWSE
handler. Be sure to set the LRESULT
parameter to nonzero.
The control will send another WM_NOTIFY
message with a FEC_NM_POSTBROWSE
notification code after the browse dialog is closed but before the control's window text has been updated. The NMHDR*
pointer will once again point to a FEC_NOTIFY
structure. If the pNewText
parameter is NULL
, the dialog was cancelled. If it is not NULL
, it will be a pointer to a CString
containing the new text. If you set the LRESULT
parameter of the OnNotify
handler to a nonzero value, you will stop the control from updating.
The control also sends a WM_NOTIFY
message with the FEC_NM_DROP
notification code after the user drags and drops a file or folder onto the control, but before the control updates its text. Once again, setting the LRESULT
parameter of the OnNotify
handler to a nonzero value will stop the control from updating.
top
User Functions
These are the public member functions that are used to control the CFileEditCtrl
class.
CFileEditCtrl::CFileEditCtrl(BOOL bAutoDelete )
CFileEditCtrl constructor
Initializes all the internal variables.
Parameters:
bAutoDelete
[in] - Auto delete flag
Returns:
Nothing.
Note:
If bAutoDelete
is TRUE
, this class object will be deleted when its window is destroyed (in CFileEditCtrl::PostNCDestroy
). The only time this should be used is when the control is created dynamically in the DDX_FileEditCtrl(CDataExchange*,int,CString&,DWORD)
function.
User Functions CFileEditCtrl::~CFileEditCtrl()
CFileEditCtrl destructor
Cleans up internal data variables.
Parameters:
None
Returns:
Nothing.
User Functions BOOL CFileEditCtrl::Create(DWORD dwFlags,
DWORD dwExStyle,
LPCTSTR lpszWindowName,
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID)
CFileEditCtrl::Create
Creates the CFileEditCtrl
in any window.
Parameters:
dwFlags |
[in] |
- CFileEditCtrl flags (FEC_* ) |
dwExStyle |
[in] |
- Windows extended styles (WS_EX_* ) |
lpszWindowName |
[in] |
- The initial text in the control |
dwStyle |
[in] |
- Windows and Edit control styles (WS_* and ES_* ) |
rect |
[in] |
- The position and size of the control |
pParentWnd |
[in] |
- Pointer to the control's parent window |
nID |
[in] |
- The control's ID |
Returns:
TRUE
if the control was successfully created. FALSE
if not.
Note:
See SetFlags() below for descriptions of the flags used.
User Functions DWORD CFileEditCtrl::GetFlags()
CFileEditCtrl::GetFlags
Retrieves the current flags.
Parameters:
None.
Returns:
The current flags.
Note:
See SetFlags() below for descriptions of the flags used. Because some flags can be changed via GetOpenFileName()
, always use this function to get the current state of the flags.
User Functions BOOL CFileEditCtrl::ModifyFlags(DWORD remove,
DWORD add)
CFileEditCtrl::ModifyFlags
Modifies the control flags.
Parameters:
remove |
[in] |
- The flags to remove |
add |
[in] |
- The flags to add |
Returns:
TRUE
if the flags are successfully modified. FALSE
if not.
Note:
See SetFlags() below for descriptions of the flags used.
User Functions BOOL CFileEditCtrl::SetFlags(DWORD dwFlags)
CFileEditCtrl::SetFlags
- Sets all the internal flags.
- Initializes and sets up the
OPENFILENAME
or BROWSEINFO
structures.
- Forces the control to be redrawn if the button position changes.
Parameters:
dwFlags
[in] - The flags to set.
Returns:
TRUE
if successful. FALSE
if not.
Note:
The following table describes the flags used in the dwFlags
parameter.
dwFlags |
Purpose |
FEC_FILEOPEN |
The control is set to accept files. When the ellipses button is clicked, the control starts the Windows Common File Open dialog. This flag cannot be used with the FEC_FOLDER nor FEC_FILESAVEAS flags. |
FEC_FILESAVEAS |
The control is set to accept files. When the ellipses button is clicked, the control starts the Windows Common File Save As dialog. This flag cannot be used with the FEC_FOLDER nor FEC_FILEOPEN flags. |
FEC_MULTIPLE |
Used with FEC_FILEOPEN . The control will accept multiple files. Has the same effect as the OFN_ALLOWMULTISELECT flag. |
FEC_MULTIPLEFILES |
Combination of FEC_FILEOPEN and FEC_MULTIPLE |
FEC_WILDCARDS |
Used with FEC_FILEOPEN . The control will accept and resolve any wildcards ('*' and/or '?') in the file name. If the FEC_MULTIPLE flag is set, GetNextPathName() will return all the files that match. If FEC_MULTIPLE is not set, GetNextPathName() will return only the first match. |
FEC_NODEREFERENCELINKS |
Used with FEC_FILEOPEN . GetNextPathName() will return the path name of any shortcut (*.lnk) files entered. If this flag is not set, GetNextPathName() will return the path name of the file the shortcut points to. Has the same effect as the OFN_NODEREFERENCELINKS flag. |
FEC_FOLDER |
The control is set to accept folders. When the ellipses button is clicked, the control starts the SHBrowseForFolder dialog. This flag cannot be used with the FEC_FILEOPEN nor FEC_FILESAVEAS flag. |
FEC_TRAILINGSLASH |
Used with FEC_FOLDER . The folder path entered in the control will have a trailing slash. |
FEC_BUTTONLEFT |
The ellipses button will be placed on the left side of the control. |
FEC_BUTTONTIP |
Enables the browse button tooltip. The tooltip text is set with the FEC_IDS_BUTTONTIP resource string. |
FEC_CLIENTTIP |
Enables the client area tooltip. The tooltip text is set with the SetClientTipText() member function. |
FEC_FLAT |
Sets the control to be drawn as a flat, hot to mouse control. |
FEC_GRAYSCALE |
Used with FEC_FLAT . The dots or image on the button will be drawn in grayscale when the control is flat. They are drawn in color when the control is active/hot. |
User Functions void CFileEditCtrl::SetClientTipText(CString text)
CFileEditCtrl::SetClientTipText
Sets the text to be used by the client area tooltip.
Parameters:
text
[in] - The text to set
Returns:
Nothing.
User Functions BROWSEINFO* CFileEditCtrl::GetBrowseInfo() const
CFileEditCtrl::GetBrowseInfo
Retrieve a pointer to the BROWSEINFO
structure.
Parameters:
None.
Returns:
A pointer to the BROWSEINFO
structure if the FEC_FOLDER
flag was set. NULL
otherwise.
Note:
If the default SHBrowseForFolder
settings do not fit your use, use the pointer returned by this function to set up the SHBrowseForFolder
using your own settings.
User Functions OPENFILENAME* CFileEditCtrl::GetOpenFileName() const
CFileEditCtrl::GetOpenFileName
Retrieves a pointer to the OPENFILENAME
structure.
Parameters:
None.
Returns:
A pointer to the OPENFILENAME
structure if the FEC_FILE
flag was set. NULL
otherwise.
Note:
If the default CFileDialog
settings do not fit your use, use the pointer returned by this function to set up the CFileDialog
using your own settings.
User Functions POSITION CFileEditCtrl::GetStartPosition()
CFileEditCtrl::GetStartPosition
Gets the starting position for the GetNextPathName() function.
Parameters:
None.
Returns:
A MFC POSITION
structure that points to the first file in the control.
User Functions CString CFileEditCtrl::GetNextPathName(POSITION &pos)
CFileEditCtrl::GetNextPathName
Returns the file name at the specified position in the buffer.
Parameters:
pos |
[in] |
- The position of the file name to retrieve |
|
[out] |
- The position of the next file name |
Returns:
The complete path name of the file or folder.
Note:
The starting position is retrieved using the GetStartPosition() function. pos
will be set to NULL
when there are no more files.
User Functions int CFileEditCtrl::SetButtonWidth(int width)
CFileEditCtrl::SetButtonWidth
Sets the width, in pixels, of the browse button.
Parameters:
width
[in] - The new width of the button
Returns:
The previous width of the button.
Note:
Setting the width to -1 causes the control to use the default width which is calculated to be 80% of its height.
User Functions int CFileEditCtrl::GetButtonWidth()
CFileEditCtrl::GetButtonWidth
Retrieves the width, in pixels, of the browse button.
Parameters:
None.
Returns:
The width of the browse button.
User Functions void CFileEditCtrl::SetButtonImage(HANDLE hImage,
DWORD PJAIFlags,
COLORREF Transparent)
CFileEditCtrl::SetButtonImage
Sets the image to be used on the browse button.
Parameters:
hImage |
[in] |
- Handle of the image (can be a HBITMAP or HICON ) |
PJAIFlags |
[in] |
- The image flags (see the note below) |
Transparent |
[in] |
- The transparent color on the bitmap. If CLR_DEFAULT is used, the color of the top left pixel is used as the transparent color. |
Returns:
TRUE
if a new image is set. FALSE
if not.
Note:
The PJAImage.h file must be included (see lines 37 to 41 of FileEditCtrl.h) in order for this function to work.
Flags used in the PJAIFlags
parameter:
PJAI_BITMAP |
The given handle is an HBITMAP |
PJAI_ICON |
The given handle is an HICON |
PJAI_AUTODELETE |
The given handle will be deleted and the memory freed when a new image is set or the CFileEditCtrl object is deleted. If this flag is not set, the user of this class is responsible for freeing the image handle when it is no longer needed |
PJAI_STRETCHED |
Draws the image so that it fills the button. |
PJAI_TRANSPARENT |
Draws the bitmap image transparently. This flag has no effect if the image is an icon, as icons are transparent by default. |
User Functions
Data Exchange Functions
void DDV_FileEditCtrl (CDataExchange *pDX,
int nIDC)
DDV_FileEditCtrl
Verifies that the files or folders entered actually exist.
Parameters:
pDX |
[in] |
- Pointer to the CDataExchange object |
nIDC |
[in] |
- The control's resource ID |
Returns:
Nothing.
Note:
If the file or folder is invalid, pops up a message box informing the user, then sets the focus to the offending CFileEditCtrl
.
User Functions void DDX_FileEditCtrl (CDataExchange *pDX,
int nIDC,
CFileEditCtrl &rCFEC,
DWORD dwFlags)
DDX_FileEditCtrl
Subclasses the control with the given ID. Transfers the data between the window text and the supplied CFileEditCtrl
.
Parameters:
pDX |
[in] |
- Pointer to the CDataExchange object |
nIDC |
[in] |
- The control's resource ID |
rCFEC |
[in] |
- The CFileEditCtrl object that is to control this window |
dwFlags |
[in] |
- The flags used to setup this control |
Returns:
Nothing.
Note:
See SetFlags() above for descriptions of the flags used.
User Functions top
The Button
In order to get the button to work, I first had to override the OnNcCalcSize()
function. This is the function that is used to calculate the size and position of a Windows client area. In my override, I called CEdit::OnNcCalcSize()
to get the default size and position of the client area, then I adjusted the size of the client area and calculated the size and position of the button. The CRect m_rcButtonRect
member variable is used to store this information.
void CFileEditCtrl::OnNcCalcSize(BOOL bCalcValidRects,
NCCALCSIZE_PARAMS FAR* lpncsp)
{
CEdit::OnNcCalcSize(bCalcValidRects, lpncsp);
m_rcButtonRect = lpncsp->rgrc[0];
if (m_bButtonLeft)
{
lpncsp->rgrc[0].left +=
(lpncsp->rgrc[0].bottom - lpncsp->rgrc[0].top) * 8/10;
m_rcButtonRect.right = lpncsp->rgrc[0].left;
}
else
{
lpncsp->rgrc[0].right -=
(lpncsp->rgrc[0].bottom - lpncsp->rgrc[0].top) * 8/10;
m_rcButtonRect.left = lpncsp->rgrc[0].right;
}
if (bCalcValidRects)
m_rcButtonRect.OffsetRect(-lpncsp->rgrc[1].left,
-lpncsp->rgrc[1].top);
m_rcButtonRect.NormalizeRect();
}
The only time OnNcCalcSize()
is called is when the windows frame has changed, so to force a call to OnNcCalcSize()
, I had to call SetWindowPos()
from SetFlags()
, using the SWP_FRAMECHANGED
flag.
BOOL FileEditCtrl::SetFlags(DWORD dwFlags)
{
...
SetWindowPos(NULL,0,0,0,0,
SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|
SWP_NOZORDER|SWP_NOACTIVATE);
...
}
I then needed to paint the button on the control, so I wrote the DrawButton()
function. Because the button is not in the client area of the window, DrawButton()
has to be called from OnNcPaint()
.
void CFileEditCtrl::OnNcPaint()
{
CEdit::OnNcPaint();
DrawButton (m_nButtonState);
}
The next thing was to get mouse messages for the button. Because the button is not in the client area, it would not get client area mouse messages, and because it is not a border, it would not get non-client mouse messages. To solve this problem, I had to override OnNcHitTest()
and get it to return HT_BORDER
when the mouse cursor was over the button.
UINT CFileEditCtrl::OnNcHitTest(CPoint point)
{
...
UINT where = CEdit::OnNcHitTest(point);
if (where == HTNOWHERE && ScreenPointInButtonRect(point))
where = HTBORDER;
return where;
}
Now a mouse press on the button would generate a WM_NCLBUTTONDOWN
message, so I had to override OnNcLButtonDown()
. In OnNcLButtonDown()
, I would capture the mouse using SetCapture()
and call DrawButton()
to draw the button as down. Because once the mouse is captured, it no longer generates non-client mouse messages, I would have to respond to WM_LBUTTONUP
and WM_MOUSEMOVE
messages in order to keep track of the mouse. Because CEdit::OnLButtonDown
also captures the mouse, I could not use GetCapture
to see if the button had captured the mouse, so I added the BOOL m_bMouseCaptured
variable to keep track of it.
void CFileEditCtrl::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
CEdit::OnNcLButtonDown(nHitTest, point);
...
if (ScreenPointInButtonRect(point))
{
SetCapture();
m_bMouseCaptured = TRUE;
SetFocus();
DrawButton(BTN_DOWN);
}
}
By overriding OnMouseMove()
, I could keep track of the captured mouse, and draw the button as down if the mouse cursor was over the button, or as up if it was not.
void CFileEditCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
CEdit::OnMouseMove(nFlags, point);
...
if (m_bMouseCaptured)
{
ClientToScreen(point);
if (ScreenPointInButtonRect(point))
{
if (m_nButtonState != BTN_DOWN)
DrawButton (BTN_DOWN);
}
else if (m_nButtonState != BTN_UP)
DrawButton (BTN_UP);
}
}
In the override of OnLButtonUp
, the mouse capture is released, the m_bMouseCaptured
flag is cleared, and if the mouse cursor is over the button, the ButtonClicked()
function is called. The ButtonClicked()
function opens the appropriate dialog and sends a WM_NOTIFY
notification message to the control's parent window.
void CFileEditCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
CEdit::OnLButtonUp(nFlags, point);
...
if (m_bMouseCaptured)
{
ReleaseCapture();
m_bMouseCaptured = FALSE;
if (m_nButtonState != BTN_UP)
DrawButton(BTN_UP);
ClientToScreen(point);
if (ScreenPointInButtonRect(point))
ButtonClicked();
}
}
top
Revision History
- Created October 2000
- November 11, 2000 - allowed the control to work with dialog templates
- November 22, 2000 - registers the control's window class, can now be added to dialog as custom control
- January 4, 2001
- near total rewrite of the control, now derived from
CEdit
- control can now be added to dialog template using an edit control
- browse button now drawn in non-client area of the control
- January 5, 2001 - removed
OnKillFocus()
, replaced with OnDestroy()
- January 15, 2001
- added
DDX_
and DDV_
support
- modified
GetStartPosition()
and GetNextPathName()
- modified how
FECOpenFile()
updates the control text when multiple files are selected
- added
FillBuffers()
- added support for relative paths
- added
OnChange
handler
- added drag and drop support
- January 26, 2001 - fixed bug where
SHBrowseForFolder
does not like trailing slash
- January 27, 2001 - fixed bug where if control is initialized with text,
FillBuffers
was not called.
- January 28, 2001
- removed
GetFindFolder()
and SetFindFolder()
; replaced with GetFlags()
and SetFlags()
- modified the
DDX_
and DDV_
functions to accept these flags
- modified the
Create()
function to accept these flags
- allowed option for returned folder to contain trailing slash
- allowed browse button to be on the left side of the control
- added
ScreenPointInButtonRect()
to better tell if mouse cursor is over the button
- modified how
OnDropFiles()
updates the control text when multiple files are dropped
- February 25, 2001 - fixed
EN_CHANGE
notification bug. Now parent window receives this notification message, used ON_CONTROL_REFLECT_EX
macro instead of ON_CONTROL_REFLECT
- April 12, 2001 - added
OnSize
handler, fixed button drawing problem when control size changed
- April 21, 2001 - added a tooltip for the browse button
- May 12, 2001
- removed
OnDestroy
, replaced with PostNCDestroy
- added tooltip support to client area
- modified the
FECBrowseForFolder
and FECFolderProc
functions
- added a one pixel neutral area between the client area and browse button when the button is on the right hand side of the control. (looks better IMO)
- May 29, 2001
- PL -- removed the filename from the
m_pCFileDialog->m_ofn.lpstrInitialDir
variable, so when browsing back for file, we open the correct folder.
- used smaller (exact size) arrays for file, extension and path components.
- some cosmetic changes.
- May 29, 2001 -
FECFolderProc
now checks for UNC path. SHBrowseForFolder
cannot be initialized with UNC
- June 2, 2001 - modified
ButtonClicked
function. Now sends a WM_NOTIFY
message to parent window before showing dialog, allows parent window to cancel action by setting result to nonzero. Also sends WM_NOTIFY
message to parent window after dialog closes with successful return
- June 9, 2001 - added
OnNcLButtonDblClk
handler. Double click on button now treated as two single clicks
- June 23, 2001
- placed a declaration for the
FECFolderProc
global callback function into the header file
- fixed bug that occurred when removing the filename from the
m_pCFileDialog->m_ofn.lpstrInitialDir
variable when there was no file to remove.
- August 2, 2001 - replaced
SetWindowText()
with OnSetText()
message handler. Now correctly handles WM_SETTEXT
messages
- August 12, 2001
- added
GetValidFolder()
function and modified FECOpenFile()
function. We now start browsing in the correct folder -- it finally works!!! {:o)
- modified
SetFlags()
so the button could be moved by setting the FEC_BUTTONLEFT
flag
- removed the
m_bCreatingControl
variable
- removed the call to
SetWindowPos()
from the Create()
and DDX_FileEditCtrl()
functions. Now done in SetFlags()
function
- August 14, 2001 - modified
FECOpenFile()
. Now sets the file name in CFileDialog
to first file name in FileEditCtrl
- August 18, 2001 - Set the tooltip font to the same font used in the
CFileEditCtrl
- September 2, 2001
- added the
ModifyFlags()
function and changed how the flags are handled
- modified the
GetFlags()
function
- added the
FEC_MULTIPLE
and FEC_MULTIPLEFILES
flags
- added support for wildcards ( '*' and '?') in filenames
Involved:
- modifying the
GetStartPosition()
, GetNextPathName()
, SetFlags()
, and FillBuffers()
functions
- adding the
ExpandWildCards()
function
- replacing the
m_lpstrFiles
variable with the m_Files
array
- adding the
FEC_WILDCARDS
flag.
- September 3, 2001
- added ability to dereference shortcut files (*.lnk)
- added the
FEC_NODEREFERENCELINKS
flag.
- added the
DereferenceLink()
function.
- September 5, 2001 - fixed the
Create()
function - now destroys the control if the SetFlags()
function fails
- September 8, 2001
- added the
AddFiles()
function to be better able to handle shortcut (*.lnk) files
- modified the
OnDropFiles()
function to be better able to handle shortcut (*.lnk) files
- September 12, 2001
- PR -- added
#include <shlobj.h>
to the FileEditCtrl.h header file
- UNICODE fixes, added
_T()
macro in Create()
function and in TRACE()
calls.
- PR states that the code now works perfectly with UNICODE builds and UNC paths. {:o) {:o) {:o) {:o) {:o) {:o)
- September 18, 2001 - added ability to use icons or bitmaps on the browse button
Involved:
- adding
SetButtonImage()
function.
- modifying the
DrawButton()
function
- adding the
FECButtonImage
class.
- September 20, 2001
- fixed resource leak in
FECButtonImage
class
- cleaned up the
FECButtonImage
class code
- added ability to resize the browse button
Involved:
- adding
m_nButtonWidth
variable
- adding
SetButtonWidth()
and GetButtonWidth()
functions
- modifying
OnNcCalcSize()
and DrawButton()
functions
- September 24, 2001 - fixed bug in
GetNextPathName()
and ExpandWildCards()
where multiple files could not start from the current drive. i.e. \folder\file.ext as second file would give an error
- September 26, 2001 - fixed bug in
GetNextPathName()
to allow incomplete relative paths (i.e. ..\..\) when browsing for files.
- October 5, 2001 - PR -- Added
#include <afxcmn.h>
to the CFileEditCtrl.h header file
- October 14, 2001
- rewrote the
FECButtonImage::DrawImage()
function, it now handles disabled transparent bitmaps better (the transparent color can be any color, no longer just light colors), and now also handles pattern and bitmap background brushes
- various other touch ups (comments mostly)
- November 20, 2001 - added ability to dereference *.pif (shortcut to MS-DOS) files
- November 26, 2001 - added ability to be flat, hot to mouse (
FEC_FLAT
flag)
Involved:
- adding
OnKillFocus()
, OnLButtonDown()
and OnNCMouseMove()
message handlers
- adding
Redraw()
and SetReadOnly()
member functions
- modifying
OnEnable()
, OnMouseMove()
, OnNCPaint()
and OnSetFocus()
message handlers
- modifying
DrawButton()
and SetFlags()
member functions
- modifying the
CFECButtonImage::DrawImage()
function
- December 1, 2001 - clean up code from November 26, 2001
- December 5, 2001 - added the
FEC_GRAYSCALE
flag. Flat buttons can be drawn in full color or grayscale.
- December 8, 2001 - greatly improved the button drawing code.
- December 18, 2001
- removed the
CFECButtonImage
class, replaced with the CPJAImage
class.
- rewrote the
SetButtonImage()
function.
- rewrote the
DrawButton()
function.
- January 7, 2002 - Remon -- added the
FEC_NM_DROP
notification. The control now sends a WM_NOTIFY
message to its parent window after a file or folder has been dropped onto it.
- January 14, 2002 - fixed a bug that prevented the tooltips from displaying properly.
- February 18, 2002 - replaced
SetReadOnly()
with OnSetReadOnly()
, the control now properly handles the EM_SETREADONLY
message.
- March 27, 2002 - fixed border drawing when control is drawn flat. Now the control does not appear to change size when it switches from edit mode to readonly or disabled.
- March 28, 2002
- moved the
FEC_NM_POSTBROWSE
notification. Now it is sent after the dialog closes, but before the edit control's text is updated. The parent window can now return a nonzero value to stop the edit control from updating.
Involved:
- modifying the
ButtonClicked()
, FECBrowseForFolder()
and FECOpenFile()
functions
- adding the
pNewText
pointer to the FEC_NOTIFY
structure
- modified
FEC_NM_DROP
notification. The parent window can now return a nonzero value to stop the edit control from updating.
- April 1, 2002 - Removed the
CStringArray
used to store file names, now using a linked list (CStringList
)
Involved:
- modifying the
AddFile()
, GetStartPosition()
, GetNextPathName
and FillBuffers()
functions
- April 2, 2002 - Added the ability for the
CFECFileDialog
to dynamically manage the memory needed by the lpstrFile
member of the OPENFILENAME
structure. (Thanks to Philippe Lhoste)
Involved:
- adding the
DoModal()
, OnFileNameChange()
and Reset()
functions to the CFECFileDialog
class
- modifying the
FECOpenFile()
function.
- November 23, 2002 - The April 2, 2002 changes did not work with WinNT and above. No idea why not. I fixed it by adding the
GetStartPosition()
and GetNextPathName()
functions and a destructor to the CFECFileDialog
class. I also removed the Reset()
function, and modified the DoModal()
and FECOpenFile()
functions.
- December 4, 2002
- Added the
FEC_FILEOPEN
and FEC_FILESAVEAS
flags. FEC_FILEOPEN
replaces the FEC_FILE
flag. The FEC_FILESAVEAS
flag causes the browse button to open the 'File Save As' dialog.
- Improved the drawing code for flat control
top
Be sure to check here for the latest updates.