MFC,文件新建对话框提示参数和多个文档类型?

Posted

技术标签:

【中文标题】MFC,文件新建对话框提示参数和多个文档类型?【英文标题】:MFC, File New with dialog to prompt for paramters and multiple Doc Types? 【发布时间】:2010-11-01 03:52:59 【问题描述】:

我有一个非常棘手的问题。

我有一个包含六种不同类型 MDI 窗口的程序。

需要有对话框提示提示图形尺寸(高度、宽度),然后根据图形的种类创建六种不同的MDI窗口。

问题是:

我已经让 6 种 MDI 类型工作(在某种程度上)。

如何创建自定义文件|新建以适应自定义对话框屏幕的需要?

例如,在 MDI 中,有一个通用的文件|新建对话框。我希望在 MFC 中自定义它。

【问题讨论】:

【参考方案1】:

首先,您需要覆盖处理打开新文件的CDocument 函数;它可能是CDocument::OnNewDocumentCDocument::OnOpenDocument 之一。我过去也这样做过,将以下消息映射添加到CMainFrame,不确定哪个是正确的方法:

ON_COMMAND( ID_FILE_OPEN, &CMainFrame::OnFileOpen )

然后,要显示自定义的新建文件对话框,请使用 WINAPI GetOpenFileName 函数。注意必须使用这个功能,MFC 的CFileDialog 不起作用。这是我在上面的消息映射中列出的CMainFrame::OnFileOpen 函数的代码 sn-p:

/**
 * 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 );
  

在那个项目中,我在标准文件打开对话框中添加了 2 个组合框。 These MSDN 文档描述了如何自定义标准对话框。这是我使用的资源文件 (.rc2) 自定义:

//
// 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


/////////////////////////////////////////////////////////////////////////////

请注意,仅当您为 Windows XP 和更早版本进行编程时,才建议使用这种自定义方法。从 Vista 开始,MS 建议使用 Common Item Dialog API 进行自定义,但我从未使用过。

【讨论】:

以上是关于MFC,文件新建对话框提示参数和多个文档类型?的主要内容,如果未能解决你的问题,请参考以下文章

mfc 单文档 多文档 对话框 区别

新建一个MFC单文档程序含有菜单和工具栏,又建了一个对话框,如何直接显示对话框?

MFC VC++6.0 对话框怎么获得文档类中的数据

mfc怎么实现打开文件夹

在mfc对话框工程中,如何使用CDockablePane。另外,在单文档工程中,能否做出一个视频播放器

如何实现:MFC编程,对话框内按钮动作实现退出应用程序?