IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MFC Discussion :

Comment mettre un CString dans le champ lParam d'une CListCtrl


Sujet :

MFC

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 90
    Points : 54
    Points
    54
    Par défaut Comment mettre un CString dans le champ lParam d'une CListCtrl
    Bonjour,

    J'ai créé une CListCtrl et je souhaiterai que lorsque nous selectionnons une ligne dans cette CListCtrl puis que nous cliquons sur un bouton, un paramètre de type CString soit récupéré afin de poursuivre le traitement.

    Pour cela, j'utilise la méthode SetItemData, cependant je ne trouve pas comment passer un paramètre de type CString par le biais de cette méthode...

    J'aurais donc besoin d'un ptit coup de main pour trouver comment faire

    Merci d'avance!

  2. #2
    Membre éclairé
    Avatar de PetitPapaNoël
    Développeur informatique
    Inscrit en
    Septembre 2006
    Messages
    559
    Détails du profil
    Informations personnelles :
    Âge : 48

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 559
    Points : 749
    Points
    749
    Par défaut
    Bonjour,

    A mon avis, il n'est pas possible de passer directement un CString à la méthode SetItemData. Par contre, il est possible de lui passer l'adresse d'une variable de type CString, sous forme de pointeur.
    La méthode est évoquée dans la FAQ.

    Une autre méthode, moins élégante mais tout aussi efficace, consisterait à ajouter une colonne de largeur nulle (donc invisible pour l'utilisateur) dans laquelle seraient stockées les données (celles que tu cherches à stocker avec la méthode SetItemData). Celles ci seraient ensuite facilement accessibles via la méthode GetItemText.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 90
    Points : 54
    Points
    54
    Par défaut
    Pas bête la méthode du champ caché, c'est la méthode qui me semble le plus facil pour moi mais j'aimerai faire quelquechose de plus propre en utilisant le SetItemData.

    Par contre, n'étant pas trop à l'aise avec les pointeurs et adresses, je n'arrive pas à utiliser le bon code pour récupérer mon paramètre...

    mon code pour "setter" ma valeur et la "getter" ensuite est le suivant:

    Valorisation du paramètre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_ListForm.SetItemData(lvItem.iItem,(long)(LPCTSTR) typeFormulaire->_code);
    Récupération du paramètre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    CString newTypeForm;
    newTypeForm = (CString) (m_ListForm.GetItemData((int)m_ListForm.GetFirstSelectedItemPosition()-1));

  4. #4
    Membre éclairé
    Avatar de PetitPapaNoël
    Développeur informatique
    Inscrit en
    Septembre 2006
    Messages
    559
    Détails du profil
    Informations personnelles :
    Âge : 48

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 559
    Points : 749
    Points
    749
    Par défaut
    Pour bien faire, et pour éviter les fuites mémoire, il faut gérer tes pointeurs comme des membres protégés de ta fenêtre. Étant donné que tu travailles sur une grille, je suppose que le mieux serait de faire une liste de pointeurs sur des CString :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    CArray<CString*, CString*> m_pListe;
    Mais la simplicité voudrait plutôt que tu gères directement tes données dans un CStringArray tout simple, plutôt que te t'embêter avec des pointeurs et SetItemData...
    Si tu travaillais directement sur des pointeurs et que tu n'avais pas besoin de les créer, ce serait différent. Par exemple, si typeFormulaire était un pointeur sur un objet plutôt qu'une variable, tu pourrais carrément faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    m_ListForm.SetItemData(lvItem.iItem, reinterpret_cast<DWORD_PTR> (typeFormulaire));
    Ensuite, au moment de récupérer tes données, tu ferais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    CTypeFormulaire *pTypeFormulaire = reinterpret_cast<CTypeFormulaire*> (m_ListForm.GetItemData(position));

  5. #5
    Membre éclairé
    Avatar de PetitPapaNoël
    Développeur informatique
    Inscrit en
    Septembre 2006
    Messages
    559
    Détails du profil
    Informations personnelles :
    Âge : 48

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 559
    Points : 749
    Points
    749
    Par défaut
    Sinon, si tu veux quand même travailler avec SetItemData et des pointeurs, il y a une autre solution...
    Valorisation du paramètre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    CString *pCode = reinterpret_cast<CString*> (m_ListForm.GetItemData(lvItem.iItem));
     
    if (pCode)
    	delete pCode;
     
    pCode = new CString(typeFormulaire->_code);
     
    m_ListForm.SetItemData(lvItem.iItem, reinterpret_cast<DWORD_PTR> (pCode));
    Récupération du paramètre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    CString *pNewTypeForm = reinterpret_cast<CString*> (m_ListForm.GetItemData(position));
    Dans ce cas, il ne faut pas oublier de libérer la mémoire des pointeurs sur les CString au moment de la destruction de la fenêtre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    for (int i = 0 ; i < m_ListForm.GetItemCount() ; i++)
    {
    	CString *pCode = reinterpret_cast<CString*> (m_ListForm.GetItemData(i));
     
    	if (pCode)
    		delete pCode;
    }

  6. #6
    Membre éclairé
    Avatar de PetitPapaNoël
    Développeur informatique
    Inscrit en
    Septembre 2006
    Messages
    559
    Détails du profil
    Informations personnelles :
    Âge : 48

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 559
    Points : 749
    Points
    749
    Par défaut
    En ce qui me concerne, soit je travaille avec des pointeurs et dans ce cas j'utilise SetItemData, soit je gère une liste en parallèle dans une variable membre protégée de la classe associée à la fenêtre.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 90
    Points : 54
    Points
    54
    Par défaut
    J'ai essayé ta solution pour le SetItemData et les pointeurs.

    A quoi sert exactement le reinterpret_cast?

    J'ai aussi essayé de compiler mais j'ai rencontré un problème avec DWORD_PTR donc j'ai retenté la compilation en remplacant DWORD_PTR par DWORD et ca a marché.

    J'ai ensuite testé l'écran, et la j'ai eu un "debug assertion failed" à la ligne suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CString *pCode = reinterpret_cast<CString*> (m_ListForm.GetItemData(lvItem.iItem));
    Cette ligne est elle vraiment nécessaire? Car le nettoyage est censé se faire à la fermeture de la fenêtre, non?

  8. #8
    Membre éclairé
    Avatar de PetitPapaNoël
    Développeur informatique
    Inscrit en
    Septembre 2006
    Messages
    559
    Détails du profil
    Informations personnelles :
    Âge : 48

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 559
    Points : 749
    Points
    749
    Par défaut
    Le reinterpret_cast sert à faire un cast entre deux objets qui n'ont, en apparence, aucun rapport. Cf. une petite explication récente...

    C'est bizarre ton erreur avec DWORD_PTR. Il me semblait pourtant que CListCtrl::SetItemData fonctionnait avec des DWORD_PTR...

    Quant à ton assertion, je ne la comprends pas non plus. Elle se produit à quel moment exactement ?
    C'est à toi de faire le nettoyage des pointeurs car si tu mets des pointeurs dans ton CListCtrl avec SetItemData, ils ne sont pas supprimés lors de la destruction du contrôle. Et heureusement, d'ailleurs, sinon l'intérêt de cette façon de faire serait moindre.

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 90
    Points : 54
    Points
    54
    Par défaut
    Mon assertion se produit lors de l'appel de GetItemData comme je te l'ai précisé. Apparemment, ca se passe à la ligne suivante de la methode GetItemData de la CListCtrl:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    VERIFY(::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)&lvi));
    Merci pour ton aide

  10. #10
    Membre éclairé
    Avatar de PetitPapaNoël
    Développeur informatique
    Inscrit en
    Septembre 2006
    Messages
    559
    Détails du profil
    Informations personnelles :
    Âge : 48

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 559
    Points : 749
    Points
    749
    Par défaut
    Peux-tu préciser tout ton code ?

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 90
    Points : 54
    Points
    54
    Par défaut
    Voici le code de la méthode OnInitDialog où j'initialise ma CListCtrl:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    BOOL CreerFormulaireEcran::OnInitDialog() 
    {
    	CDialog::OnInitDialog();
    	long cptI=0;
    	LV_ITEM lvItem;
    	LV_COLUMN lvc;
    	CRect tailleList;
    	long width = 0;
    	long taille;
    	CString formLibelle;
    	CNodeTypeFormulaire * typeFormulaire;
    	try
    	{
    		if ( _sireneDoc == 0 )
    			return FALSE;
    		if ( ! _sireneDoc->DisableAction(true) )
    			return FALSE;
     
     
    		m_ListForm.SetExtendedStyle(LVS_EX_FULLROWSELECT);
     
    		//on récupère la liste des formulaires
    		taille = _sireneDoc->_tabTypeFormulaire.lGetLastPos();
    		if ( taille <= 0 )
    		{
    			_sireneDoc->Get_ReferentielConsulter(CODE_REFERENTIEL_TYPE_FORMULAIRE);
    			taille = _sireneDoc->_tabTypeFormulaire.lGetLastPos();
    		}
     
    		//on parcourt une première fois la liste des libellés pour récupérer la plus grand largeur
    		for ( cptI = 0 ; cptI < taille ; cptI++ )
    		{
    			typeFormulaire = (CNodeTypeFormulaire *)_sireneDoc->_tabTypeFormulaire[cptI];
    			if (typeFormulaire->_libelle.GetLength() > width)
    				width = typeFormulaire->_libelle.GetLength();
    		}
     
    		lvc.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH | LVIF_PARAM;
    		lvc.iSubItem = 0;
    		lvc.pszText = _T("Type de formulaire:");
    		lvc.cx = 7 * width; //la longueur du texte multiplié par la moyenne en pixel d'un caractère...
    		m_ListForm.InsertColumn(0,&lvc);
    		lvItem.mask = LVIF_TEXT;
     
    		//on initialise la liste des formulaires
    		for ( cptI = 0 ; cptI < taille ; cptI++ )
    		{
    			typeFormulaire = (CNodeTypeFormulaire *)_sireneDoc->_tabTypeFormulaire[cptI];
    			lvItem.iItem = cptI;
    			lvItem.iSubItem = 0;
    			lvItem.pszText = (char*)(LPCTSTR) typeFormulaire->_libelle;
     
    			CString * pCode = reinterpret_cast<CString*> (m_ListForm.GetItemData(lvItem.iItem));
    			if (pCode)
    				delete pCode;
    			pCode = new CString(typeFormulaire->_code);
    			m_ListForm.SetItemData(lvItem.iItem, reinterpret_cast<DWORD> (pCode));
     
    			lvItem.iItem = m_ListForm.InsertItem(&lvItem);
    		}
    		UpdateData(FALSE);
    		m_ListForm.SetRedraw(TRUE);
    	}
    	catch(...)
    	{
    		_sireneDoc->DisableAction(false);
    		return FALSE;
    	}
    	_sireneDoc->DisableAction(false);
    	              // EXCEPTION: OCX Property Pages should return FALSE
    	return TRUE;  // return TRUE unless you set the focus to a control
    }
    Et voici le code de la méthode OnOK où je dois récupérer la valeur pour la passer en paramètre à une méthode:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    void CreerFormulaireEcran::OnOK() 
    {
    	CString * pNewTypeForm;
    	try
    	{
    		if ( ! DisableAction(true) )
    			return;
    		if ( m_ListForm.GetSelectedCount() <= 0 )
    			MessageBox(MSG_BOX_INFO_CREER_FORMULAIRE);
    		else
    		{
    			//newTypeForm = m_ListForm.GetItemText((long)m_ListForm.GetFirstSelectedItemPosition()-1,0);
    			pNewTypeForm = reinterpret_cast<CString*> (m_ListForm.GetItemData((int)m_ListForm.GetFirstSelectedItemPosition()-1));
    		//	_sireneDoc->OpenNewFormulaire(newTypeForm);
    			EndDialog(IDOK);
    		}
    	}
    	catch(...)
    	{
    	}
    	DisableAction(false);
    }

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 90
    Points : 54
    Points
    54
    Par défaut
    Je viens de tester en commentant les lignes de code suivante dans la méthode OnInitDialog:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    CString * pCode; // = reinterpret_cast<CString*> (m_ListForm.GetItemData(lvItem.iItem));
    			//if (pCode)
    				//delete pCode;
    Suite à cela, je n'ai plus d'erreur.

    Par contre j'ai mis un point d'arrêt lors de la récupération du paramètre et ce dernier est vide.

  13. #13
    Membre éclairé
    Avatar de PetitPapaNoël
    Développeur informatique
    Inscrit en
    Septembre 2006
    Messages
    559
    Détails du profil
    Informations personnelles :
    Âge : 48

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 559
    Points : 749
    Points
    749
    Par défaut
    Il y a quelques chose qui ne va pas : dans ton OnInitDialog, tu crées les nouvelles lignes de ta CListCtrl après avoir mis à jour les données que tu veux leur associer. Il faut d'abord créer la ligne et ensuite faire le SetItemData. De plus, le test sur la donnée associée est inutile dans ce cas, puisque venant de créer la ligne, tu n'as pas de donnée associée...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    BOOL CreerFormulaireEcran::OnInitDialog() 
    {
    	...
     
    			lvItem.iItem = m_ListForm.InsertItem(&lvItem);
     
    //			CString * pCode = reinterpret_cast<CString*> (m_ListForm.GetItemData(lvItem.iItem));
    //			if (pCode)
    //				delete pCode;
    //			pCode = new CString(typeFormulaire->_code);
    			m_ListForm.SetItemData(lvItem.iItem, reinterpret_cast<DWORD_PTR> (new CString(typeFormulaire->_code)));
    		}
    		UpdateData(FALSE);
    		m_ListForm.SetRedraw(TRUE);
    	}
    	catch(...)
    	{
    		_sireneDoc->DisableAction(false);
    		return FALSE;
    	}
    	_sireneDoc->DisableAction(false);
    	              // EXCEPTION: OCX Property Pages should return FALSE
    	return TRUE;  // return TRUE unless you set the focus to a control
    }

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 90
    Points : 54
    Points
    54
    Par défaut
    Ah mon code fonctionne enfin

    Merci beaucoup PetitPapaNoël pour ton aide

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 12
    Dernier message: 12/05/2014, 10h31
  2. Réponses: 2
    Dernier message: 23/05/2012, 23h23
  3. Réponses: 13
    Dernier message: 03/10/2007, 11h25
  4. Réponses: 13
    Dernier message: 26/08/2005, 16h34
  5. Comment insérer un espace dans un champ
    Par davyd dans le forum Langage SQL
    Réponses: 4
    Dernier message: 22/03/2005, 10h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo