MFC, File New with dialog to prompt for paramters and multiple Doc Types?
I have really tough question.
I have a program with six different kinds of MDI Windows.
There needs to be a dialog prompt to prompt the graphic dimensions (Height, Width) and then create six different kinds of M开发者_运维百科DI Window depending on what kind of graphics.
Question is:
I already got 6 MDI types working (to some extent).
What do I do to create a customized File|New to accommodate the need for a custom dialog screen?
For example, in MDI, there's a generic File|New dialog box. I wish to customize that in MFC.
First of all you'll need to override the CDocument
function that handles opening of new files; it's probably one of CDocument::OnNewDocument
or CDocument::OnOpenDocument
. I've also done this in the past by adding the following message map to CMainFrame
, not sure which one the correct method is:
ON_COMMAND( ID_FILE_OPEN, &CMainFrame::OnFileOpen )
Then, to display a customized New File dialog, use the WINAPI GetOpenFileName
function. Note that you must use this function, MFC's CFileDialog
will not work. Here's a code snippet from the CMainFrame::OnFileOpen
function I listed above in the message map:
/**
* Hook procedure for OPENFILENAME structure. This function processes messages from the custom
* controls added to the standard "Open File" dialog.
*
* @param [in] hdlg
* handle of the hdlg.
* @param [in] uiMsg
* message describing the user interface.
* @param [in] wParam
* the wParam field of the message.
* @param [in] lParam
* the lParam field of the message.
*
* @return If the return value is zero, the default dialog box procedure processes the message;
* otherwise it ignores the message.
*/
UINT_PTR CALLBACK OpenHexFileHook( HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam )
{
(void)(wParam);
if( !::IsWindow( hdlg ) ) {
return 0;
}
switch( uiMsg ) {
case WM_NOTIFY:
/* Sent when an event occurs or the custom controls require information */
{
LPOFNOTIFY pOfnNotify = (LPOFNOTIFY)lParam;
if( pOfnNotify == NULL ) {
return 0;
}
CWinApp *app = AfxGetApp();
switch( pOfnNotify->hdr.code ) {
case CDN_INITDONE:
/* Sent when the system has finished arranging the controls in the dialog box */
{
CString rv;
LRESULT idx;
/* Configure the Hex file format ComboBox */
HWND hHexFmt = GetDlgItem( hdlg, IDC_HEX_FILE_FORMAT );
ASSERT( hHexFmt );
/* Clear existing content */
::SendMessage( hHexFmt, CB_RESETCONTENT, 0, 0 );
/* Add new items to the list */
::SendMessage( hHexFmt, CB_ADDSTRING, 0, (LPARAM)_T("INTEL 32") );
::SendMessage( hHexFmt, CB_ADDSTRING, 0, (LPARAM)_T("INTEL 16") );
::SendMessage( hHexFmt, CB_ADDSTRING, 0, (LPARAM)_T("INTEL 8") );
/* Read user's last selection from registry */
rv = app->GetProfileString( _T("Settings"), _T("HexFormat"), _T("INTEL 32") );
idx = ::SendMessage( hHexFmt, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)((LPCTSTR)rv) );
if( idx == CB_ERR ) {
/* On error select the first item */
idx = 0;
}
/* Set current selection to the previously selected item's index */
::SendMessage( hHexFmt, CB_SETCURSEL, idx, 0 );
/* Configure the Bytes per address ComboBox */
HWND hBytePerLoc = GetDlgItem( hdlg, IDC_BYTES_PER_ADDR );
ASSERT( hBytePerLoc );
/* Clear existing content */
::SendMessage( hBytePerLoc, CB_RESETCONTENT, 0, 0 );
/* Add new items to the list */
::SendMessage( hBytePerLoc, CB_ADDSTRING, 0, (LPARAM)_T("1") );
::SendMessage( hBytePerLoc, CB_ADDSTRING, 0, (LPARAM)_T("2") );
::SendMessage( hBytePerLoc, CB_ADDSTRING, 0, (LPARAM)_T("4") );
/* Read user's last selection from registry */
rv = app->GetProfileString( _T("Settings"), _T("BytesPerAddr"), _T("1") );
idx = ::SendMessage( hBytePerLoc, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)((LPCTSTR)rv) );
if( idx == CB_ERR ) {
/* On error select the first item */
idx = 0;
}
/* Set current selection to the previously selected item's index */
::SendMessage( hBytePerLoc, CB_SETCURSEL, idx, 0 );
break;
}
case CDN_FILEOK:
/* Sent when the user specifies a file name and clicks the OK button */
{
/* Save user selection for the Hex file format ComboBox */
HWND hHexFmt = GetDlgItem( hdlg, IDC_HEX_FILE_FORMAT );
ASSERT( hHexFmt );
/* Get current selection's index */
LRESULT idx = ::SendMessage( hHexFmt, CB_GETCURSEL, 0, 0 );
if( idx != CB_ERR ) {
/* Get current selection's text length */
LRESULT len1 = ::SendMessage( hHexFmt, CB_GETLBTEXTLEN, idx, 0 );
if( len1 != CB_ERR ) {
TCHAR *text = new TCHAR[len1 + 1];
/* Get current selection's text */
LRESULT len2 = ::SendMessage( hHexFmt, CB_GETLBTEXT, idx, (LPARAM)text );
if( len1 == len2 ) {
/* Write string to registry */
app->WriteProfileString( _T("Settings"), _T("HexFormat"), text );
}
delete[] text;
}
}
/* Save user selection for the Bytes per address ComboBox */
HWND hBytePerLoc = GetDlgItem( hdlg, IDC_BYTES_PER_ADDR );
ASSERT( hBytePerLoc );
/* Get current selection's index */
idx = ::SendMessage( hBytePerLoc, CB_GETCURSEL, 0, 0 );
if( idx != CB_ERR ) {
/* Get current selection's text length */
LRESULT len1 = ::SendMessage( hBytePerLoc, CB_GETLBTEXTLEN, idx, 0 );
if( len1 != CB_ERR ) {
TCHAR *text = new TCHAR[len1 + 1];
/* Get current selection's text */
LRESULT len2 = ::SendMessage( hBytePerLoc, CB_GETLBTEXT, idx, (LPARAM)text );
if( len1 == len2 ) {
/* Write string to registry */
app->WriteProfileString( _T("Settings"), _T("BytesPerAddr"), text );
}
delete[] text;
}
}
break;
}
default:
/* Do nothing */
break;
}
break;
}
default:
/* Do nothing */
break;
}
return 0;
}
void CMainFrame::OnFileOpen()
{
std::basic_string<TCHAR> filterSpec;
/* Use *.hex filter */
filterSpec = _T("Hex Files (*.hex)");
filterSpec += (std::basic_string<TCHAR>::value_type)'\0';
filterSpec += _T("*.hex");
filterSpec += (std::basic_string<TCHAR>::value_type)'\0';
OPENFILENAME ofn = { sizeof(ofn) };
TCHAR filePath[MAX_PATH] = { 0 };
TCHAR fileTitle[MAX_PATH] = { 0 };
ofn.hwndOwner = AfxGetMainWnd()->GetSafeHwnd();
ofn.hInstance = AfxGetInstanceHandle();
ofn.lpstrFilter = filterSpec.c_str();
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 1;
ofn.lpstrFile = filePath;
ofn.nMaxFile = sizeof(filePath) / sizeof(TCHAR);
ofn.lpstrFileTitle = fileTitle;
ofn.nMaxFileTitle = sizeof(fileTitle) / sizeof(TCHAR);
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = _T("Select Intel HEX file");
ofn.Flags = OFN_ENABLETEMPLATE | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
OFN_EXPLORER | OFN_ENABLESIZING | OFN_DONTADDTORECENT |
OFN_HIDEREADONLY | OFN_ENABLEHOOK;
ofn.lpstrDefExt = _T("hex");
ofn.lCustData = NULL;
ofn.lpfnHook = OpenHexFileHook;
ofn.lpTemplateName = MAKEINTRESOURCE(IDD_HEX_FILE_OPEN);
ofn.FlagsEx = 0;
if( GetOpenFileName( &ofn ) != false ) {
AfxGetApp()->m_pDocManager->OpenDocumentFile( ofn.lpstrFile );
SetTitle( ofn.lpstrFileTitle );
}
}
In that project I added 2 ComboBoxes to the standard File Open dialog. These MSDN docs describe how to customize the standard dialogs. This is the resource file (.rc2) customization that I used:
//
// HexViewer.RC2 - resources Microsoft Visual C++ does not edit directly
//
#ifdef APSTUDIO_INVOKED
#error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
// Add manually edited resources here...
/////////////////////////////////////////////////////////////////////////////
//
// File Open Dialog Template
//
IDD_HEX_FILE_OPEN DIALOGEX 0, 0, 370, 40
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS
EXSTYLE WS_EX_CONTROLPARENT
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
LTEXT "&HEX file format:", IDC_HEX_FILE_FORMAT_TEXT, 67, 2, 58, 8, SS_NOTIFY
COMBOBOX IDC_HEX_FILE_FORMAT, 130, 0, 164, 100,
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "&Bytes per address:", IDC_BYTES_PER_ADDR_TEXT, 67, 20, 63, 8, SS_NOTIFY
COMBOBOX IDC_BYTES_PER_ADDR, 130, 18, 164, 100,
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
END
/////////////////////////////////////////////////////////////////////////////
Note that this method of customization is recommended only if you're programming for Windows XP and older versions. From Vista onwards MS recommends using the Common Item Dialog API for customizing, but I've never used that.
精彩评论