Tab Controls



  • Hallo !

    Wie realisiere ich das umschalten mit den tab controls am effizientesten ? Bis jetzt habe ich immer für jeden tab ein satic window verwendet und dieses als parent angegeben für die jeweiligen komponenten (und dann eben show und hide angewendet, je nach dem welcher tab angezeigt werden soll).

    In der MSDN findet man dazu auch keine bsp, nur ein kleines wo aber nur andere strings angezeigt werden.

    Ist der Ansatz so ok, oder ist das eher schlechtes design ? und falls ja, wie macht mans richtig ? 🙂


  • Mod

    Es gibt PropertySheet doch direkt in der WinApi verankert. Du musst das nicht händisch machen.

    http://msdn.microsoft.com/en-us/library/cc656536(VS.85).aspx



  • Hi,
    Ich hatte mir eine kleine Klasse gebastelt, die über den Tabwechsel ein child window anzeigt das ich dann beliebig füllen kann,... pro tab ein childwindow,...
    Zum Beispiel ist die tabRcp_firstPageProc die CALLBACK für das erste tab childwindow....

    Header:

    //******************************************************************************
    // TabControl
    //******************************************************************************
    
    typedef struct _tcpages{
    	HWND hWndWindowHandle;
    	WNDPROC wpProc;
    	int iIndex;
    	std::string str_title;
    	BOOL bHidden;
    	_tcpages(){
    	hWndWindowHandle=(HWND)NULL;
    	wpProc=(WNDPROC)NULL;
    	iIndex=0;
    	str_title.clear();
    	bHidden=FALSE;
    	};
    
    }TCPAGES,*LPTCPAGES;
    
    typedef std::vector<TCPAGES> _tcsv;
    
    typedef struct _tcstruct{
    DWORD dwExStyle;
        LPCTSTR lpClassName;                  
        LPCTSTR lpWindowName;
        DWORD dwStyle;
        int x;
        int y;
        int nWidth;
        int nHeight;
        HWND hWndParent;
        HMENU hMenu;
        HINSTANCE hInstance;
        LPVOID lpParam;
        HWND handle;
    	WNDPROC wpOldProc, wpNewProc;
    _tcsv tcpages_vec;
    _tcstruct(){
    lpClassName=NULL;
    lpWindowName=NULL;
    dwStyle=NULL;
    x=0;
    y=0;
    nWidth=0;
    nHeight=0;
    hWndParent=(HWND)NULL;
    hMenu=(HMENU)NULL;
    hInstance=(HINSTANCE)NULL;
    lpParam=(LPVOID)NULL;
    handle=(HWND)NULL;
    wpOldProc=(WNDPROC)NULL;
    wpNewProc=(WNDPROC)NULL;
    };
    }TCSTRUCT,*LPTCSTRUCT;
    
    class TabControl{
    private:
    TCSTRUCT _tc; 
    protected:
    
    public:    
       bool is_set;
       TabControl();
       TabControl(int xPos,int yPos,int width,int height, HINSTANCE instance, HWND hWnd);
       HWND getHandle();
       bool CreateTabControl(WNDPROC);
       ~TabControl();
    WNDPROC getOldProc(void);
    void AddTabPage(int, std::string, WNDPROC);
    void HideTabPage(int);
    void DeleteTabPage(int);
    void ShowTabPage(int);
    void MovePages(RECT rct);
    static const UINT SET_THIS_PTR=(WM_USER+33);
    };
    

    Dann der Code:

    //****************************************************************************************
    // TabControl
    //****************************************************************************************
    TabControl::TabControl(int xPos, int yPos,int width,int height, HINSTANCE instance, HWND hWnd)
    {
    	this->_tc.dwExStyle=NULL;
    	this->_tc.dwStyle=WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
    	this->_tc.handle=(HWND)NULL;
    	this->_tc.hInstance=instance;
    	this->_tc.hMenu=(HMENU)NULL;
    	this->_tc.hWndParent=hWnd;
    	this->_tc.lpClassName=WC_TABCONTROL;;
    	this->_tc.lpWindowName=NULL;
    	this->_tc.lpParam=NULL;
    	this->_tc.nHeight=height;
    	this->_tc.nWidth=width;
    	this->_tc.x=xPos;
    	this->_tc.y=yPos;
    };
    bool TabControl::CreateTabControl(WNDPROC wpProc)
    {
    RECT rct={0};
    GetClientRect(this->_tc.hWndParent,&rct);
    InitCommonControls();
    this->_tc.handle=CreateWindow(WC_TABCONTROL,TEXT(""),
    					 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,
    					 0,0,rct.right+5,rct.bottom-100,
    					 this->_tc.hWndParent,NULL,this->_tc.hInstance,NULL);
    //if(this->
    ShowWindow(this->_tc.handle,SW_SHOWNORMAL);
    this->_tc.wpOldProc=(WNDPROC)SetWindowLong(this->_tc.handle,GWL_WNDPROC,(LONG)wpProc);
    this->_tc.wpNewProc=wpProc;
    SendMessage(this->_tc.handle,TabControl::SET_THIS_PTR,(WPARAM)NULL,(LPARAM)this);
    
    return 1;
    }
    
    WNDPROC TabControl::getOldProc(void)
    {return (this->_tc.wpOldProc);}
    
    void TabControl::AddTabPage(int _i, std::string _str, WNDPROC wpProc)
    {
    
    TCPAGES _tp;
    _tp.bHidden=FALSE;
    _tp.wpProc=wpProc;
    _tp.iIndex=_i;
    _tp.str_title=_str;
    
    WNDCLASS wc;
    GetClassInfo(this->_tc.hInstance,_T("EDIT"),&wc);
        //wc.cbSize         =sizeof(WNDCLASSEX);
    	wc.hInstance      =this->_tc.hInstance;
        wc.style          = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc    = wpProc;
        wc.cbClsExtra     = 0;
        wc.cbWndExtra     = 0;
        wc.hIcon          = (HICON)NULL;//LoadIcon(NULL,IDI_EXCLAMATION);
        wc.hCursor        = (HICON)NULL;//LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground  = (HBRUSH)(CreateSolidBrush(0x00ffffff));
        //wc.lpszMenuName   = NULL;
    	wc.lpszClassName  = _str.c_str();
    RegisterClass(&wc);
    
    RECT rct={0};
    GetClientRect(this->_tc.handle,&rct);
    //rct.right=300;
    //rct.bottom=300;
    //rct.top=25;
    //rct.left=0;
    _tp.hWndWindowHandle=CreateWindowEx(WS_EX_COMPOSITED,wc.lpszClassName,TEXT(""),
    					 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,
    					 rct.left,rct.top+25,rct.right-25,rct.bottom-105,
    					 this->_tc.handle,NULL,this->_tc.hInstance,NULL);
    
    if(_tp.hWndWindowHandle==NULL){return;}
    //get last item, indes starts by zero
    int iSize=this->_tc.tcpages_vec.size();
    this->_tc.tcpages_vec.push_back(_tp);
    
    TCITEM tie;
    char g_achTemp[255]={0};
    tie.mask=TCIF_TEXT|TCIF_IMAGE;
    tie.iImage=-1;
    tie.pszText=g_achTemp;
    CopyMemory(g_achTemp,_str.c_str(),_str.length());
    SendMessage(this->_tc.handle,TCM_INSERTITEM,(WPARAM)iSize,(LPARAM)&tie);
    
    };
    void TabControl::HideTabPage(int iIndex)
    {
    	int iSize=this->_tc.tcpages_vec.size();
    
    	_tcsv::iterator itBegin=this->_tc.tcpages_vec.begin();
    	_tcsv::iterator itEnd=this->_tc.tcpages_vec.end();
    	BOOL done=FALSE;
    	_tcsv::iterator itCounter=itBegin;
    
    	while(!done)
    	{
    		if(itCounter->iIndex==iIndex)
    			{
    				done=TRUE;
    				itCounter->bHidden=TRUE;
    				CallWindowProc(this->_tc.wpOldProc,this->_tc.handle,TCM_DELETEITEM,(WPARAM)iIndex,(LPARAM)NULL);
    			}	
    		if(itCounter==itEnd)
    		{
    				done=TRUE;
    		}
    		else
    		{
    				itCounter++;
    		}
    	};
    
    //Select now the smallest index
    int iSmalestIndex=iSize;
    while(!done)
    	{
    		if((itCounter->iIndex<iSmalestIndex)&&(itCounter->bHidden==FALSE))
    			{
    				iSmalestIndex=itCounter->iIndex;
    			}	
    		if(itCounter==itEnd)
    		{
    				done=TRUE;
    		}
    		else
    		{
    				itCounter++;
    		}
    	};
    
    CallWindowProc(this->_tc.wpOldProc,this->_tc.handle,TCM_SETCURSEL,(WPARAM)iSmalestIndex,(LPARAM)NULL);
    };
    
    void TabControl::DeleteTabPage(int iIndex)
    {
    int iSize=this->_tc.tcpages_vec.size();
    	if(iIndex>=iSize){ return;};
    
    	_tcsv::iterator itBegin=this->_tc.tcpages_vec.begin();
    	_tcsv::iterator itEnd=this->_tc.tcpages_vec.end();
    	BOOL done=FALSE;
    	_tcsv::iterator itCounter=itBegin;
    
    	while(!done)
    	{
    		if(itCounter->iIndex==iIndex)
    			{
    				itCounter->bHidden=TRUE;
    				DestroyWindow(itCounter->hWndWindowHandle);
    				done=TRUE;
    				CallWindowProc(this->_tc.wpOldProc,this->_tc.handle,TCM_DELETEITEM,(WPARAM)iIndex,(LPARAM)NULL);
    			}	
    		if(itCounter==itEnd)
    		{
    				done=TRUE;
    		}
    		else
    		{
    				itCounter++;
    		}
    	};
    this->_tc.tcpages_vec.erase(itCounter);
    
    int iSmalestIndex=iSize;
    while(!done)
    	{
    		if((itCounter->iIndex<iSmalestIndex)&&(itCounter->bHidden==FALSE))
    			{
    				iSmalestIndex=itCounter->iIndex;
    			}	
    		if(itCounter==itEnd)
    		{
    				done=TRUE;
    		}
    		else
    		{
    				itCounter++;
    		}
    	};
    
    SendMessage(this->_tc.handle,TCM_SETCURSEL,(WPARAM)iSmalestIndex,(LPARAM)NULL);
    
    return;
    };
    
    void TabControl::ShowTabPage(int iIndex)
    {
    	_tcsv::iterator itBegin=this->_tc.tcpages_vec.begin();
    	_tcsv::iterator itEnd=this->_tc.tcpages_vec.end();
    	BOOL done=FALSE;
    
    	for(_tcsv::iterator itCounter=itBegin; itCounter!=itEnd; itCounter++)
    	{ SendMessage(itCounter->hWndWindowHandle,WM_CLOSE,NULL,NULL);};
    
    _tcsv::iterator itCounter=itBegin;
    while(!done)
    	{
    		if(itCounter->iIndex==iIndex)
    			{
    				//has been deleted the item before ?
    				if(itCounter->bHidden==TRUE)
    				{							
    					TCITEM tie;
    					char g_achTemp[255]={0};
    					tie.mask=TCIF_TEXT|TCIF_IMAGE;
    					tie.iImage=-1;
    					tie.pszText=g_achTemp;
    					CopyMemory(g_achTemp,itCounter->str_title.c_str(),itCounter->str_title.length());	
    					CallWindowProc(this->_tc.wpOldProc,this->_tc.handle,TCM_SETITEM,(WPARAM)iIndex,(LPARAM)&tie);
    					itCounter->bHidden=FALSE;
    
    				}
    				done=TRUE;
    				//SendMessage(this->_tc.handle,TCM_SETCURSEL,(WPARAM)iIndex,(LPARAM)NULL);
    				ShowWindow(itCounter->hWndWindowHandle,SW_SHOWNORMAL);
    			}
    		else
    		{
    	//		ShowWindow(itCounter->hWndWindowHandle,SW_HIDE);
    		if(itCounter==itEnd)
    		{
    				done=TRUE;
    		}
    		else
    		{
    				itCounter++;
    		}
    		};
    }
    return;
    };
    
    HWND TabControl::getHandle(void)
    { return (this->_tc.handle);};
    
    void TabControl::MovePages(RECT rct)
    {
    
    	int iSize=this->_tc.tcpages_vec.size();
    	for(int i=0; i<iSize; i++)
    	{
    		MoveWindow(this->_tc.tcpages_vec[i].hWndWindowHandle,rct.left,rct.top,rct.right,rct.bottom,TRUE);
    
    	}
    };
    TabControl::TabControl(){};
    TabControl::~TabControl(){};
    

    Eine Verwaltungsproc:

    LRESULT CALLBACK tabRcpProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    static TabControl *tcOriginal=NULL;
    
    static WNDPROC wpOldProc=NULL;	
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;
    	HDC hdc;
    	RECT rct;
    static HBITMAP hBackground=NULL;
    
    switch (message)
    {
    case TabControl::SET_THIS_PTR:
    	{
    tcOriginal=(TabControl*)lParam;
    wpOldProc=(WNDPROC) (tcOriginal->getOldProc());
    hBackground=(HBITMAP)LoadBitmap(hGlobalInstance,MAKEINTRESOURCE(IDB_TAB_BKGND));
    
    return 1;
    	}
    case WM_PAINT:
    	{
    return CallWindowProc(wpOldProc,hWnd,message,wParam,lParam);
    	}
    
    case WM_MOUSEHOVER|WM_MOUSEMOVE:
    	{
    
    int i=2;
    return 1;	
    	}
    
    case WM_SIZE:
    	{
    
    		if(tcOriginal==NULL){return DefWindowProc(hWnd,WM_SIZE,wParam,lParam);};
    		CallWindowProc(wpOldProc,hWnd,message,wParam,lParam);
    		RECT rect;
    		 rect.top=50;
    		 rect.left=2;
    		 rect.right=LOWORD(lParam)-rect.left-4;
    		 rect.bottom=HIWORD(lParam)-rect.top-4;
    		 tcOriginal->MovePages(rect);
    
    return 0;
    	};
    
    }
    if(wpOldProc==NULL){
    	return DefWindowProc(hWnd,message,wParam,lParam);}
    else{ return CallWindowProc(wpOldProc,hWnd,message,wParam,lParam);};
    }
    

    Dann die Anwendung:

    static TabControl tabRcp(0,0,0,0,hInst,hWnd);
    	switch (message)
    	{
    
    	case WM_CREATE:
    		{
    			tabRcp.CreateTabControl((WNDPROC)tabRcpProc);
    			RECT rct;
    			GetWindowRect(hWnd,&rct);
    			TabCtrl_SetItemSize(tabRcp.getHandle(),0,40);
    			MoveWindow(tabRcpEdit.getHandle(),0,0,rct.right,rct.bottom,TRUE);
    			ShowWindow(tabRcp.getHandle(),SW_SHOWNORMAL);
    			tabRcp.AddTabPage(0," first \0",tabRcp_firstPageProc);
    			tabRcp.AddTabPage(1," second \0",tabRcp_secondPageProc);
    			tabRcp.AddTabPage(2," third \0",tabRcp_thirdPageProc);
    
    			tabRcp.ShowTabPage(0);
    			HFONT hMeinFontBold = CreateFont(16,0,0,0,FW_BOLD,FALSE,FALSE,0,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH | FF_DONTCARE,"Arial"); 
    			SendMessage(tabRcp.getHandle(),WM_SETFONT,(WPARAM)hMeinFontBold,(LPARAM)NULL);
    
    break;}
    case WM_SIZE:
    		{
    		 HDWP hdwp;
    		 RECT rect;
    		 rect.top=0;
    		 rect.left=0;
    		 rect.right=LOWORD(lParam);
    		 rect.bottom=HIWORD(lParam);
    
    		 GetClientRect(hWnd,&rect);
    		 		 MoveWindow(tabRcp.getHandle(),0,0,rect.right,rect.bottom,FALSE);
    
    		break;
    		};
    
    	case WM_NOTIFY:
    		{
    			switch(((LPNMHDR)lParam)->code)
    			{
    			case  TCN_SELCHANGE:
    				{
    					int iPage=TabCtrl_GetCurSel(tabRcp.getHandle());
    
    					tabRcp.ShowTabPage(iPage);
    
    				}
    			}
    
    		return DefWindowProc(hWnd,message,wParam,lParam);
    
    		};
    


  • aso,... ich benutze für bessere optik die Common controls (InitCommonControls) mit manifestfile in XP style,... deswegen ist auch der weiße hintergrund der childfenster gewählt,...'

    grüße


Anmelden zum Antworten