CTabCtrl -> Seiten aufbauen

langer1801

Erfahrenes Mitglied
Hallo, ich habe ein Projekt im Explorer-Stil, links von CTreeView und rechts eine von CFormView abgeleitete Klasse. In dieser FormView habe ich ein CTabCtrl. Das Einfügen von Seiten mittels InsertItem ist auch kein Problem. Nur - danach habe ich erstmal leere Seiten zur Verfügung. Wie bringe ich meine Steuerelemente auf die Seiten? Kann man einfach Dialoge vom Typ CPropertyPage an die Seiten übergeben? Und wenn ja, wie?

Danke

langer
 

MCoder

Erfahrenes Mitglied
CPropertyPage ist für die Verwendung in CPropertySheet gedacht. Für CTabControl reicht eine normale CDialog basierte Klasse. Das Dialog-Template sollte keinen Titel und keinen Rand haben und den Style WS_CHILD (untergeordnet) besitzen.

Der Code zum Einbinden des Dialogs schaut so aus:
Code:
// m_dlgTab ist ein Objekt der Klasse CMyDialog (als Beispiel)
// m_TabCtrl ist das CTabCtrl-Objekt

// Dialog erzeugen
m_dlgTab.Create(CMyDialog::IDD, m_TabCtrl);

CString strTitle = _T("Tab Überschrift");   // Titel des Dialogs
int     iIndex   = 0                        // Tab-Index

// Dialog  als Tab hinzufügen
TCITEM item;
item.mask    = TCIF_TEXT | TCIF_PARAM;
item.lParam  = (LPARAM)&m_dlgTab;
item.pszText = (LPTSTR)(LPCTSTR)strText;
m_TabCtrl.InsertItem(iIndex, &item);

// Dialog positionieren
CRect rcItem;
m_TabCtrl.GetItemRect(0, &rcItem);

m_dlgTab.SetWindowPos( NULL,
                       rcItem.left,
                       rcItem.bottom + 1,
                       0,
                       0,
                       SWP_NOSIZE | SWP_NOZORDER );

// Anzeigen (nur den ersten Tab)
m_dlgTab.ShowWindow(iIndex ? SW_HIDE : SW_SHOW);

Bei Verwendung von CTabCtrl musst du dich allerdings auch noch selber um die Umschaltung der Tabs kümmern
Code:
// benötigte Member-Variable: m_uiSelectedTab (mit 0 vorbelegen)

// Message-Handler für TCN_SELCHANG
void CMyFormView::OnSelchangeTabcontrol(NMHDR* pNMHDR, LRESULT* pResult) 
{
    TCITEM  item;
    CWnd*   pWnd;
    int     iNewTab = m_TabCtrl.GetCurSel();

    item.mask = TCIF_PARAM;

    // aktuellen Tab ausblenden
    m_TabCtrl.GetItem(m_uiSelectedTab, &item);
    if( item.lParam )
    {
        pWnd = reinterpret_cast<CWnd*> (item.lParam);
        pWnd->ShowWindow(SW_HIDE);
    }

    // neuen Tab anzeigen
    m_TabCtrl.GetItem(iNewTab, &item);
    if(item.lParam)
    {
        pWnd = reinterpret_cast<CWnd*> (item.lParam);
        pWnd->ShowWindow(SW_SHOW);
    }

    *pResult = 0;
}

// Message-Handler für TCN_SELCHANGING
void CMyFormView::OnSelchangingTabcontrol(NMHDR* pNMHDR, LRESULT* pResult) 
{
    m_uiSelectedTab = m_TabCtrl.GetCurSel();
    *pResult = 0;
}
 

langer1801

Erfahrenes Mitglied
Danke für die Antwort. Habe den Code mal ausprobiert in meinem Projekt. Das Einfügen des Items klappt problemlos. Nur wird der Dialog nicht angezeigt.
Code:
void CAbrVersuchView::OnInitialUpdate()
{
	TCITEM item;
	int iIndex=0;
	CString strTitel = _T("Patientendaten");
	CVersuchDlg m_versuch;
	m_versuch.Create(CVersuchDlg::IDD,&ctr_Tab1);
	CFormView::OnInitialUpdate();
	GetParentFrame()->RecalcLayout();
	ResizeParentToFit();
	item.mask=TCIF_TEXT|TCIF_PARAM;
	item.lParam=(LPARAM)&m_versuch;
	item.pszText=(LPTSTR)(LPCTSTR)strTitel;
	ctr_Tab1.InsertItem(iIndex,&item);
	CRect rcItem;
	ctr_Tab1.GetItemRect(0,&rcItem);
	ctr_Tab1.SetWindowPos(NULL,rcItem.left,rcItem.bottom+1,0,0,SWP_NOSIZE|SWP_NOZORDER);
	ctr_Tab1.ShowWindow(/*iIndex?SW_HIDE:*/SW_SHOW);
//	ctr_Tab1.InsertItem(2,"Leistungen SGB V");
//	ctr_Tab1.InsertItem(3,"Einsätze SGB V");
//	ctr_Tab1.InsertItem(4,"Leistungen SGB XI");
//	ctr_Tab1.InsertItem(5,"Einsätze SGB XI");
}
Das TabCtr habe ich in der .h deklariert.
Code:
public:
	CTabCtrl ctr_Tab1;
