demande de précisions sur DDX/DDV [MFC] - C++ - Programmation
Marsh Posté le 26-06-2005 à 11:27:18
tu n'as pas à appeler toi même DoDataExchange().
tu veux faire quoi exactement ?
Marsh Posté le 26-06-2005 à 14:26:37
Je vais préciser (cas concret vécu au taf)
J'ai un dialogue (modal) contenant plusieurs champs de saisie.
J'utilise le mécanisme DDX pour l'échange attributs/contrôle de saisie. J'implémente donc DoDataExchange() de la façon adhoc.
A la modification d'un contrôle (donc dans le gestionnaire d'événement, par ex EN_KILLFOCUS), je souhaite contrôler puis récupérer la valeur de ce contrôle et uniquement de celui-là. Je ne peux donc pas appeler UpdateData(TRUE) sinon les autres contrôles sont testés/échangés.
Marsh Posté le 27-06-2005 à 09:36:19
He bien personne peut répondre. Harkonnen t'avait l'air sur la bonne voie...
Marsh Posté le 27-06-2005 à 12:16:31
y'a un truc que je comprends pas... par le DDX, ton controle est mappé à un objet normalement non ? (CString dans ton cas). pourquoi ne pas utiliser ses méthodes ?
Marsh Posté le 27-06-2005 à 13:40:25
Parce qu'il faut passer un CDataExchange en paramètre mais si c'est la seule solution je vais le construire ce CDataExchange
Edit: après relecture je sais pas si ton "ses méthodes" s'applique à DDX_xxx ou à CString?
Marsh Posté le 27-06-2005 à 14:41:48
comprends rien... tu me dis si je me trompe :
- tu as une form contenant plusieurs champs de saisie (des TextBox je suppose ?)
- au KILLFOCUS d'un textbox, tu veux récupérer la valeur de ce textbox.
donc, ta fonction DoDataExchange doit ressembler à ceci (ID_TBOX est l'ID de ton textbox)
Code :
|
la variable m_TextBox est une variable membre de type CString, qui contient donc le contenu de ton TextBox. tu sais surement que pour mettre à jour le contenu de la variable avec celui du TextBox, tu dois appeler UpdateData(TRUE), et que pour mettre le TextBox à jour avec la valeur de la variable, tu appelles UpdateData(FALSE)
donc, à partir de là, tout ce que tu as à faire dans le handler rattaché à EN_KILLFOCUS est ceci :
Code :
|
Marsh Posté le 27-06-2005 à 18:52:06
C'est tout à fait exact. Bon maintenant j'expose le problème:
Je n'ai pas qu'un seul TextBox dans ma form (connaissait pas ce nom là mais ok).
Ma DoDataExchange c'est plutôt ce genre là:
Code :
|
DONC si j'appelle UpdateData(TRUE), je valide TOUS les champs.
MAIS je veux uniquement valider un des TextBox.
Marsh Posté le 28-06-2005 à 12:49:56
Ben alors dans ce cas, t'as qu'une chose à faire : subclasser le controle "à la main" dés que tu veux le valider, avec la fonction SubclassDlgItem()
Plus d'infos, avec exemple ici :
http://msdn.microsoft.com/library/ [...] lgitem.asp
Marsh Posté le 28-06-2005 à 13:43:31
Tu pourrais par exemple créer une variable de type m_nLastModifiedID que tu mets à jours sur EN_KILLFOCUS et ensuite tu appelles une fonction du genre
Code :
|
Marsh Posté le 28-06-2005 à 13:56:13
Ouais j'y avais pensé en utilisant m_nLastModifiedID de cette façon:
Si m_nLastModifiedID == -1 alors je traite tous les champs sinon m_nLastModifiedID est l'ID du champ à traiter.
Ma question portait plutôt sur l'existence ou non d'un méthode miracle. J'ai regardé du côté de CWnd::UpdateData mais j'ai estimé ne pas pouvoir en faire grand chose (à moins de créer un contrôle à la main bien sûr)
Pour le SubclassDlgItem, je connais j'ai déja utilisé mais je ne comprend pas l'utilisation que tu veux en faire Harkonnen. Explique moi STP.
Marsh Posté le 28-06-2005 à 16:52:50
Pourquoi tu n'utilises pas GetDlgItem() pour récupérer directement le control et getWindowText pour avoir la valeur ?
CString resultat;
((CEdit*)GetDlgItem(ID_MONTEXTBOX))->GetWindowText(resultat);
Marsh Posté le 28-06-2005 à 18:23:57
slash33 a écrit : |
Quand tu appelles UpdateData(), SubclassDlgItem() est appelée afin de remplacer la procédure WndProc du controle (ici le TextBox) par celle que tu as défini dans le DDX_CONTROL.
Donc ce que tu peux faire, c'est virer le DDX_CONTROL du TextBox de la fonction DoDataExchange(), afin que tout appel à UpdateData soit sans effet sur ce TextBox.
Ensuite, tu créé une classe CMyEdit, qui hérite de la classe CEdit (qui est la classe MFC qui encapsule le controle TextBox), et dans laquelle tu créé le handler qui intercepte EN_KILLFOCUS.
Enfin, dans la fonction OnInitDialog() de la fenêtre contenant tes TextBox, tu sous classes le TextBox que tu souhaites :
dans le .h de ta Dialog :
Code :
|
dans la fonction OnInitDialog de ton .cpp :
Code :
|
Ainsi, l'interception de EN_KILLFOCUS se fera dans l'objet m_textbox, et pas dans la classe de dialog principale.
Marsh Posté le 28-06-2005 à 18:58:26
ChristianS_ a écrit : Pourquoi tu n'utilises pas GetDlgItem() pour récupérer directement le control et getWindowText pour avoir la valeur ? |
1. Je ne me contente pas de CString et des DDX_Text, c'était juste un exemple. Dans le problème qui me préoccupe c'est en fait un DDX_CBIndex...
Au passage, tu sais qu'il existe GetDlgItemText()?
2. les validation DDX/DDV tu les fais comment??
Harkonnen:
Je comprends ce que tu proposes mais je ne vois pas où tu appelles les DDX_ et DDV_? Dans le gestionnaire EN_KILLFOCUS de la classe spécialisée CMyText?
Mon intérêt étant d'employer les méthodes DDX_ et DDV_ pas de tout refaire à la main.
Enfin c'est pas grave, je vais probablement opter pour la solution de XtremDev qui n'est pas trop contraignante. Il y a même peut être moyen de spécialiser CDataExchange pour mon besoin.
Marsh Posté le 28-06-2005 à 20:04:13
slash33 a écrit : |
mais vu que tu subclasses, t'as plus besoin de DDX !
si tu vires le DDX_CONTROL du TextBox de la classe principale, UpdateData() n'aura plus aucun effet sur lui.
donc, au KILLFOCUS, c'est le gestionnaire de la classe spécialisée qui sera appelé, et uniquement celui ci. les autres textbox ne seront pas concernés si tu ne leur codes pas de gestionnaire dans la classe principale.
c'est ce que tu veux, non ?
Marsh Posté le 29-06-2005 à 10:11:25
On va prendre un exemple concret:
Code :
|
Dans l'exemple, il faut pouvoir extraire et valider la valeur de IDC_INTEGER de façon isolée.
Conformément à ta proposition, je retire les lignes 30 à 32 de DoDataExchange et je crée une spécialisation de CEdit.
Le code de CMyDialog
Code :
|
La classe CMyEdit
Code :
|
Marsh Posté le 30-06-2005 à 15:04:20
mouais... effectivement, le subclassing n'est pas adapté ici
je ne vois guère que la soluce de XTremDev, GetDlgItemText(). tes validations DDX/DDV n'ont pas l'air trop chiantes à faire apparemment, ça devrait pas être bien méchant
Marsh Posté le 30-06-2005 à 16:07:20
L'exemple est resté volontairement simple mais il m'arrive de coder des méthodes DDX (un peu) ou DDV (plus souvent) perso.
Un exemple classique de DDX perso c'est les DDX_Text mais pour des champs optionnels (le champ peut n'avoir aucune valeur). Ca paraît simple comme ça mais dans les faîts ça pose pas mal de problèmes: représentation de indéfini pour tous les types de bases, gestion des -INF et +INF, etc.
Merci quand même pour tes réponses. Je trouve effectivement que la solution de XTremDev (celle avec l'indicateur du champ à traiter) est de loin la plus efficace pour régler ma problématique.
Cela soulève les problèmes que l'on rencontre quand on s'écarte de l'architecture MFC. C'est un peu comme avec le mécanisme document/vue: c'est très bien quand tu respectes à la lettre l'architecture, par contre quand tu fais quelque chose hors norme ça devient un peu la galère...
Marsh Posté le 25-06-2005 à 18:38:10
Comment appeler le code de validation/échange de données spécifique à un seul contrôle de dialogue sachant que j'ai plusieurs DDX_xxx déclarés dans dans DoDataExchange()?