STRINGTABLE PRELOAD DISCARDABLE BEGIN IDR_MYDOCTYPE "MyApp\nMyApp\nMyApp Document\nMyApp Files (*.dib,*.tif,*.pcx)\n.dib;*.tif;*.pcx\n\n" END
Figure 3 File Open Dialog
////////////////////////////////////////////////////////////////
// TabDlg 1997 Microsoft Systems Journal.
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
// TabDlg illustrates how to make a dialog with dynamic TAB order
// and that handles the RETURN key.
//
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxpriv.h> // for WM_KICKIDLE
#include <stdlib.h> // for random number generator fns
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////
// Dialog class that alters the TAB sequence and handles
// the RETURN key.
//
class CTabDialog : public CDialog {
HACCEL m_hAccel; // dialog accelerators
BOOL m_bRandomTabOrder; // do random TAB order?
public:
CTabDialog();
virtual BOOL OnInitDialog();
virtual BOOL PreTranslateMessage(MSG* pMsg);
// Message/command handlers
afx_msg LRESULT OnKickIdle(WPARAM wp, LPARAM lp);
afx_msg void OnChangeTabs();
afx_msg void OnReturn();
afx_msg void OnUpdateChangeTabs(CCmdUI* pCmdUI);
afx_msg BOOL OnNextPrevField(UINT nCmdID);
DECLARE_MESSAGE_MAP()
};
////////////////////////////////////////////////////////////////
// Application class
//
class CApp : public CWinApp {
public:
CApp() { }
virtual BOOL InitInstance();
} theApp;
/////////////////
// Initialize: just run the dialog and quit.
//
BOOL CApp::InitInstance()
{
srand(time(NULL)); // seed random number generator
CTabDialog dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK) {
// TODO: handle case when the dialog is dismissed with OK
} else if (nResponse == IDCANCEL) {
// TODO: handle case when the dialog is dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
////////////////////////////////////////////////////////////////
// CTabDialog
//
BEGIN_MESSAGE_MAP(CTabDialog, CDialog)
ON_MESSAGE(WM_KICKIDLE, OnKickIdle)
ON_COMMAND(ID_CHANGE_TABS, OnChangeTabs)
ON_COMMAND(ID_RETURN, OnReturn)
ON_COMMAND_EX(ID_NEXT_FIELD, OnNextPrevField)
ON_COMMAND_EX(ID_PREV_FIELD, OnNextPrevField)
ON_UPDATE_COMMAND_UI(ID_CHANGE_TABS, OnUpdateChangeTabs)
END_MESSAGE_MAP()
//////////////////
// Construct dialog: set everything to zero or NULL.
//
CTabDialog::CTabDialog() : CDialog(IDD_DIALOG1)
{
m_hAccel = NULL;
m_bRandomTabOrder = FALSE;
}
//////////////////
// Possibly translate accelerator key.
//
BOOL CTabDialog::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) {
// Translate the message using accelerator table
ASSERT(m_hAccel);
return ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg);
}
return CDialog::PreTranslateMessage(pMsg);
}
//////////////////
// Handle idle message: update dialog controls. This is required to make
// the idle update command UI mechanism work for a dialog.
//
LRESULT CTabDialog::OnKickIdle(WPARAM wp, LPARAM lCount)
{
UpdateDialogControls(this, TRUE);
return 0;
}
/////////////////
// Initialize dialog: load accelerators and set initial focus.
//
BOOL CTabDialog::OnInitDialog()
{
m_hAccel = ::LoadAccelerators(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDD_DIALOG1));
ASSERT(m_hAccel);
GotoDlgCtrl(GetDlgItem(IDC_EDIT1));
return FALSE; // because I have set the focus
}
//////////////////
// Scramble/unscramble tab order
//
void CTabDialog::OnChangeTabs()
{
m_bRandomTabOrder = !m_bRandomTabOrder;
}
//////////////////
// Update name of Scramble/unscramble button
//
void CTabDialog::OnUpdateChangeTabs(CCmdUI* pCmdUI)
{
pCmdUI->SetText(m_bRandomTabOrder ?
"Unscramble &TAB Order" : "Scramble &TAB Order");
}
/////////////////
// Handle Return (Enter) key
//
void CTabDialog::OnReturn()
{
OnNextPrevField(ID_NEXT_FIELD);
}
/////////////////
// Go to next or previous field
//
BOOL CTabDialog::OnNextPrevField(UINT nCmdID)
{
CWnd* pWnd = CWnd::GetFocus();
if (m_bRandomTabOrder) {
static int controls[] = { IDC_EDIT1,
IDC_EDIT2, IDC_EDIT3, IDC_COMBO1, ID_CHANGE_TABS, IDOK, IDCANCEL };
const NCONTROLS = sizeof(controls)/sizeof(int);
// Select a random control that's different from the current one.
int nIDCtrl;
while ((nIDCtrl = controls[rand() % NCONTROLS]) == pWnd->GetDlgCtrlID())
; // same as current, try another
pWnd = GetDlgItem(nIDCtrl);
} else
// Normal next/prev using dialog's TAB order.
pWnd = GetNextDlgTabItem(pWnd, nCmdID==ID_PREV_FIELD);
ASSERT(pWnd);
GotoDlgCtrl(pWnd);
return TRUE;
}
Figure 6 Functions for Navigating Dialog Controls
|
CWnd Function |
|
|
CWnd* GetNextDlgTabItem(CWnd* pWndCtl, BOOL bPrevious = FALSE) |
Gets the next child control in the dialog's tab order. |
|
CDialog Functions (These take care of highlighting edit text, and so on.) |
|
|
void CDialog::NextDlgCtrl() |
Move to next control |
|
void CDialog::PrevDlgCtrl() |
Move to previous control |
|
void CDialog::GotoDlgCtrl(CWnd* pWndCtrl) |
Move to specified control |
Figure 7 AfxRegisterWndClass
//////////////////
// How to register your own window class without CS_HREDRAW and CS_VREDRAW
//
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.lpszClass = AfxRegisterWndClass(
CS_DBLCLKS, // if you need double-clicks
NULL, // no cursor (use default)
NULL, // no background brush
AfxGetApp()->LoadIcon(IDR_MAINFRAME)); // app icon
ASSERT(cs.lpszClass);
return CFrameWnd::PreCreateWindow(cs);
}