Ich habe alles, was nicht unbedingt nötig ist, auskommentiert. Aber ich kann machen, was ich will, ich kriege nur das Item angezeigt, aber nie den dazugehörigen Dialog.
Wo liegt der Fehler?

langer
 

MCoder

Erfahrenes Mitglied
Den Dialog musst du ebenfalls als Member in der .h deklarieren. Ansonsten ist er am Ende von OnInitialUpdate() wieder weg.
 

Elayas

Grünschnabel
Hi, ich habe Deinen Lösungsvorschlag wie folgt umgesetzt:
C++:
// Header-Datei des Hauptdialogs
...
CDlg_Tab_Suche mDlg_Tab;      // Objekt auf den ersten Tab-Dialog
CTabCtrl mCtrl_Tab;           // Objekt auf CTabCtrl, ist Control-Var vom TabControl
unsigned int mUI_SelectedTab;

C++:
// CPP-Datei des Hauptdialogs

BOOL CHauptDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    ...

    // Initialisierung des TabControl
    // Dialog erzeugen
    mDlg_Tab.Create(CDlg_Tab_Suche::IDD, &this->mCtrl_Tab);

    CString strTitle = _T("Tab Überschrift");   // Titel des Dialogs
    int     iIndex   = 0;                        // Tab-Index

    // Dialog  als Tab hinzufügen
    CString strText = "Hallo Welt!";
    TCITEM item;
    item.mask    = TCIF_TEXT | TCIF_PARAM;
    item.lParam  = (LPARAM)&mDlg_Tab;
    item.pszText = (LPTSTR)(LPCTSTR)strText;
    mCtrl_Tab.InsertItem(iIndex, &item);

    // Dialog positionieren
    CRect rcItem;
    mCtrl_Tab.GetItemRect(0, &rcItem);

    mDlg_Tab.SetWindowPos(NULL, rcItem.left, rcItem.bottom + 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER );

    mDlg_Tab.ShowWindow(iIndex ? SW_HIDE : SW_SHOW);

    return TRUE;
}

Jedoch erscheint bei mir das TabControl nicht. Woran kann das liegen?

Danke!

Gruß,

Elayas
 

chefsalat-

Mitglied
Hallo,
ich versuche mich momentan auch an einem CTabCtrl.
Folgendes habe ich ausprobiert:
In der .h meines Dialoges, in dem das CTabCtrl erscheinen soll, habe ich die untergeordneten Dialoge ohne Rand erzeugt.
C++:
CmeinTab1Dlg mDlg_Tab1;
CmeinTab2Dlg mDlg_Tab2;

In der .cpp (OnInitDialog) des Dialoges, sieht es so aus
C++:
CTabCtrl* pTabCtrl = (CTabCtrl*)GetDlgItem(IDC_TAB_USERVERWALTUNG); //Zugriff auf das CTabCtrl

mDlg_Tab1.Create(IDD_DLG_MEIN_TAB1, pTabCtrl->GetParent());
mDlg_Tab2.Create(IDD_DLG_MEIN_TAB2, pTabCtrl->GetParent());

CString sUeberschrift = "Passwort ändern";
TCITEM item1;
item1.mask    = TCIF_TEXT | TCIF_PARAM;
item1.lParam  = (LPARAM)&mDlg_Tab1;
item1.pszText = (LPTSTR)(LPCTSTR)sUeberschrift;
pTabCtrl->InsertItem(0, &item1);

sUeberschrift = "Neuen User anlegen";
TCITEM item2;
item2.mask    = TCIF_TEXT | TCIF_PARAM;
item2.lParam  = (LPARAM)&mDlg_Tab2;
item2.pszText = (LPTSTR)(LPCTSTR)sUeberschrift;
pTabCtrl->InsertItem(1, &item2);

pTabCtrl->ShowWindow(SW_SHOW);

Normalerweise müsste das doch dann so funktionieren, dass wenigstens der untergeordnete Dialog für das erste Tab angezeigt wird, oder?

