Thread: CTabCtrl not receiving messages

  1. #1
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607

    CTabCtrl not receiving messages

    This is a bit of an advanced question but here goes.

    I want to use a tab control in a docked dialog. Since CPropertySheet won't do this correctly, I had to code my own as well as my own docking system.

    Docking system
    CDockContWnd
    Windows that are docked to the frame, act as containers for other windows.

    CDockDialog
    A docking dialog class compatible with CDockContWnd.


    Usage in tile editor

    CLayerDlg
    A CDockDialog derived class that displays the current layers of the tile map and allows the user to change view and draw layers. Has a CListBox object - just used the default one in MFC.

    CMyTabCtrl - a tab control derived from CTabCtrl that supports showing pages, adding pages, etc, etc.

    CToolsDlg
    A CDockDialog window contained in the CDockContWnd acting as a tools window for the tab control. Has a CMyTabCtrl object. This, in essence, is my replacement for CPropertySheet. Just wraps a CMyTabCtrl object.


    The tab control inside of the CToolsDlg is NOT receiving TCN_SELCHANGE and is not painting correctly. I downloaded a sample from codeguru for MSVC 6, converted it to .NET 2005 and it works just fine.

    However, when attempting to implement it into my own system, it does not paint correctly nor does it receive any messages.

    I'm not quite sure how to add a CTabCtrl object to the dialog in the resource editor, but use my own class instead of CTabCtrl.

    Here is the setup code from SetupMainView(), called by OnFileNewProject().

    CMainFrame.h
    Code:
    void CMainFrame::SetupMainView(void)
    {
      //Get pointer to view first
      m_pView=(CTileEditorView *)GetActiveView();
      
      //Get client rect of frame
      CRect rect;
      GetClientRect(&rect);
      
      //Create new tools dialog
      m_pToolsDlg=new CToolsDlg;
      m_pToolsDlg->Create(IDD_TOOLS,this);
    
      //Dock the dialog to the left side of the frame
      DockDialog(m_pToolsDlg,DLG_DOCK_LEFT);
      
      //Add a layer dialog (type CDockDialog) to the tools dialog
      //tab control
      CLayerDlg *dlg=new CLayerDlg();
      dlg->Create(IDD_LAYERWND,this);
      m_pToolsDlg->AddPage(dlg,L"Layers");
      ...
    ToolsDlg.cpp
    Code:
    // ToolsDlg.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "TileEditor.h"
    #include "ToolsDlg.h"
    
    
    // CToolsDlg dialog
    
    IMPLEMENT_DYNAMIC(CToolsDlg, CDockDialog)
    
    CToolsDlg::CToolsDlg(CWnd* pParent /*=NULL*/)
    	: CDockDialog(CToolsDlg::IDD, pParent)
    {
      
    }
    
    CToolsDlg::~CToolsDlg()
    {
    }
    
    void CToolsDlg::DoDataExchange(CDataExchange* pDX)
    {
      CDialog::DoDataExchange(pDX);
    
      DDX_Control(pDX, IDC_TAB_TOOLS, m_tabMyTabCtrl);
    }
    
    
    BEGIN_MESSAGE_MAP(CToolsDlg, CDockDialog)
    END_MESSAGE_MAP()
    
    
    // CToolsDlg message handlers
    Pretty simple, just a dummy CDockDialog. MFC does not support custom subclassing via Class Wizard so I changed some things myself to get it to work. Namely the message map and constructor.

    This works fine and dialogs receive messages. It's the tab control that isn't receiving messages. Also the layer dialog still receives it's messages even though it's inside of a tab control that is not. Quite odd.

    The tab appears in the tab control, but you must move the mouse over areas to invalidate it before you see the controls. Also when you add a second page, you can see both tabs, with a white window area, and nothing else works. Not even drawing on the first tabbed window.

    MyTabCtrl.h
    Code:
    #pragma once
    
    
    // CMyTabCtrl
    #include <vector>
    
    class CMyTabCtrl : public CTabCtrl
    {
      DECLARE_DYNAMIC(CMyTabCtrl)
      
      std::vector<CWnd *> m_vWnds;
      
    public:
    	
    	CMyTabCtrl();
    	virtual ~CMyTabCtrl();
    	
    	void ShowPage(int iPage);
    	void AddPage(CWnd *pDlg,CString text);
    	
    
    protected:
    	DECLARE_MESSAGE_MAP()
    public:
      
    public:
      afx_msg void OnTcnSelchange(NMHDR *pNMHDR, LRESULT *pResult);
    
      
    };
    MyTabCtrl.cpp
    Code:
    // MyTabCtrl.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "TileEditor.h"
    #include "MyTabCtrl.h"
    #include "DockDialog.h"
    #include "ToolsDlg.h"
    
    // CMyTabCtrl
    
    IMPLEMENT_DYNAMIC(CMyTabCtrl, CTabCtrl)
    
    CMyTabCtrl::CMyTabCtrl()
    {
      
    }
    
    CMyTabCtrl::~CMyTabCtrl()
    {
      //Cleanup vector of CWnds
      for (int i=0;i<static_cast<int>(m_vWnds.size());i++)
     {
        delete m_vWnds[i];
     }
    
    }
    
    
    BEGIN_MESSAGE_MAP(CMyTabCtrl, CTabCtrl)
      ON_NOTIFY_REFLECT(TCN_SELCHANGE, OnTcnSelchange)
    
    END_MESSAGE_MAP()
    
    void CMyTabCtrl::AddPage(CWnd *pWnd,CString text)
    {
      ASSERT(pWnd->m_hWnd);
      
      pWnd->ModifyStyle(WS_POPUP,WS_CHILD);
      
      m_vWnds.push_back(pWnd);
      
     
      InsertItem(m_vWnds.size()-1,text);
      
      ShowPage(m_vWnds.size()-1);
      
    }
    
    void CMyTabCtrl::ShowPage(int iPage)
    {
      m_vWnds[iPage]->ShowWindow(SW_HIDE);
        
      CRect rectClient;
      CRect rectWnd;
    
      
      GetClientRect(rectClient);
      AdjustRect(FALSE,rectClient);
      GetWindowRect(rectWnd);
      GetParent()->ScreenToClient(rectWnd);
      rectClient.OffsetRect(rectWnd.left,rectWnd.top);
      
      for(int nCount=0; nCount < static_cast<int>(m_vWnds.size()); nCount++)
      {
        m_vWnds[nCount]->SetWindowPos(&wndTop, 
                                       rectClient.left, 
                                       rectClient.top, 
                                       rectClient.Width(), 
                                       rectClient.Height(), 
                                       SWP_HIDEWINDOW);
      }
      
        m_vWnds[iPage]->SetWindowPos(&wndTop, 
                                  rectClient.left, 
                                  rectClient.top, 
                                  rectClient.Width(), 
                                  rectClient.Height(), 
                                  SWP_SHOWWINDOW);
    
      m_vWnds[iPage]->ShowWindow(SW_SHOW);
      m_vWnds[iPage]->Invalidate();
      Invalidate();
    
    }
    
    
    // CMyTabCtrl message handlers
    void CMyTabCtrl::OnTcnSelchange(NMHDR *pNMHDR, LRESULT *pResult)
    {
      // TODO: Add your control notification handler code here
      AfxMessageBox(L"On sel change");
      *pResult = 0;
    }

    Any ideas?

    Docking targets confusion
    From the code sample you may be confused with DockDialog().

    If you are confused as to how DockDialog() knows which CDockContWnd to use as the docking target, it is a hack for right now and always uses vector element 0 or m_vDockContWnds[0]. The docking system is not completely functional in that the layout manager is not yet taking into account all CDockContWnds attached to the frame. This is a simple fix, but right now I need to get this editor done so working on GUI while the game project just sits idle is not good.

    The target of the docking operation is normally specified in a third parameter (CDockContWnd *pDockTarget) and still can be by directly accessing the vector of CDockContWnd's in CMainFrame.

    void CMainFrame::DockDialog(CDockDialog *pDialog,
    DLG_DOCK_MODE mode,
    CDockContWnd *pDockTarget)


    enum DLG_DOCK_MODE {
    DLG_DOCK_TOP,
    DLG_DOCK_LEFT,
    DLG_DOCK_BOTTOM,
    DLG_DOCK_RIGHT
    };



    However this is not the source of the problem.
    Last edited by VirtualAce; 06-04-2006 at 06:24 PM.

  2. #2
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I got it working.

    Code:
    pWnd->SetParent(this);
    It wasn't drawing because it was not receiving the WM_PAINT message. Now the message is passed from the frame to the dock container to the docking dialog. And the tab control was receiving the message all along, I just had no way to prove it was since I never added more than 1 window. How can you have a TCN_SELCHANGE occur when you only have 1 tab in the control? You can't.

    Duh.
    Last edited by VirtualAce; 03-12-2011 at 11:42 AM.

  3. #3
    Registered User
    Join Date
    Jul 2009
    Posts
    1
    Hi Bubba, can you pls send me the complete source code of this programm. I muss creat an application similiar with yours. Though read your code can help me out. Thanks

  4. #4
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    Quote Originally Posted by tutigermany View Post
    Hi Bubba, can you pls send me the complete source code of this programm. I muss creat an application similiar with yours. Though read your code can help me out. Thanks
    plz email me teh codez

    Translation: do your own (home)work.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Spy++ view messages posted/sent to a control, or from it?
    By hanhao in forum Windows Programming
    Replies: 2
    Last Post: 06-24-2007, 11:07 PM
  2. Sending windows messages
    By Ideswa in forum Windows Programming
    Replies: 2
    Last Post: 03-02-2006, 01:27 PM
  3. Receiving Messages from other Applications
    By 1943 in forum Windows Programming
    Replies: 6
    Last Post: 07-21-2002, 12:00 AM
  4. Receiving messages from child of a child.
    By Sindol in forum Windows Programming
    Replies: 3
    Last Post: 01-26-2002, 07:58 AM