Précédent   Forum du club des développeurs et IT Pro > C et C++ > Outils pour C & C++ > Visual C++ > MFC
MFC Vos questions sur les MFC
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 14/12/2012, 15h54   #1
rdb11
Invité de passage
 
Homme
Inscription : décembre 2012
Messages : 7
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : décembre 2012
Messages : 7
Points : 0
Points : 0
Par défaut MFC: création contenu onglet CTabCtrl dynamique

Bonjour,
J'ai pour but de développer une fenêtre contenant plusieurs onglets qui vont se remplir dynamiquement : Combobox, Label... (nombre d'onglet dynamique aussi).
Cette fenêtre a été crée avec l'outil graphique de Visual 6, mais le reste (CTabCtrl pour les onglets et tout ce qu'ils vont contenir) vont être créés par du code au chargement de la fenêtre.
Je viens de me faire un petit programme de test afin de construire cette fenêtre.
Pourriez vous m'aider pour spécifier à quel onglet va "appartenir" ma ComboBox ?

ma classe correspondant a ma fenêtre:
Code :
class CDlgFormDyn : public CDialog
Voici une partie de mon code de l’implémentation de cette classe
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
 
BOOL CDlgFormDyn::OnInitDialog() 
{
CDialog::OnInitDialog();
	m_tab_ongl	= new CTabCtrl();
	m_tab_ongl->Create(TCS_TABS,CRect(5,70,950,600),this,1);
	m_tab_ongl->ShowWindow(SW_SHOW);
 
	test() ;
	UpdateData(FALSE);
	return TRUE;
}
 
void CDlgFormDyn::test() 
{
CComboBox* cbBox;
CButton* cbt = new CButton();
CRect rect;
 
TC_ITEM TabItem;
TabItem.mask = TCIF_TEXT | TCIF_IMAGE;
TabItem.pszText = "onglet3";
 
// 2 facons de créer mes onglets
m_tab_ongl->InsertItem(0, "onglet1");
m_tab_ongl->InsertItem(1, "onglet2");
m_tab_ongl->InsertItem(2, &TabItem);
 
GetWindowRect(&rect);
rect.left	= POS_X_DEB;			//20
rect.right	= rect.left+TAILLE_X;		//20+80
rect.top	= POS_Y_DEB;			//90
rect.bottom = rect.top+TAILLE_Y;		//90+20	
 
 
	for(int i=0; i<20; i++) {
		cbBox = new CComboBox();
 
		if(!cbBox->Create(CBS_DROPDOWNLIST | WS_VISIBLE,rect2,m_tab_ongl,1))
			return;      // fail to create
		cbBox->AddString("ma combobox");
		cbBox->ShowWindow(SW_SHOW);
 
		rect2.left += 100;
		rect2.right = rect2.left+TAILLE_X;
		maj_rect(rect2);
	}
}
 
bool CDlgFormDyn::maj_rect(CRect& rect) 
{
	if(rect.left > SIZE_MAX_X) {
		rect.left	= POS_X_DEB;
		rect.right	= rect.left+TAILLE_X;
		rect.top	+= INCR_Y;
		rect.bottom = rect.top+TAILLE_Y;
		return true;
	}
	return false;
}
Je n'utilise pas de "view" car je dois intégrer ceci dans un module déjà existant n’ayant pas cette spécificité.

Quelqu'un a t il une idée ou a deja été confronté à ce problème ?
rdb11 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/12/2012, 19h04   #2
bacelar
Expert Confirmé Sénior
 
Homme Paul Bacelar
Développeur informatique
Inscription : février 2005
Messages : 2 651
Détails du profil
Informations personnelles :
Nom : Homme Paul Bacelar
Âge : 41
Localisation : France

Informations professionnelles :
Activité : Développeur informatique
Secteur : Conseil

Informations forums :
Inscription : février 2005
Messages : 2 651
Points : 4 044
Points : 4 044
Pourquoi utiliser directement un CTabCtrl plutôt qu'une CPropertySheet ?

Ci-dessous une référence VS2012 mais je suis quasi certain que cela existait déjà en VC++6.
http://msdn.microsoft.com/en-us/library/614xe086.aspx
bacelar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/12/2012, 09h16   #3
rdb11
Invité de passage
 