Beim Debuggen läuft es ohne Probleme durch, aber der untergeordnete Dialog wird im CTabCtrl nicht angezeigt.

Kann mir jemand weiterhelfen?

Gruß chefsalat-
 

chefsalat-

Mitglied
Ok, ich hab selber nochmal n bischen dran rumgespielt.
Warum funktioniert es immer erst dann, wenn man sich schon Mühe gemacht hat, sein Problem zu posten? :mad:

So sieht meine Lösung aus:
.h
C++:
CmeinTab1Dlg mDlg_Tab1;
CmeinTab2Dlg mDlg_Tab2;

.cpp
C++:
CTabCtrl* pTabCtrl = (CTabCtrl*)GetDlgItem(IDC_TAB_USERVERWALTUNG);

mDlg_Tab1.Create(IDD_DLG_MEIN_TAB1, pTabCtrl);
mDlg_Tab2.Create(IDD_DLG_MEIN_TAB2, pTabCtrl);

CString sUeberschrift = "Passwort ändern";
TCITEM item1;
item1.mask    = TCIF_TEXT | TCIF_PARAM;
item1.lParam  = (LPARAM)&mDlg_Tab1;
item1.pszText = (LPTSTR)(LPCTSTR)sUeberschrift;
pTabCtrl->InsertItem(0, &item1);

sUeberschrift = "Neuen User anlegen";
TCITEM item2;
item2.mask    = TCIF_TEXT | TCIF_PARAM;
item2.lParam  = (LPARAM)&mDlg_Tab2;
item2.pszText = (LPTSTR)(LPCTSTR)sUeberschrift;
pTabCtrl->InsertItem(1, &item2);

// Dialog positionieren
CRect rcItem;	
pTabCtrl->GetItemRect(0, &rcItem);
mDlg_Tab1.SetWindowPos(NULL, rcItem.left, rcItem.bottom + 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER );
 
int iCount = pTabCtrl->GetCurSel();
pTabCtrl->ShowWindow(iCount ? SW_HIDE : SW_SHOW);
mDlg_Tab1.ShowWindow(SW_SHOW);

Ist schon praktisch, wenn man den untergeordneten Dialog auch noch anzeigt und an die richtige Position setzt...

Gruß chefsalat-
 

bw1faeh0

Grünschnabel
Hallo!

auch wenn der Thread schon etwas älter ist, würde ich mich an dieser Stelle gerne einmal einklinken.
Ich möchte in meiner Anwendung auch gerne die erwähnten Tabs nutzen. Dazu habe ich den Code aus chefsalat's letztem Posting wie folgt übernommen:

Code:
BOOL CSourceDlg::OnInitDialog()
{
	/*
	...
	*/

	// TODO: Hier zusätzliche Initialisierung einfügen

	CTabCtrl* pTabCtrl = (CTabCtrl*)GetDlgItem(IDC_TAB);	


	CString sUeberschrift = "Register 1";
	TCITEM pTabCtrlItem_01;
	pTabCtrlItem_01.mask    = TCIF_TEXT | TCIF_PARAM;
	pTabCtrlItem_01.lParam  = (LPARAM)&m_register_01;
	pTabCtrlItem_01.pszText = (LPTSTR)(LPCTSTR)sUeberschrift;
	pTabCtrl->InsertItem(0, &pTabCtrlItem_01);

	sUeberschrift = "Register 2";
	TCITEM pTabCtrlItem_02;
	pTabCtrlItem_02.mask    = TCIF_TEXT | TCIF_PARAM;
	pTabCtrlItem_02.lParam  = (LPARAM)&m_register_02;
	pTabCtrlItem_02.pszText = (LPTSTR)(LPCTSTR)sUeberschrift;
	pTabCtrl->InsertItem(1, &pTabCtrlItem_02);

	// Dialog positionieren
	CRect rcItem;
	pTabCtrl->GetItemRect(0, &rcItem);
	m_register_01.SetWindowPos(NULL, rcItem.left, rcItem.bottom + 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER );

	pTabCtrl->SetCurSel(0);
	int iCount = mctl_Tab.GetCurSel();
	mctl_Tab.ShowWindow(iCount ? SW_HIDE : SW_SHOW);
	m_register_01.ShowWindow(SW_SHOW); 
}

m_register_01 und m_register_02 wurden wie folgt definiert:

Code:
	CRegister_01 m_register_01;
	CRegister_02 m_register_02;

Das Problem ist nun, dass das Programm beim Ausführen der Zeile
Code:
	pTabCtrl->GetItemRect(0, &rcItem);
gnadenlos abstürtzt.

Hat jemand spontan eine Idee, woran das liegen könnte?

mfg

Christian Flämig