|
|
1.1 root 1:
2: Microsoft Foundation Classes Microsoft Corporation
3: Technical Notes
4:
5: #13 : Using the standard dialog classes
6:
7:
8: This note describes the use of the standard dialog classes provided
9: with MFC. The classes are CFileDialog, CFontDialog, CColorDialog,
10: CPrintDialog, and CFindReplaceDialog. They provide standard user interface
11: objects for your application. The class declarations for these
12: classes can be found in the source file \C700\MFC\INCLUDE\AFXDLGS.H.
13: =============================================================================
14:
15:
16: Requirements
17: ============
18: You may use these classes for any MFC application. Although these
19: classes use the Windows 3.1 COMMDLG functions, they do not require
20: Windows 3.1 to run. You must redistribute COMMDLG.DLL with your
21: application and install the DLL in the user's Windows 3.0 system directory.
22: When building an application that uses these classes, you must
23: link with the library COMMDLG.LIB, which is part of the Windows SDK
24: installation.
25:
26:
27: General Use
28: ===========
29: These dialogs classes may be used in one of two ways. You can use them
30: "as is" and supply the necessary arguments to the constructor to
31: customize the dialogs to suit your needs. You might also
32: consider deriving from these classes and providing a specific constructor
33: tailored to your needs. In either case, these dialogs act
34: like standard MFC dialogs, since they derive from CDialog (either
35: directly or indirectly.) You can use message maps and customize
36: these dialogs even more.
37:
38: COMMDLG dialog APIs interface with the application code via
39: a parameter block structure. The MFC dialog classes provide
40: public access to this structure, which may be accessed at any
41: time to permit maximum customization. On the other hand, MFC
42: provides sensible defaults for most of the fields in the parameter
43: block so that you do not need to worry about them. These structures
44: are described in the online Windows 3.1 API reference.
45:
46:
47: Examples
48: ========
49: The MULTIPAD sample application uses the CFileDialog, CFontDialog,
50: and CPrintDialog. The CHART application uses CFileDialog
51: and CPrintDialog. The MDI application uses the CColorDialog. In
52: addition, the OLE classes use the standard CFileDialog for
53: implementing standard OLE user interface objects.
54:
55:
56: CFileDialog
57: ===========
58: The CFileDialog class encapsulates the OPENFILENAME structure
59: and the two Windows APIs GetOpenFileName and GetSaveFileName. This
60: dialog box is used to obtain from a user either a new file name
61: or the name of an existing file to open. CFileDialog is a modal
62: dialog and derives from the class CModalDialog.
63:
64: To use a CFileDialog class object, create an object using the CFileDialog
65: constructor. The arguments to the constructor are below, note
66: that several have default values:
67:
68: bOpenFileDialog set to TRUE for file open dialog, FALSE for
69: a file save dialog
70: lpszDefExt is the default extension, if a user does not
71: include a file extension, this is
72: automatically appended.
73: lpszFileName is the initial file name (defaults to NULL)
74: dwFlags is a set of flags that you can supply
75: that allow you to customize the dialog box.
76: See the online Windows API reference
77: (OPENFILESTRUCT) for more information
78: (defaults to OFN_HIDEREADONLY |
79: OFN_OVERWRITEPROMPT)
80: lpszFilter is a series of pairs of strings that specify
81: filters the user may apply to the files.
82: See below (defaults to NULL)
83: pParentWnd is a pointer to a parent Window. This is
84: used only when routing customized help
85: messages (defaults to NULL.)
86:
87: The lpszFilter is used to display a possible list of suffixes. For
88: example Microsoft Excel permits users to open *.XLC and *.XLS
89: (and many others). The filter for Excel would look something
90: like the following:
91:
92: char BASED_CODE szFilter[] =
93: "Chart Files (*.xlc)|*.xlc|Worksheet Files (*.xlm)|*.xlm|All Files (*.*)|*.*||"
94:
95: Note the use of '|' to separate the components of the filter. Also
96: note that the entire filter ends with two '|'. This is the
97: standard MFC syntax for specifying filters. Also, note that the
98: entire string is a standard NULL terminated C string, though you
99: can always use an MFC CString object.
100:
101: Once the dialog has been constructed, you are free to modify the
102: public member variable m_ofn, which is an OPENFILENAME structure.
103: You may manually set any flags or fields that you need. When you
104: are ready to prompt the user call the DoModal function (this is
105: a virtual function derived from CModalDialog.) The user is then
106: prompted for a file name (either an existing file or new file,
107: depending on the bOpenFileDialog constructor parameter.) When
108: the user clicks OK, CANCEL, or selected the CLOSE option from the
109: dialogs System Menu, control is returned to your application. The
110: return value from DoModal indicates success (IDOK) or
111: failure (IDCANCEL.) If the return value is IDCANCEL, either the
112: user closed the dialog or clicked CANCEL, or there was an error
113: in the parameter block. If you suspect an error, you can call
114: the CommDlgExtendedError API to learn more about the problem.
115: CommDlgExtendedError function returns 0 if there was no error.
116: This function differs from the standard OnOK and OnCancel functions
117: in that it is possible to force the user to change actions, whereas
118: OnOK and OnCancel are notifications that you must accept.
119:
120: If the user chose a file name, then you can continue processing.
121: The CFileDialog class provides a number of helper functions to
122: retrieve information regarding the users choice:
123:
124: GetPathName retrieves the fully qualified path name of the
125: selected file (suitable to use with CFile)
126: GetFileName retrieves just the file name without an extension
127: GetFileExt retrieves only the file extension (without a '.')
128: GetFileTitle retrieves the preferred title of the file, which
129: should be used as the title text of the frame window
130: GetReadOnlyPref returns TRUE if the user checked the read-only
131: option. If this is TRUE, you should open the file
132: with read-only permissions.
133:
134: There are also several "callback" functions that you may respond
135: to in your derived CFileDialog class. You do not need message map
136: entries for these, since they are standard virtual functions.
137:
138: OnShareViolation this function is called when a network
139: sharing violation occurs while processing
140: the dialog. See OPENFILENAME in the Windows
141: API for more information.
142: OnLBSelChangeNotify this function is called whenever the
143: user changes the selection(s) in the file
144: list. You can use this message if you
145: need to do extra work when a file is
146: a potential selection, such as calculating
147: disk space required, or displaying
148: file access rights.
149: OnFileNameOK this function is called when the user
150: selects OK. You can validate the file name
151: and determine if the user can continue. If
152: you return TRUE, be sure to indicate to the
153: user the problem with the selected file(s.)
154:
155: One other technique available to customize the CFileDialog is to
156: introduce a message map in a derived class and to handle messages
157: just as you would for any other dialog. For example, you can modify
158: the dialog background color or handle the command messages for
159: a new control (the .RC file for the dialog is included.)
160:
161:
162: CFontDialog
163: ===========
164: The CFontDialog class provides support for a standard dialog
165: that permits a user to choose a font. The dialog makes use
166: of the COMMDLG structure CHOOSEFONT and the API ChooseFont.
167: CFontDialog is a modal dialog derived from the CModalDialog class.
168:
169: To use a CFontDialog class object, create an object using the CFontDialog
170: constructor. The arguments to the constructor are below, note
171: that several have default values:
172:
173: lplfInitial the initial settings of the dialog box (defaults
174: to NULL)
175: dwFlags is a set of flags that you can use to customize
176: the function and appearance of the dialog. See
177: the CHOOSEFONT structure reference for more
178: information on possible values. (defaults to
179: CF_EFFECTS | CF_SCREENFONTS)
180: hdcPrinter if supplied is a CDC for the printer for which fonts
181: are to be selected (defaults to NULL)
182: pParentWnd is a pointer to a parent Window. This is
183: used only when routing customized help
184: messages (defaults to NULL)
185:
186: As with the CFileDialog class, once the object has been constructed
187: you are free to modify the CHOOSEFONT structure, m_cf, in order
188: to customize the dialog box fully. After any further customization,
189: you call the member function DoModal, which will return either
190: IDOK or IDCANCEL. If the return value is IDCANCEL, the user clicked
191: on CANCEL or there was an initialization error in the dialog. You
192: may use the CommDlgExtendedError function to determine if there
193: was an initialization error. If the user selected OK the IDOK value
194: is returned. The CFontDialog class provides a number of helper functions
195: for extracting information out of the dialog:
196:
197: GetFaceName returns the face name of the font
198: GetStyleName returns the style name of the font
199: GetSize returns the point size in 1/10ths of a point
200: GetColor returns the color of the selected font
201: GetWeight returns the weight of the font
202: IsStrikeout returns TRUE if the strikeout effect was selected
203: IsUnderline returns TRUE if the underline effect was selected
204: IsBold returns TRUE if the weight is equal to FW_BOLD
205: IsItalic returns TRUE if the font is italic
206:
207: In addition, the member variable m_lf is the LOGFONT descriptor
208: of the font, which can be used in a CreateFontIndirect call,
209: or accessed directly.
210:
211: You may customize the dialog by deriving your own class from CFontDialog
212: and using a message map to handle any messages. You can also use
213: the CFontDialog::GetCurrentFont member function to determine the
214: currently selected font while in a message handler.
215:
216:
217: CColorDialog
218: ============
219: The CColorDialog class provides support for a standard dialog
220: that permits a user to choose/create a color. The dialog makes use
221: of the COMMDLG structure CHOOSECOLOR and the API ChooseColor.
222: CColorDialog is a modal dialog derived from the CModalDialog class.
223:
224: CColorDialog is used just like CFontDialog. The COMMDLG structure
225: that is used for customizing the dialog is CHOOSECOLOR, and it
226: can be modified after construction of the object and before
227: DoModal is called. The arguments to the constructor are as
228: follows:
229:
230: clrInit is a COLORREF that is the initial color selection
231: (defaults to RGB(0,0,0))
232: dwFlags is a set of flags that you can use to customize
233: the function and appearance of the dialog. See
234: the CHOOSECOLOR structure reference for more
235: information on possible values. (defaults to 0)
236: pParentWnd is a pointer to a parent Window. This is
237: used only when routing customized help
238: messages (defaults to NULL.)
239:
240: In addition, the CColorDialog permits the user to define up to 16
241: custom colors. The CColorDialog saves these custom colors between
242: invocations of the dialog in the static member variable clrSavedCustom.
243: If you wish to save these colors between executions of the application,
244: then you must do this yourself. After the dialog has been constructed
245: you call DoModal. If the return value is IDOK, then you can use
246: the GetColor member function to retrieve the color the user
247: selected.
248:
249: As with all of the standard dialog classes, you are permitted
250: to define a message map in your derived CColorDialog class
251: customize the dialog to suite your needs. The member function
252: SetCurrentColor is provided for forcing the currently selected
253: color to a certain value. As with CFileDialog, a validation
254: callback is provided that gives you a chance to override the OK
255: selection. This validation is handled in the OnColorOK virtual
256: function.
257:
258:
259: CPrintDialog
260: ============
261: The CPrintDialog class provides support for a standard dialog
262: that permits a user to print a document or setup the printer.
263: The dialog makes use of the COMMDLG structure PRINTDLG and the
264: API PrintDlg. CPrintDialog is a modal dialog derived from
265: the CModalDialog class.
266:
267: As with CFileDialog, CPrintDialog is really two different dialogs,
268: distinguished by a constructor argument. The CPrintDialog class
269: can be used to respond to the Print command and/or the Print Setup
270: command (both usually in the File menu.) The arguments to the
271: constructor for CPrintDialog include:
272:
273: bPrintSetupOnly TRUE if you want only a Print Setup
274: dialog, FALSE for the Print dialog
275: dwFlags is a set of flags that you can use to customize
276: the function and appearance of the dialog. See
277: the PRINTDLG structure reference for more
278: information on possible values. (defaults to
279: PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS
280: | PD_HIDEPRINTTOFILE | PD_NOSELECTION)
281: pParentWnd is a pointer to a parent Window. This is
282: used only when routing customized help
283: messages (defaults to NULL.)
284:
285: You may use the GetDefaults member function to retrieve the
286: current printer defaults. All of the helper functions described
287: below will be valid after a successful return. Note that
288: this member function requires no user interaction.
289:
290: As with other standard dialogs, you can customize the appearance
291: and functionality by directly modifying the PRINTDLG structure,
292: which is the m_pd member variable. After any customization
293: you call DoModal, which will return IDOK or IDCANCEL as expected.
294: Remember to check for extended errors if IDCANCEL is the return
295: value, since there might have been a setup error. If IDOK
296: is returned there are a number of functions that can be used
297: to retrieve information about the selected printer. Some of
298: these functions might not be valid, depending on the settings
299: of dwFlags and m_pd.Flags.
300:
301: GetCopies returns the number of copies the user chose
302: GetFromPage returns the starting page of the print job
303: GetToPage returns the ending page of the print jon
304: GetDevMode returns a pointer to the device mode
305: GetDriverName returns a string that is the driver name
306: GetDeviceName returns a string that is the device name
307: GetPortName returns a string that is the port name
308: PrintCollate returns TRUE if the job is to be collated
309: PrintAll returns TRUE if All pages selected
310: PrintRange returns TRUE if the user entered a print range
311: (GetFromPage and GetToPage are then valid)
312: PrintSelection returns TRUE if the user wishes to print
313: the current selection
314: GetPrinterDC returns an HDC for the selected printer
315:
316: The GetPrinterDC function returns an HDC only if the bPrintSetupOnly
317: constructor parameter was FALSE (i.e. the Print dialog is displayed.)
318: You are responsible for calling DeleteDC. If you wish to
319: use this DC as an MFC CDC object, then you can attach it to
320: an object as follows:
321: {
322: CDC printerDC;
323: CPrintDialog pd(FALSE);
324: if (pd.DoModal() == IDCANCEL)
325: return FALSE;
326: printerDC.Attach(pd.GetPrinterDC());
327: // print using printerDC
328: } // falling out of scope will implicitly call CDC::DeleteDC
329:
330: While the Print dialog is active, it is possible for the user to
331: obtain a Print Setup dialog and further customize the print job.
332: MFC handles this automatically for you.
333:
334: You may customize the CPrintDialog object by deriving your
335: own class from it and using a message map to handle messages and
336: commands of your choosing. If you wish to handle the same message
337: differently depending on if the Print dialog or Print Setup dialog
338: is active you will need to derive an additional class, one
339: for the Print dialog and one for your custom Print Setup dialog. In
340: your print dialog class you will also need to override the
341: AttachOnSetup member function. This function handles the creation
342: of a new dialog for when the Print Setup button is clicked. The
343: source code in \C700\MFC\SRC\WINDLGS.CPP provides more documentation
344: on how to implement this feature.
345:
346:
347: CFindReplaceDialog
348: ==================
349: The CFindReplaceDialog class is a standard modeless dialog for implementing
350: a dialog that queries the user for a find/replace string pair. The
351: dialog is dual purpose in that it can display either a Find dialog
352: or a Find Replace dialog. This is a modeless dialog and is
353: derived from the CDialog class. You are responsible for implementing
354: code that does the actual search and replace, as this dialog only
355: receives input from the user. The relevant parameter block
356: structure is FINDREPLACE and the APIs used are FindText and
357: ReplaceText.
358:
359: Since this dialog is modeless, it should be dynamically allocated
360: using operator new. If you wish to allocate a CFindReplace dialog
361: on the stack frame, you will need to derive your own CFindReplaceDialog
362: and override the default behavior of the PostNcDestroy function.
363: The constructor for this class takes no arguments. When your application
364: needs to query the user for find/replace information the Create
365: member function is called. This will create and show the modeless
366: dialog. The parameters to Create are as follows:
367:
368: bFindDialogOnly TRUE for Find, FALSE for Find and Replace
369: lpszFindWhat the default search string, such as the
370: current selection
371: lpszReplaceWith the default replacement string
372: (defaults to NULL)
373: dwFlags is a set of flags that you can use to customize
374: the function and appearance of the dialog. See
375: the FINDREPLACE structure reference for more
376: information on possible values. (defaults to
377: FR_DOWN)
378: pParentWnd the parent of the dialog, this is the dialog
379: that receives the special message indicating
380: that a find/replace action is requested (defaults
381: to the current frame window, CWinApp::m_pMainWnd)
382:
383: In order for the pParentWnd to be notified of find/replace requests
384: you must use the Windows API ::RegisterMessage(FINDMSGSTRING). The
385: return value of this function is a message number that is unique to this
386: application instance. Your frame window should have a message map
387: entry that handles this registered message. The following code
388: fragments show how to do this for a frame window class CMyFrameWnd.
389:
390: class CMyFrameWnd : public CFrameWnd
391: {
392: // normal members
393:
394: protected:
395: // CFindReplaceDialog helpers
396: static CFindReplace* pFindReplace;
397: static UINT nMsgFind;
398: afx_msg LONG CmdFindHelper(UINT wParam, LONG lParam);
399:
400: DECLARE_MESSAGE_MAP()
401: };
402:
403: BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
404: // normal message map entries
405: ON_REGISTERED_MESSAGE(nMsgFind, CmdFindHelper)
406: END_MESSAGE_MAP
407:
408: UINT CMyFrameWnd::nMsgFind = ::RegisterMessage(FINDMSGSTRING);
409: CFindReplace* CMyFrameWnd::pFindReplace = NULL;
410:
411: Note the use of a static member that is the current CFindReplaceDialog
412: object. When the user first executes the Find command, a dialog will
413: be created and that object will be used until the Close command on
414: the system menu is executed or the user clicks CANCEL.
415:
416: Within the CmdFindHelper you will interpret the intentions of the
417: user and do the work for find/replace. In order to assist you, there
418: are a number of helper functions available:
419:
420: GetFindString returns the current find string
421: SearchDown TRUE of the user wishes to search down
422: the document
423: FindNext TRUE if the user clicked the Find Next
424: button
425: MatchCase TRUE if the user wishes to match case
426: of text exactly
427: MatchWholeWord TRUE if the user wishes to match entire
428: words only
429: GetReplaceString returns the current replace string for
430: a replace dialog
431: ReplaceCurrent TRUE is the user requested that the current
432: word be replaced in a replace dialog
433: ReplaceAll TRUE if the user wishes all occurrences
434: to be replaced
435: IsTerminating TRUE is the dialog is terminating (the
436: current m_hWnd is no longer valid when this
437: function returns TRUE)
438: GetNotifier return the CFindReplaceDialog structure
439: (valid only in the CmdFindHandler callback
440: function)
441:
442: The CmdFindHandler upon being called will first use the static
443: member function of CFindReplaceDialog, GetNotifier, to convert
444: the lParam into a CFindReplaceDialog object pointer, which will
445: then be used to call member functions and extract dialog information.
446: If you derived your own CFindReplaceDialog, you will need to
447: provide a typesafe castdown static member function to safely convert
448: the lParam to your own derived CFileDialog.
449:
450: Normally the CmdFindHandler will then do a check to see if the
451: dialog is being terminated (using IsTerminating) and if this is
452: TRUE you will cleanup (delete the current pFindReplace dialog and
453: set the member variable to NULL) and possibly store away the
454: final find/replace text to be used in the initialization of the
455: next dialog.
456:
457: Although this dialog is a modeless dialog, as with other
458: CDialog derived modeless dialogs MFC automatically
459: handles the translation dialog messages and routes them to
460: your dialog's message map. Thus you are free to customize your
461: CFindReplaceDialog by deriving and supplying a message map with
462: the necessary handlers.
463:
464:
465: Advanced Usage Notes
466: ====================
467: Many of these dialogs permit the use of strings to customize
468: the appearance or functionality of the dialog. Whenever a
469: string is used, it is best to use a STRINGTABLE resource
470: rather than embedding the string in your code. The CString::LoadString
471: API can assist you in loading a string from a resource file.
472: Similarly, if the string is read-only, you could place it in
473: a code segment (use the MFC helper macro BASED_CODE.)
474:
475: The standard COMMDLG functions all permit the user to add special
476: "hook" functions in order to customize the dialog box appearance and
477: functionality. With MFC you should not use these special
478: hook procedures, but you should use a derived class and a message
479: just as you would for any other standard Windows dialog. If you
480: require the use of the hook function, be sure to save the MFC
481: hook function and call it if you do not handle a message, just
482: as when dynamically subclassing a Windows window.
483:
484: As with other short-lived objects, dialogs that derive from
485: the CModalDialog class are best allocated on the stack frame.
486: The CFindReplaceDialog class is designed to be heap allocated
487: (via operator new) since it is a long-lived object.
488:
489: All of these dialog classes have a parent window pointer as
490: a constructor parameter. The classes will all use the current
491: frame window (CWinApp::m_pMainWnd) as the parent if you
492: specify NULL as the pParentWnd parameter (the default.) If
493: you are spawning a standard dialog from another dialog, it
494: you must pass the current dialog as the the parent pointer
495: (the 'this' pointer in the command handler that spawns the
496: dialog. If you do not, the two dialogs will have sibling
497: relationship rather than a parent/child relationship.
498:
499: COMMDLG functions require significant stack space, so be
500: sure to have at least 16K of stack space available (use the
501: .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.