[转]如何使用CTabCtrl来实现多页面属性对话框?

导读:
  关于在VC中如何使用这个控件,大体思路可以这样:
  1)在资源管理器中创建几个Dialog, 分别生成相应的类(基于CDialog),注意,要设置Dialog的Style为"Child", Border为"None";
  2)在CDialog::OnInitDialog中,调用CTabCtrl::InsertItem(...)方法添加几个页面
  3)调用CDialog的Create方法创建几个对话框变量;
  3)在主窗口中,捕获Tab Control的页选择事件,在其中对索引值进行分类,然后就显示你的对话框,注意显示一个的同时,要隐藏其他的对话框。
  下面是个测试程序:
  
   [转]如何使用CTabCtrl来实现多页面属性对话框?_第1张图片
  
  主对话框:
  // TmpTstDlg.h : header file
  //
  #if !defined(AFX_TMPTSTDLG_H__881692D3_4A86_42CD_89F6_1FCB692A13F9__INCLUDED_)
  #define AFX_TMPTSTDLG_H__881692D3_4A86_42CD_89F6_1FCB692A13F9__INCLUDED_
  #if _MSC_VER >1000
  #pragma once
  #endif // _MSC_VER >1000
  #include "TreeDlg.h"
  #include "TstDlg.h"
  #include "OtherDlg.h"
  /////////////////////////////////////////////////////////////////////////////
  // CTmpTstDlg dialog
  class CTmpTstDlg : public CDialog
  {
  // Construction
  public:
  CTmpTstDlg(CWnd* pParent = NULL); // standard constructor
  // Dialog Data
  //{{AFX_DATA(CTmpTstDlg)
  enum { IDD = IDD_TMPTST_DIALOG };
  CTabCtrl m_ctrlTab;
  //}}AFX_DATA
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CTmpTstDlg)
  public:
  virtual BOOL PreTranslateMessage(MSG* pMsg);
  protected:
  virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
  //}}AFX_VIRTUAL
  // Implementation
  protected:
  HICON m_hIcon;
  CMenu m_menuMain;
  void AdjustCtrl();
  // Generated message map functions
  //{{AFX_MSG(CTmpTstDlg)
  virtual BOOL OnInitDialog();
  afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  afx_msg void OnPaint();
  afx_msg HCURSOR OnQueryDragIcon();
  afx_msg void OnDestroy();
  afx_msg void OnSize(UINT nType, int cx, int cy);
  afx_msg void OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult);
  afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
  afx_msg void OnAbout();
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()
  private:
  CTreeDlg m_dlgTree;
  CTstDlg m_dlgTst;
  COtherDlg m_dlgOther;
  };
  //{{AFX_INSERT_LOCATION}}
  // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
  #endif // !defined(AFX_TMPTSTDLG_H__881692D3_4A86_42CD_89F6_1FCB692A13F9__INCLUDED_)
  // TmpTstDlg.cpp : implementation file
  //
  #include "stdafx.h"
  #include "TmpTst.h"
  #include "TmpTstDlg.h"
  #ifdef _DEBUG
  #define new DEBUG_NEW
  #undef THIS_FILE
  static char THIS_FILE[] = __FILE__;
  #endif
  #pragma comment(lib, "vfw32.lib")
  #pragma comment(lib, "User32.lib")
  /////////////////////////////////////////////////////////////////////////////
  // CAboutDlg dialog used for App About
  class CAboutDlg : public CDialog
  {
  public:
  CAboutDlg();
  // Dialog Data
  //{{AFX_DATA(CAboutDlg)
  enum { IDD = IDD_ABOUTBOX };
  //}}AFX_DATA
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CAboutDlg)
  protected:
  virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
  //}}AFX_VIRTUAL
  // Implementation
  protected:
  //{{AFX_MSG(CAboutDlg)
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()
  };
  CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  {
  //{{AFX_DATA_INIT(CAboutDlg)
  //}}AFX_DATA_INIT
  }
  void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  {
  CDialog::DoDataExchange(pDX);
  //{{AFX_DATA_MAP(CAboutDlg)
  //}}AFX_DATA_MAP
  }
  BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  //{{AFX_MSG_MAP(CAboutDlg)
  // No message handlers
  //}}AFX_MSG_MAP
  END_MESSAGE_MAP()
  /////////////////////////////////////////////////////////////////////////////
  // CTmpTstDlg dialog
  CTmpTstDlg::CTmpTstDlg(CWnd* pParent /*=NULL*/)
  : CDialog(CTmpTstDlg::IDD, pParent)
  {
  //{{AFX_DATA_INIT(CTmpTstDlg)
  // NOTE: the ClassWizard will add member initialization here
  //}}AFX_DATA_INIT
  // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  }
  void CTmpTstDlg::DoDataExchange(CDataExchange* pDX)
  {
  CDialog::DoDataExchange(pDX);
  //{{AFX_DATA_MAP(CTmpTstDlg)
  DDX_Control(pDX, IDC_TAB1, m_ctrlTab);
  //}}AFX_DATA_MAP
  }
  BEGIN_MESSAGE_MAP(CTmpTstDlg, CDialog)
  //{{AFX_MSG_MAP(CTmpTstDlg)
  ON_WM_SYSCOMMAND()
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  ON_WM_DESTROY()
  ON_WM_SIZE()
  ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnSelchangeTab1)
  ON_WM_CREATE()
  ON_COMMAND(ID_ABOUT, OnAbout)
  //}}AFX_MSG_MAP
  END_MESSAGE_MAP()
  /////////////////////////////////////////////////////////////////////////////
  // CTmpTstDlg message handlers
  BOOL CTmpTstDlg::OnInitDialog()
  {
  CDialog::OnInitDialog();
  // Add "About..." menu item to system menu.
  // IDM_ABOUTBOX must be in the system command range.
  ASSERT((IDM_ABOUTBOX &0xFFF0) == IDM_ABOUTBOX);
  ASSERT(IDM_ABOUTBOX <0xF000);
  CMenu* pSysMenu = GetSystemMenu(FALSE);
  if (pSysMenu != NULL)
  {
  CString strAboutMenu;
  strAboutMenu.LoadString(IDS_ABOUTBOX);
  if (!strAboutMenu.IsEmpty())
  {
  pSysMenu->AppendMenu(MF_SEPARATOR);
  pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  }
  }
  // Set the icon for this dialog. The framework does this automatically
  // when the application's main window is not a dialog
  SetIcon(m_hIcon, TRUE); // Set big icon
  SetIcon(m_hIcon, FALSE); // Set small icon
  
  // TODO: Add extra initialization here
  WORD wVersion = 0;
  WSAData sttWsa;
  CString m_strErrMsg;
  memset(&sttWsa, 0, sizeof(WSAData));
  wVersion = MAKEWORD(2, 0);
  if (0 != WSAStartup(wVersion, &sttWsa))
  {
  m_strErrMsg.Format("Fail to initialize socket of version [%u], and error no is [%ld]",
  wVersion, WSAGetLastError());
  MessageBox(m_strErrMsg, "Initialization Error", MB_OK + MB_ICONSTOP);
  WSACleanup();
  return -1;
  }
  /*m_hMenu = ::LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MENU1));
  ASSERT(m_hMenu);
  CMenu* pMenu = CMenu::FromHandle(hMenu);
  ASSERT(pMenu);
  SetMenu(pMenu);
  */
  ASSERT(m_menuMain.LoadMenu(IDR_MENU1));
  ASSERT(SetMenu(&m_menuMain));
  this->AdjustCtrl();
  //add pages for tab
  BOOL bRet = FALSE;
  bRet = m_ctrlTab.InsertItem(0, _T("树操作测试"));
  bRet = m_ctrlTab.InsertItem(1, _T("临时测试"));
  bRet = m_ctrlTab.InsertItem(2, "其他测试");
  ASSERT(bRet);
  /*CRect rc;
  m_ctrlTab.GetClientRect(rc);
  
  rc.top+=20;
  rc.bottom-=4;
  rc.left+=4;
  rc.right-=4;
  
  //adjust size
  m_dlgTree.MoveWindow(rc);
  m_dlgTst.MoveWindow(rc);
  m_dlgOther.MoveWindow(rc);
  
  m_dlgTree.ShowWindow(SW_SHOW);
  m_ctrlTab.SetCurSel(0);//set focus on first page
  */
  return TRUE; // return TRUE unless you set the focus to a control
  }
  void CTmpTstDlg::OnSysCommand(UINT nID, LPARAM lParam)
  {
  if ((nID &0xFFF0) == IDM_ABOUTBOX)
  {
  CAboutDlg dlgAbout;
  dlgAbout.DoModal();
  }
  else
  {
  CDialog::OnSysCommand(nID, lParam);
  }
  }
  // If you add a minimize button to your dialog, you will need the code below
  // to draw the icon. For MFC applications using the document/view model,
  // this is automatically done for you by the framework.
  void CTmpTstDlg::OnPaint()
  {
  if (IsIconic())
  {
  CPaintDC dc(this); // device context for painting
  SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  // Center icon in client rectangle
  int cxIcon = GetSystemMetrics(SM_CXICON);
  int cyIcon = GetSystemMetrics(SM_CYICON);
  CRect rect;
  GetClientRect(&rect);
  int x = (rect.Width() - cxIcon + 1) / 2;
  int y = (rect.Height() - cyIcon + 1) / 2;
  // Draw the icon
  dc.DrawIcon(x, y, m_hIcon);
  }
  else
  {
  CDialog::OnPaint();
  //this->AdjustCtrl();
  }
  }
  // The system calls this to obtain the cursor to display while the user drags
  // the minimized window.
  HCURSOR CTmpTstDlg::OnQueryDragIcon()
  {
  return (HCURSOR) m_hIcon;
  }
  int CTmpTstDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
  {
  if (CDialog::OnCreate(lpCreateStruct) == -1)
  return -1;
  
  // TODO: Add your specialized creation code here
  ASSERT(m_dlgTree.Create(IDD_DIALOG1, GetDlgItem(IDC_TAB1)));
  ASSERT(m_dlgTst.Create(IDD_DIALOG2, GetDlgItem(IDC_TAB1)));
  ASSERT(m_dlgOther.Create(IDD_DIALOG3, GetDlgItem(IDC_TAB1)));
  return 0;
  }
  void CTmpTstDlg::OnDestroy()
  {
  CDialog::OnDestroy();
  
  // TODO: Add your message handler code here
  m_menuMain.DestroyMenu();
  m_dlgTree.DestroyWindow();
  m_dlgTst.DestroyWindow();
  m_dlgOther.DestroyWindow();
  }
  void CTmpTstDlg::AdjustCtrl()
  {
  /*if (GetMenu())
  {
  SetMenu(NULL);
  }*/
  
  int iCapHgh = ::GetSystemMetrics(SM_CYCAPTION);//caption height:19(default)
  TRACE("Caption height is %ld in pixels/n", iCapHgh);
  int iBordWid = ::GetSystemMetrics(SM_CXBORDER);//border width:1(default)
  int iBordHgh = ::GetSystemMetrics(SM_CYBORDER);//border height:1(default)
  TRACE("Horizonal border width is %ld in pixels/n", iBordWid);
  TRACE("Vertical border height is %ld in pixels/n", iBordHgh);
  CRect rcClient(0, 0, 0, 0);
  GetClientRect(rcClient);
  
  CWnd* pWndOk = GetDlgItem(IDOK);
  CWnd* pWndCancel = GetDlgItem(IDCANCEL);
  ASSERT_VALID(pWndOk);
  ASSERT_VALID(pWndCancel);
  CRect rcBtnOk(0, 0, 0, 0);
  CRect rcBtnCancel(0, 0, 0, 0);
  pWndOk->GetWindowRect(rcBtnOk);
  ScreenToClient(rcBtnOk);
  pWndOk->GetWindowRect(rcBtnCancel);
  ScreenToClient(rcBtnCancel);
  
  //calculate coordinates of 'IDOK' button
  int iBtnWid = rcBtnOk.Width();
  int iBtnHgh = rcBtnOk.Height();
  rcBtnOk.left = rcClient.right - 2*iBtnWid /*- iBordWid*/ - 1;
  rcBtnOk.top = rcClient.bottom - iBtnHgh/* - iBordHgh*/;
  rcBtnOk.right = rcBtnOk.left + iBtnWid;
  rcBtnOk.bottom = rcBtnOk.top + iBtnHgh;
  //calculate coordinates of 'IDCANCEL' button
  rcBtnCancel.left = rcBtnOk.right + 1;
  rcBtnCancel.top = rcBtnOk.top;
  rcBtnCancel.right = rcBtnCancel.left + iBtnWid;
  rcBtnCancel.bottom = rcBtnOk.bottom;
  BOOL bRet = pWndOk->SetWindowPos(NULL, rcBtnOk.left, rcBtnOk.top,
  rcBtnOk.Width(), rcBtnOk.Height(), SWP_NOSIZE | SWP_NOZORDER);
  ASSERT(bRet);
  bRet = pWndCancel->SetWindowPos(NULL, rcBtnCancel.left, rcBtnCancel.top,
  rcBtnCancel.Width(), rcBtnCancel.Height(), SWP_NOSIZE | SWP_NOZORDER);
  ASSERT(bRet);
  
  CRect rcTab(rcClient);
  rcTab.bottom = rcBtnOk.top - 1;
  m_ctrlTab.MoveWindow(rcTab);
  //ajust coordinates
  CRect rc;
  m_ctrlTab.GetClientRect(rc);
  rc.top+=20;
  rc.bottom-=4;
  rc.left+=4;
  rc.right-=4;
  
  //adjust per page size
  m_dlgTree.MoveWindow(rc);
  m_dlgTst.MoveWindow(rc);
  m_dlgOther.MoveWindow(rc);
  
  //show first page at first
  m_dlgTree.ShowWindow(SW_SHOW);
  m_ctrlTab.SetCurSel(0);//set focus on first page
  }
  void CTmpTstDlg::OnSize(UINT nType, int cx, int cy)
  {
  // TODO: Add your message handler code here
  CDialog::OnSize(nType, cx, cy);
  
  if (SIZE_MAXIMIZED == nType)
  {
  this->AdjustCtrl();
  }
  if (NULL != GetDlgItem(IDOK))//very mild, modified
  {
  if (SIZE_RESTORED == nType)
  {
  this->AdjustCtrl();
  }
  }
  }
  void CTmpTstDlg::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
  {
  // TODO: Add your control notification handler code here
  int iIndex = m_ctrlTab.GetCurSel();
  switch (iIndex)
  {
  case -1:
  {
  break;
  }
  case 0:
  {
  m_dlgTree.ShowWindow(SW_SHOW);
  m_dlgTst.ShowWindow(SW_HIDE);
  m_dlgOther.ShowWindow(SW_HIDE);
  break;
  }
  case 1:
  {
  m_dlgTree.ShowWindow(SW_HIDE);
  m_dlgTst.ShowWindow(SW_SHOW);
  m_dlgOther.ShowWindow(SW_HIDE);
  break;
  }
  case 2:
  {
  m_dlgTree.ShowWindow(SW_HIDE);
  m_dlgTst.ShowWindow(SW_HIDE);
  m_dlgOther.ShowWindow(SW_SHOW);
  break;
  }
  default:
  {
  break;
  }
  }
  *pResult = 0;
  }
  void CTmpTstDlg::OnAbout()
  {
  // TODO: Add your command handler code here
  CAboutDlg dlgAbout;
  dlgAbout.DoModal();
  }
  BOOL CTmpTstDlg::PreTranslateMessage(MSG* pMsg)
  {
  // TODO: Add your specialized code here and/or call the base class
  if (pMsg->message == WM_KEYDOWN)
  {
  if (VK_ESCAPE == pMsg->wParam)
  {
  return FALSE;
  }
  }
  return CDialog::PreTranslateMessage(pMsg);
  }

本文转自
http://blog.csdn.net/zcm242004/archive/2006/08/30/1144439.aspx

你可能感兴趣的:([转]如何使用CTabCtrl来实现多页面属性对话框?)