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



Comment mettre à jour les contrôles depuis leurs variables et vice-versa ?
auteur : Farscape

CWnd::UpdateData
BOOL UpdateData( BOOL bSaveAndValidate = TRUE );
Cette fonction comme son nom l'indique permet :

  • La mise à jour des variables attachées aux contrôles lorsque bSaveAndValidate est égal à TRUE ;
  • La mise à jour des contrôles depuis les variables lorsque bSaveAndValidate est égal à FALSE.
Jusque là rien d'extraordinaire.
Il faut quand même savoir que ce mécanisme de mise à jour dans les deux sens est assujetti à une fonction essentielle dans la classe fenêtre où sont situés les contrôles :

CWnd::DoDataExchange  
virtual void DoDataExchange( CDataExchange* pDX );
Cette fonction virtuelle sera générée automatiquement par ClassWizard lors de la génération d'une classe Fenêtre. Le code de conversion approprié sera placé automatiquement en fonction des types de variables que l'utilisateur aura sélectionnées. Les fichiers include et source étant bien sûr mis à jour automatiquement.
Exemple de DoDataExchange

void CBnqView::DoDataExchange(CDataExchange* pDX)
{
    CMyFormView::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CBnqView)
    DDX_Control(pDX, IDC_CEDITCDEBNQ, m_EditCdeBnq);
    DDX_Control(pDX, IDC_CEDITCDEGUICHET, m_EditCdeGuichet);
    DDX_Control(pDX, IDC_CEDITDOM, m_EditDom);
   //???????????????????.
   //}}AFX_DATA_MAP
}
Il existe d'autres formes d'échanges :contrôle vers entiers,string .
DoDataExchange sera appelée chaque fois que UpdateData sera invoquée,
L'échange des données se fera par la fonction DDX_xxxx qui établira le lien entre le numéro d'identité du contrôle (IDC_) et sa variable.
Dans le cas de la fonction DDX_Control d'autres mécanismes sont mis en jeu.

// header afxdd_.h
// for getting access to the actual controls
void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl);
Au premier UpdateData le contrôle est « subclassé » ,c'est-à-dire qu'on va intercepter les messages Windows à destination du contrôle (tous les processus par défaut de Windows) pour lui donner un autre « moteur » de gestion des messages ,celui de l'objet mentionné dans la fonction DDX_Control .
Ce travail est fait par la fonction CWnd ::SubclassWindow(HWND hWnd) qui fait appel elle-même à

LONG SetWindowLong( 
HWND hWnd, 
int nIndex, 
LONG dwNewLong); 
C'est à la fin de ce traitement dont je viens de résumer les grandes lignes que la donnée membre m_hWnd de la variable contrôle sera affectée.
Autre point un UpdateData est fait à votre « insu » dans la fonction CDialog ::OnInitDialog

BOOL CDialog::OnInitDialog()
{
    //-??????????????????????..Extrait
    // transfer data into the dialog from member variables
    if (!UpdateData(FALSE))
   {
       TRACE0("Warning: UpdateData failed during dialog init.\n");
       EndDialog(-1);
       return FALSE;
   }
   //-??????????????????????..Extrait
}
Les conséquences de ce qui vient d'être dit sont nombreuses :

  • Toute variable contrôle déclarée dans une fenêtre dialogue (CDialog ou CFormView etc ..) qui ne fera pas partie de la fonction DoDataExchange ne sera pas « subclassée » son handle de fenêtre sera égal à NULL et son utilisation provoquera une assertion.
  • Toute variable contrôle non présente dans la fonction DoDataExchange ne sera pas affectée par l'action de UpdateData.
  • Pour subclasser un contrôle manuellement on pourra utiliser la fonction SubClassDlgItem :

BOOL CAboutDlg::OnInitDialog() 
{
   CDialog::OnInitDialog();
   // IDC_BUTTON1 is the ID for a button on the 
   // dialog template used for CAboutDlg.
   m_myButton.SubclassDlgItem(IDC_BUTTON1, this);   
//?????????????
Pour placer dans la fonction DoDataExchange une variable dynamique utiliser la technique suivante :

void CBnqView::DoDataExchange(CDataExchange* pDX)
{
    CMyFormView::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CBnqView)
    DDX_Control(pDX, IDC_CEDITCDEBNQ, m_EditCdeBnq);
    // m_pEditDynamique mis à null dans le constructeur et initialiser dans OnInitialUpdate.
    if(m_pEditDynamique)
    {
        DDX_Control(pDX, IDC_CEDITDYN, *m_pEditDynamique);
    }
    DDX_Control(pDX, IDC_CEDITCDEGUICHET, m_EditCdeGuichet);
    DDX_Control(pDX, IDC_CEDITDOM, m_EditDom);
   //???????????????????.
   //}}AFX_DATA_MAP
}
L'appel à la fonction DDX_Control se fera uniquement si le pointeur est différent de NULL.
Une cause de plantage classique :le contrôle est enlevé dans la ressource et on oublie de supprimer la variable par ClassWizard au premier UpdateData on aura une belle assertion d'erreur dans le source DLGDATA.CPP.
Pour clôturer la question, il existe dans la documentation MSDN une note d'information intéressante sur tous les problèmes d'assertions avec les macros DDX_ :

INFO: Foundation Classes Common Asserts, Causes, and Solutions
Q117326


Consultez les autres F.A.Q.


Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2004 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.