Introduction
When new common file dialogs were first introduced, I immediately liked the way they looked. But I also noticed that drop-down list of drives and directories seemed a bit awkward, especially if you wanted to flip between two directories on different drives. When we started hearing same thing from our customers, I knew we should try to make it easier to pick a folder.
Implementation notes
My initial thought was, OK, CFileDialog is a common dialog just like CFontDialog
, all I have to do is copy the dialog template and insert my own controls. It turns out that customizing CFileDialog
is completely different than customizing CFontDialog
. (My article XFontDialog - Customizing CFontDialog Part I: Adding Font Filters explains how to customize CFontDialog
). I found a reasonably complete description of what was going on in the MSDN article Open and Save As Dialog Boxes. This article explains that, to add controls to the CFileDialog
dialog, what you do is create a dialog template that contains only the controls that you want to add. IDD_XFILEDIALOG
is defined as:
IDD_XFILEDIALOG DIALOG DISCARDABLE 0, 0, 360, 20
STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Recent folders:",IDC_MRU_CAPTION,13,3,51,8,
SS_CENTERIMAGE | NOT WS_GROUP
COMBOBOX IDC_MRU_COMBO,85,1,260,102,CBS_DROPDOWN |
CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
END
Note the styles of this dialog - they are necessary for proper integration with CFileDialog
. Once you have this dialog defined, you can add it to CFileDialog
in ctor
of your derived class:
SetTemplate(0, _T("IDD_XFILEDIALOG"));
I set up dialog template and its rc file according to guidelines I described in my article XDialogImport - How to share dialogs between projects.
Once I had dialog template, I then started to unravel secrets of how to integrate with CFileDialog
. As I said before, it is completely different than CFontDialog
. Whereas with CFontDialog
all controls are on one dialog, with a customized CFileDialog
you have two levels of dialogs: the new IDD_XFILEDIALOG
actually is a child of original CFileDialog
. This is alluded to in MSDN article, but I did not fully appreciate what this meant, until I saw it using one of my favorite tools, HPS HwndSpy:
As you see in the screenshot, IDD_XFILEDIALOG
is highlighted in window tree, and it is child of "Open" dialog. What this means in terms of implementation of CXFileDialog
is that you can access all controls on IDD_XFILEDIALOG
just like you would on any other dialog - by using GetDlgItem()
or by using DDX_Control
. However, all controls of CFileDialog
are sibling to IDD_XFILEDIALOG
- to access them, you must use GetParent()->GetDlgItem(xxx)
. Once I understood this, rest of the code was easy to implement - well, most of it was easy. There were still a few more things that bit me.
Before getting into more details, let me show you what I was attempting to do. I wanted to add a history combo box for most-recently used folders, so that every time user clicked Open, the current folder would be added to history list. Every time CXFileDialog
was opened, history list items would be restored to combo box (if they were still valid directories). I decided to use Paul Vickery's excellent History ComboBox to take care of loading and saving folder items, with a modification I made to allow checking folders for validity. Here is what XFileDialog
looks like:
Of course there were usual details to take care of - like positioning and sizing IDD_XFILEDIALOG
controls in the OnSize()
handler. But when I tested CXFileDialog
with pre-Win2K layout, I discovered that "File Name" control ID actually had two different values - one (1152) for when it was acting like an edit box (pre-Win2K), and another value (1148) for when it was acting like a combo box (Win2K and later). Furthermore, File Name control was also affected by a registry setting, which can be used to enable/disable the MRU property of the File Name control. How did I figure this out? Again, I used HPS HwndSpy:
The next thing that I tested was Read-Only checkbox. Naturally, when I enabled it, the checkbox positioned itself right on top of my Recent Folders control, since I had forgotten to account for checkbox in OnSize()
.
Finally, I tested pre-Win2K layout. There was not enough room for the static label "Recent folders", so for pre-Win2K layout, I moved all combo boxes to the right. Here is the new pre-Win2K layout:
CXFileDialog Features
Here are features in new CXFileDialog
:
- Recent folders MRU combo box - adds a combo box with list of most-recently used folders. Selecting a folder from the list will change the file display to that folder.
SetTitle()
- Provides a convenient way to set title of dialog.
SetOsVersion()
- Allows you to choose between old-style and Explorer-style dialog.
GetPath()
- Gets path of selected file.
How to use
To integrate CXFileDialog
into your app, you first need to add following files to your project:
- XFileDialog.cpp
- XFileDialog.h
- XFileDialog.rc
- XFileDialogRes.h
- XHistoryCombo.cpp
- XHistoryCombo.h
You also need to add XFileDialog.rc to project rc file - go to View | Resource Includes... and in the bottom listbox, scroll down to the end. Insert #include "XFileDialog.rc"
right before the #endif
:
Next, include header file XFileDialog.h in appropriate project files. Now you are ready to start using CXFileDialog
.
Demo App
The XFileDialogTest.exe demo shows how to use CXFileDialog
:
Acknowledgments
Revision history
- Version 1.1 - 2003 June 25
- Fixed some focus bugs;
- Added check for directory existence.
- Version 1.0 - 2003 June 24
Usage
This software is released into the public domain. You are free to use it in any way you like. If you modify it or extend it, please to consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.