Homme
Inscription : décembre 2012
Messages : 7
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : décembre 2012
Messages : 7
Points : 0
Points : 0
Merci. Donc en gros, mon CTabCtrl devient CPropertySheet et mes différents onglets des CPropertyPage.
Au lieu d'utiliser des "AddItem", j'utilise des "AddPage".
Par contre j'ai un pointer null lors du create.

Code :
1
2
3
4
5
6
7
8
9
10
 
CPropertySheet*	m_tab_ongl	= new CPropertySheet();
 
CPropertyPage* page1 = new CPropertyPage("onglet1");
CPropertyPage* page2 = new CPropertyPage("onglet2");
 
m_tab_ongl->AddPage(page1);
m_tab_ongl->AddPage(page2);
 
m_tab_ongl->Create(this,WS_CHILD | WS_VISIBLE);
rdb11 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/12/2012, 15h23   #4
bacelar
Expert Confirmé Sénior
 
Homme Paul Bacelar
Développeur informatique
Inscription : février 2005
Messages : 2 651
Détails du profil
Informations personnelles :
Nom : Homme Paul Bacelar
Âge : 41
Localisation : France

Informations professionnelles :
Activité : Développeur informatique
Secteur : Conseil

Informations forums :
Inscription : février 2005
Messages : 2 651
Points : 4 044
Points : 4 044
Je pense qu'il faut fournir lID du template associé à chaque CPropertyPage avant de créer la PropertySheet.
L'assert doit d'indiquer, directement ou indirectement la chose à initialiser avant d'utiliser la méthode où l'assert t'engueule.
bacelar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/12/2012, 16h23   #5
rdb11
Invité de passage
 
Homme
Inscription : décembre 2012
Messages : 7
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : décembre 2012
Messages : 7
Points : 0
Points : 0
oui le null pointer exception vient bien de cette fonction:

Code :
1
2
3
4
5
void CPropertyPage::PreProcessPageTemplate(PROPSHEETPAGE& psp, BOOL bWizard)
{
	....
	ASSERT(pTemplate != NULL);
}
Par contre je ne vois pas comment initialiser ce "template" afin qu'il ne soit plus null lors de l'appel du create


Code :
1
2
3
4
5
6
 
CPropertyPage* page1 = new CPropertyPage();
page1->Create("onglet1",m_tab_ongl);
page2->Create("onglet2",m_tab_ongl);
m_tab_ongl->AddPage(page1);
m_tab_ongl->AddPage(page2);
En tentant cette approche mais des le 1er create sur ma CPropertyPage j'ai un assert(false)

Code :
1
2
3
4
5
6
7
8
9
10
11
 
BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd) {
...
if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE))
		ASSERT(FALSE);          // invalid dialog template name
}
 
BOOL AFXAPI _AfxCheckDialogTemplate(LPCTSTR lpszResource, BOOL bInvisibleChild) {
...
	HRSRC hResource = ::FindResource(hInst, lpszResource, RT_DIALOG);
}
hResource vaut NULL
rdb11 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/12/2012, 18h47   #6
bacelar
Expert Confirmé Sénior
 
Homme Paul Bacelar
Développeur informatique
Inscription : février 2005
Messages : 2 651
Détails du profil
Informations personnelles :
Nom : Homme Paul Bacelar
Âge : 41
Localisation : France

Informations professionnelles :
Activité : Développeur informatique
Secteur : Conseil

Informations forums :
Inscription : février 2005
Messages : 2 651
Points : 4 044
Points : 4 044
Une propertypage, c'est un peu comme une boite de dialogue, vous devez donner un template pour créer correctement les contrôles qu'elle doit contenir.
bacelar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/12/2012, 15h40   #7
rdb11
Invité de passage
 
Homme
Inscription : décembre 2012
Messages : 7
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : décembre 2012
Messages : 7
Points : 0
Points : 0
Je comprends tout a fait ce principe par contre je ne vois pas à quel moment doit ton lui fournir ce template. Comme je fais une construction dynamique, comment dois je lui de dire quel est son template ?
rdb11 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2012, 14h17   #8
bacelar
Expert Confirmé Sénior
 
