Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 10 sur 10
  1. #1
    Invité de passage
    Homme Profil pro
    Inscrit en
    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 ?

  2. #2
    Expert Confirmé Sénior
    Homme Profil pro Paul Bacelar
    Développeur informatique
    Inscrit en
    février 2005
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Nom : Homme Paul Bacelar
    Âge : 42
    Localisation : France

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

    Informations forums :
    Inscription : février 2005
    Messages : 2 938
    Points : 4 574
    Points
    4 574

    Par défaut

    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

  3. #3
    Invité de passage
    Homme Profil pro
    Inscrit en
    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

    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);

  4. #4
    Expert Confirmé Sénior
    Homme Profil pro Paul Bacelar
    Développeur informatique
    Inscrit en
    février 2005
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Nom : Homme Paul Bacelar
    Âge : 42
    Localisation : France

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

    Informations forums :
    Inscription : février 2005
    Messages : 2 938
    Points : 4 574
    Points
    4 574

    Par défaut

    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.

  5. #5
    Invité de passage
    Homme Profil pro
    Inscrit en
    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

    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

  6. #6
    Expert Confirmé Sénior
    Homme Profil pro Paul Bacelar
    Développeur informatique
    Inscrit en
    février 2005
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Nom : Homme Paul Bacelar
    Âge : 42
    Localisation : France

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

    Informations forums :
    Inscription : février 2005
    Messages : 2 938
    Points : 4 574
    Points
    4 574

    Par défaut

    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.

  7. #7
    Invité de passage
    Homme Profil pro
    Inscrit en
    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

    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 ?

  8. #8
    Expert Confirmé Sénior
    Homme Profil pro Paul Bacelar
    Développeur informatique
    Inscrit en
    février 2005
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Nom : Homme Paul Bacelar
    Âge : 42
    Localisation : France

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

    Informations forums :
    Inscription : février 2005
    Messages : 2 938
    Points : 4 574
    Points
    4 574

    Par défaut

    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

  9. #9
    Invité de passage
    Homme Profil pro
    Inscrit en
    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

    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 ?

  10. #10
    Expert Confirmé Sénior
    Homme Profil pro Paul Bacelar
    Développeur informatique
    Inscrit en
    février 2005
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Nom : Homme Paul Bacelar
    Âge : 42
    Localisation : France

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

    Informations forums :
    Inscription : février 2005
    Messages : 2 938
    Points : 4 574
    Points
    4 574

    Par défaut

    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.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •