|
|
Microsoft Windows NT Build 297 06-28-1992
Microsoft Foundation Classes Microsoft Corporation
Technical Notes
#13 : Using the standard dialog classes
This note describes the use of the standard dialog classes provided
with MFC. The classes are CFileDialog, CFontDialog, CColorDialog,
CPrintDialog, and CFindReplaceDialog. They provide standard user interface
objects for your application. The class declarations for these
classes can be found in the source file \C700\MFC\INCLUDE\AFXDLGS.H.
=============================================================================
Requirements
============
You may use these classes for any MFC application. Although these
classes use the Windows 3.1 COMMDLG functions, they do not require
Windows 3.1 to run. You must redistribute COMMDLG.DLL with your
application and install the DLL in the user's Windows 3.0 system directory.
When building an application that uses these classes, you must
link with the library COMMDLG.LIB, which is part of the Windows SDK
installation.
General Use
===========
These dialogs classes may be used in one of two ways. You can use them
"as is" and supply the necessary arguments to the constructor to
customize the dialogs to suit your needs. You might also
consider deriving from these classes and providing a specific constructor
tailored to your needs. In either case, these dialogs act
like standard MFC dialogs, since they derive from CDialog (either
directly or indirectly.) You can use message maps and customize
these dialogs even more.
COMMDLG dialog APIs interface with the application code via
a parameter block structure. The MFC dialog classes provide
public access to this structure, which may be accessed at any
time to permit maximum customization. On the other hand, MFC
provides sensible defaults for most of the fields in the parameter
block so that you do not need to worry about them. These structures
are described in the online Windows 3.1 API reference.
Examples
========
The MULTIPAD sample application uses the CFileDialog, CFontDialog,
and CPrintDialog. The CHART application uses CFileDialog
and CPrintDialog. The MDI application uses the CColorDialog. In
addition, the OLE classes use the standard CFileDialog for
implementing standard OLE user interface objects.
CFileDialog
===========
The CFileDialog class encapsulates the OPENFILENAME structure
and the two Windows APIs GetOpenFileName and GetSaveFileName. This
dialog box is used to obtain from a user either a new file name
or the name of an existing file to open. CFileDialog is a modal
dialog and derives from the class CModalDialog.
To use a CFileDialog class object, create an object using the CFileDialog
constructor. The arguments to the constructor are below, note
that several have default values:
bOpenFileDialog set to TRUE for file open dialog, FALSE for
a file save dialog
lpszDefExt is the default extension, if a user does not
include a file extension, this is
automatically appended.
lpszFileName is the initial file name (defaults to NULL)
dwFlags is a set of flags that you can supply
that allow you to customize the dialog box.
See the online Windows API reference
(OPENFILESTRUCT) for more information
(defaults to OFN_HIDEREADONLY |
OFN_OVERWRITEPROMPT)
lpszFilter is a series of pairs of strings that specify
filters the user may apply to the files.
See below (defaults to NULL)
pParentWnd is a pointer to a parent Window. This is
used only when routing customized help
messages (defaults to NULL.)
The lpszFilter is used to display a possible list of suffixes. For
example Microsoft Excel permits users to open *.XLC and *.XLS
(and many others). The filter for Excel would look something
like the following:
char BASED_CODE szFilter[] =
"Chart Files (*.xlc)|*.xlc|Worksheet Files (*.xlm)|*.xlm|All Files (*.*)|*.*||"
Note the use of '|' to separate the components of the filter. Also
note that the entire filter ends with two '|'. This is the
standard MFC syntax for specifying filters. Also, note that the
entire string is a standard NULL terminated C string, though you
can always use an MFC CString object.
Once the dialog has been constructed, you are free to modify the
public member variable m_ofn, which is an OPENFILENAME structure.
You may manually set any flags or fields that you need. When you
are ready to prompt the user call the DoModal function (this is
a virtual function derived from CModalDialog.) The user is then
prompted for a file name (either an existing file or new file,
depending on the bOpenFileDialog constructor parameter.) When
the user clicks OK, CANCEL, or selected the CLOSE option from the
dialogs System Menu, control is returned to your application. The
return value from DoModal indicates success (IDOK) or
failure (IDCANCEL.) If the return value is IDCANCEL, either the
user closed the dialog or clicked CANCEL, or there was an error
in the parameter block. If you suspect an error, you can call
the CommDlgExtendedError API to learn more about the problem.
CommDlgExtendedError function returns 0 if there was no error.
This function differs from the standard OnOK and OnCancel functions
in that it is possible to force the user to change actions, whereas
OnOK and OnCancel are notifications that you must accept.
If the user chose a file name, then you can continue processing.
The CFileDialog class provides a number of helper functions to
retrieve information regarding the users choice:
GetPathName retrieves the fully qualified path name of the
selected file (suitable to use with CFile)
GetFileName retrieves just the file name without an extension
GetFileExt retrieves only the file extension (without a '.')
GetFileTitle retrieves the preferred title of the file, which
should be used as the title text of the frame window
GetReadOnlyPref returns TRUE if the user checked the read-only
option. If this is TRUE, you should open the file
with read-only permissions.
There are also several "callback" functions that you may respond
to in your derived CFileDialog class. You do not need message map
entries for these, since they are standard virtual functions.
OnShareViolation this function is called when a network
sharing violation occurs while processing
the dialog. See OPENFILENAME in the Windows
API for more information.
OnLBSelChangeNotify this function is called whenever the
user changes the selection(s) in the file
list. You can use this message if you
need to do extra work when a file is
a potential selection, such as calculating
disk space required, or displaying
file access rights.
OnFileNameOK this function is called when the user
selects OK. You can validate the file name
and determine if the user can continue. If
you return TRUE, be sure to indicate to the
user the problem with the selected file(s.)
One other technique available to customize the CFileDialog is to
introduce a message map in a derived class and to handle messages
just as you would for any other dialog. For example, you can modify
the dialog background color or handle the command messages for
a new control (the .RC file for the dialog is included.)
CFontDialog
===========
The CFontDialog class provides support for a standard dialog
that permits a user to choose a font. The dialog makes use
of the COMMDLG structure CHOOSEFONT and the API ChooseFont.
CFontDialog is a modal dialog derived from the CModalDialog class.
To use a CFontDialog class object, create an object using the CFontDialog
constructor. The arguments to the constructor are below, note
that several have default values:
lplfInitial the initial settings of the dialog box (defaults
to NULL)
dwFlags is a set of flags that you can use to customize
the function and appearance of the dialog. See
the CHOOSEFONT structure reference for more
information on possible values. (defaults to
CF_EFFECTS | CF_SCREENFONTS)
hdcPrinter if supplied is a CDC for the printer for which fonts
are to be selected (defaults to NULL)
pParentWnd is a pointer to a parent Window. This is
used only when routing customized help
messages (defaults to NULL)
As with the CFileDialog class, once the object has been constructed
you are free to modify the CHOOSEFONT structure, m_cf, in order
to customize the dialog box fully. After any further customization,
you call the member function DoModal, which will return either
IDOK or IDCANCEL. If the return value is IDCANCEL, the user clicked
on CANCEL or there was an initialization error in the dialog. You
may use the CommDlgExtendedError function to determine if there
was an initialization error. If the user selected OK the IDOK value
is returned. The CFontDialog class provides a number of helper functions
for extracting information out of the dialog:
GetFaceName returns the face name of the font
GetStyleName returns the style name of the font
GetSize returns the point size in 1/10ths of a point
GetColor returns the color of the selected font
GetWeight returns the weight of the font
IsStrikeout returns TRUE if the strikeout effect was selected
IsUnderline returns TRUE if the underline effect was selected
IsBold returns TRUE if the weight is equal to FW_BOLD
IsItalic returns TRUE if the font is italic
In addition, the member variable m_lf is the LOGFONT descriptor
of the font, which can be used in a CreateFontIndirect call,
or accessed directly.
You may customize the dialog by deriving your own class from CFontDialog
and using a message map to handle any messages. You can also use
the CFontDialog::GetCurrentFont member function to determine the
currently selected font while in a message handler.
CColorDialog
============
The CColorDialog class provides support for a standard dialog
that permits a user to choose/create a color. The dialog makes use
of the COMMDLG structure CHOOSECOLOR and the API ChooseColor.
CColorDialog is a modal dialog derived from the CModalDialog class.
CColorDialog is used just like CFontDialog. The COMMDLG structure
that is used for customizing the dialog is CHOOSECOLOR, and it
can be modified after construction of the object and before
DoModal is called. The arguments to the constructor are as
follows:
clrInit is a COLORREF that is the initial color selection
(defaults to RGB(0,0,0))
dwFlags is a set of flags that you can use to customize
the function and appearance of the dialog. See
the CHOOSECOLOR structure reference for more
information on possible values. (defaults to 0)
pParentWnd is a pointer to a parent Window. This is
used only when routing customized help
messages (defaults to NULL.)
In addition, the CColorDialog permits the user to define up to 16
custom colors. The CColorDialog saves these custom colors between
invocations of the dialog in the static member variable clrSavedCustom.
If you wish to save these colors between executions of the application,
then you must do this yourself. After the dialog has been constructed
you call DoModal. If the return value is IDOK, then you can use
the GetColor member function to retrieve the color the user
selected.
As with all of the standard dialog classes, you are permitted
to define a message map in your derived CColorDialog class
customize the dialog to suite your needs. The member function
SetCurrentColor is provided for forcing the currently selected
color to a certain value. As with CFileDialog, a validation
callback is provided that gives you a chance to override the OK
selection. This validation is handled in the OnColorOK virtual
function.
CPrintDialog
============
The CPrintDialog class provides support for a standard dialog
that permits a user to print a document or setup the printer.
The dialog makes use of the COMMDLG structure PRINTDLG and the
API PrintDlg. CPrintDialog is a modal dialog derived from
the CModalDialog class.
As with CFileDialog, CPrintDialog is really two different dialogs,
distinguished by a constructor argument. The CPrintDialog class
can be used to respond to the Print command and/or the Print Setup
command (both usually in the File menu.) The arguments to the
constructor for CPrintDialog include:
bPrintSetupOnly TRUE if you want only a Print Setup
dialog, FALSE for the Print dialog
dwFlags is a set of flags that you can use to customize
the function and appearance of the dialog. See
the PRINTDLG structure reference for more
information on possible values. (defaults to
PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS
| PD_HIDEPRINTTOFILE | PD_NOSELECTION)
pParentWnd is a pointer to a parent Window. This is
used only when routing customized help
messages (defaults to NULL.)
You may use the GetDefaults member function to retrieve the
current printer defaults. All of the helper functions described
below will be valid after a successful return. Note that
this member function requires no user interaction.
As with other standard dialogs, you can customize the appearance
and functionality by directly modifying the PRINTDLG structure,
which is the m_pd member variable. After any customization
you call DoModal, which will return IDOK or IDCANCEL as expected.
Remember to check for extended errors if IDCANCEL is the return
value, since there might have been a setup error. If IDOK
is returned there are a number of functions that can be used
to retrieve information about the selected printer. Some of
these functions might not be valid, depending on the settings
of dwFlags and m_pd.Flags.
GetCopies returns the number of copies the user chose
GetFromPage returns the starting page of the print job
GetToPage returns the ending page of the print jon
GetDevMode returns a pointer to the device mode
GetDriverName returns a string that is the driver name
GetDeviceName returns a string that is the device name
GetPortName returns a string that is the port name
PrintCollate returns TRUE if the job is to be collated
PrintAll returns TRUE if All pages selected
PrintRange returns TRUE if the user entered a print range
(GetFromPage and GetToPage are then valid)
PrintSelection returns TRUE if the user wishes to print
the current selection
GetPrinterDC returns an HDC for the selected printer
The GetPrinterDC function returns an HDC only if the bPrintSetupOnly
constructor parameter was FALSE (i.e. the Print dialog is displayed.)
You are responsible for calling DeleteDC. If you wish to
use this DC as an MFC CDC object, then you can attach it to
an object as follows:
{
CDC printerDC;
CPrintDialog pd(FALSE);
if (pd.DoModal() == IDCANCEL)
return FALSE;
printerDC.Attach(pd.GetPrinterDC());
// print using printerDC
} // falling out of scope will implicitly call CDC::DeleteDC
While the Print dialog is active, it is possible for the user to
obtain a Print Setup dialog and further customize the print job.
MFC handles this automatically for you.
You may customize the CPrintDialog object by deriving your
own class from it and using a message map to handle messages and
commands of your choosing. If you wish to handle the same message
differently depending on if the Print dialog or Print Setup dialog
is active you will need to derive an additional class, one
for the Print dialog and one for your custom Print Setup dialog. In
your print dialog class you will also need to override the
AttachOnSetup member function. This function handles the creation
of a new dialog for when the Print Setup button is clicked. The
source code in \C700\MFC\SRC\WINDLGS.CPP provides more documentation
on how to implement this feature.
CFindReplaceDialog
==================
The CFindReplaceDialog class is a standard modeless dialog for implementing
a dialog that queries the user for a find/replace string pair. The
dialog is dual purpose in that it can display either a Find dialog
or a Find Replace dialog. This is a modeless dialog and is
derived from the CDialog class. You are responsible for implementing
code that does the actual search and replace, as this dialog only
receives input from the user. The relevant parameter block
structure is FINDREPLACE and the APIs used are FindText and
ReplaceText.
Since this dialog is modeless, it should be dynamically allocated
using operator new. If you wish to allocate a CFindReplace dialog
on the stack frame, you will need to derive your own CFindReplaceDialog
and override the default behavior of the PostNcDestroy function.
The constructor for this class takes no arguments. When your application
needs to query the user for find/replace information the Create
member function is called. This will create and show the modeless
dialog. The parameters to Create are as follows:
bFindDialogOnly TRUE for Find, FALSE for Find and Replace
lpszFindWhat the default search string, such as the
current selection
lpszReplaceWith the default replacement string
(defaults to NULL)
dwFlags is a set of flags that you can use to customize
the function and appearance of the dialog. See
the FINDREPLACE structure reference for more
information on possible values. (defaults to
FR_DOWN)
pParentWnd the parent of the dialog, this is the dialog
that receives the special message indicating
that a find/replace action is requested (defaults
to the current frame window, CWinApp::m_pMainWnd)
In order for the pParentWnd to be notified of find/replace requests
you must use the Windows API ::RegisterMessage(FINDMSGSTRING). The
return value of this function is a message number that is unique to this
application instance. Your frame window should have a message map
entry that handles this registered message. The following code
fragments show how to do this for a frame window class CMyFrameWnd.
class CMyFrameWnd : public CFrameWnd
{
// normal members
protected:
// CFindReplaceDialog helpers
static CFindReplace* pFindReplace;
static UINT nMsgFind;
afx_msg LONG CmdFindHelper(UINT wParam, LONG lParam);
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
// normal message map entries
ON_REGISTERED_MESSAGE(nMsgFind, CmdFindHelper)
END_MESSAGE_MAP
UINT CMyFrameWnd::nMsgFind = ::RegisterMessage(FINDMSGSTRING);
CFindReplace* CMyFrameWnd::pFindReplace = NULL;
Note the use of a static member that is the current CFindReplaceDialog
object. When the user first executes the Find command, a dialog will
be created and that object will be used until the Close command on
the system menu is executed or the user clicks CANCEL.
Within the CmdFindHelper you will interpret the intentions of the
user and do the work for find/replace. In order to assist you, there
are a number of helper functions available:
GetFindString returns the current find string
SearchDown TRUE of the user wishes to search down
the document
FindNext TRUE if the user clicked the Find Next
button
MatchCase TRUE if the user wishes to match case
of text exactly
MatchWholeWord TRUE if the user wishes to match entire
words only
GetReplaceString returns the current replace string for
a replace dialog
ReplaceCurrent TRUE is the user requested that the current
word be replaced in a replace dialog
ReplaceAll TRUE if the user wishes all occurrences
to be replaced
IsTerminating TRUE is the dialog is terminating (the
current m_hWnd is no longer valid when this
function returns TRUE)
GetNotifier return the CFindReplaceDialog structure
(valid only in the CmdFindHandler callback
function)
The CmdFindHandler upon being called will first use the static
member function of CFindReplaceDialog, GetNotifier, to convert
the lParam into a CFindReplaceDialog object pointer, which will
then be used to call member functions and extract dialog information.
If you derived your own CFindReplaceDialog, you will need to
provide a typesafe castdown static member function to safely convert
the lParam to your own derived CFileDialog.
Normally the CmdFindHandler will then do a check to see if the
dialog is being terminated (using IsTerminating) and if this is
TRUE you will cleanup (delete the current pFindReplace dialog and
set the member variable to NULL) and possibly store away the
final find/replace text to be used in the initialization of the
next dialog.
Although this dialog is a modeless dialog, as with other
CDialog derived modeless dialogs MFC automatically
handles the translation dialog messages and routes them to
your dialog's message map. Thus you are free to customize your
CFindReplaceDialog by deriving and supplying a message map with
the necessary handlers.
Advanced Usage Notes
====================
Many of these dialogs permit the use of strings to customize
the appearance or functionality of the dialog. Whenever a
string is used, it is best to use a STRINGTABLE resource
rather than embedding the string in your code. The CString::LoadString
API can assist you in loading a string from a resource file.
Similarly, if the string is read-only, you could place it in
a code segment (use the MFC helper macro BASED_CODE.)
The standard COMMDLG functions all permit the user to add special
"hook" functions in order to customize the dialog box appearance and
functionality. With MFC you should not use these special
hook procedures, but you should use a derived class and a message
just as you would for any other standard Windows dialog. If you
require the use of the hook function, be sure to save the MFC
hook function and call it if you do not handle a message, just
as when dynamically subclassing a Windows window.
As with other short-lived objects, dialogs that derive from
the CModalDialog class are best allocated on the stack frame.
The CFindReplaceDialog class is designed to be heap allocated
(via operator new) since it is a long-lived object.
All of these dialog classes have a parent window pointer as
a constructor parameter. The classes will all use the current
frame window (CWinApp::m_pMainWnd) as the parent if you
specify NULL as the pParentWnd parameter (the default.) If
you are spawning a standard dialog from another dialog, it
you must pass the current dialog as the the parent pointer
(the 'this' pointer in the command handler that spawns the
dialog. If you do not, the two dialogs will have sibling
relationship rather than a parent/child relationship.
COMMDLG functions require significant stack space, so be
sure to have at least 16K of stack space available (use the
.DEF file to change the default.)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.