Homme Paul Bacelar
Développeur informatique
Inscription : février 2005
Messages : 2 651
Détails du profil
Informations personnelles :
Nom : Homme Paul Bacelar
Âge : 41
Localisation : France

Informations professionnelles :
Activité : Développeur informatique
Secteur : Conseil

Informations forums :
Inscription : février 2005
Messages : 2 651
Points : 4 044
Points : 4 044
C'est le genre de question que je règle en lisant les sources des MFC puis en regardant la documentation pour vérifier que les moyens détectés dans les sources sont "documentés".
Mais je n'ai pas vos MFC.

Donc, en gros, le flag "PSP_DLGINDIRECT" devrait être un bon axe de recherche.

http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx
bacelar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2012, 15h27   #9
rdb11
Invité de passage
 
Homme
Inscription : décembre 2012
Messages : 7
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : décembre 2012
Messages : 7
Points : 0
Points : 0
Merci pour tes conseils.
Dans mon projet, j'utilise une CDialog que j'ai crée de facon "graphique" via Visual6.
Voici sa definition dans le fichier .rc du projet associé

Code :
1
2
3
4
5
6
7
8
9
10
IDD_FORM_DYN DIALOG DISCARDABLE  0, 0, 639, 373
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Sans Serif"
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,582,7,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,582,24,50,14
    LTEXT           "Nom:",IDC_BANDEAU_FORM,7,26,566,8
    CTEXT           "Static",IDC_TIT_FDYN,7,9,568,8
END
Dans mon .h
Ensuite j'ai une classe qui herite de CDialog qui correspond à la fenetre qui va contenir par la suite mon CPropertySheet

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class CDlgFormDyn : public CDialog
{
// Construction
public:
	CDlgFormDyn(CWnd* pParent = NULL);
	~CDlgFormDyn();
 
// Dialog Data
	//{{AFX_DATA(CDlgFormDyn)
	enum { IDD = IDD_FORM_DYN };
	CString			m_stit;
	//}}AFX_DATA
 
	...
	CPropertySheet	*m_tab_ongl;
	...
 
// Generated message map functions
protected:
	//{{AFX_MSG(CDlgFormDyn)
	virtual BOOL OnInitDialog();
	virtual void DoDataExchange(CDataExchange* pDX);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};
Dans mon .cpp:
j'implemente cette classe

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CDlgFormDyn::CDlgFormDyn(CWnd* pParent /*=NULL*/)
	: CDialog(CDlgFormDyn::IDD, pParent)
{
	//{{AFX_DATA_INIT(CDlgFormDyn)
	//}}AFX_DATA_INIT
	m_tab_ongl	= new CPropertySheet();
}		
 
 
BOOL CDlgFormDyn::OnInitDialog() 
{
	CDialog::OnInitDialog();
	test() ;
	UpdateData(FALSE);
 
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}
J'aurais une question subsidiaire:
faut il que je crée une classe héritant de CPropertyPage dont l'interface graphique sera vide et complétée dynamiquement par la suite ? Ou seulement un objet CPropertyPage crée a la volé sur lequel ensuite j'ajoute mes différents CStaic, Combobox... suffit ?
rdb11 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2012, 19h28   #10
bacelar
Expert Confirmé Sénior
 
Homme Paul Bacelar
Développeur informatique
Inscription : février 2005
Messages : 2 651
Détails du profil
Informations personnelles :
Nom : Homme Paul Bacelar
Âge : 41
Localisation : France

Informations professionnelles :
Activité : Développeur informatique
Secteur : Conseil

Informations forums :
Inscription : février 2005
Messages : 2 651
Points : 4 044
Points : 4 044
Citation:
faut il que je crée une classe héritant de CPropertyPage dont l'interface graphique sera vide et complétée dynamiquement par la suite ? Ou seulement un objet CPropertyPage crée a la volé sur lequel ensuite j'ajoute mes différents CStaic, Combobox... suffit ?
La première approche, bien que plus "lourde" a plus de potentiel car elle aura accès la "l'interface" protected de la classe CPropertySheet, la second ne peut utiliser que ce qui est public de cette classe.
bacelar est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 10h47.


 
 
 
 
Partenaires

Hébergement Web