Contrôles de sous-classification

Si un contrôle effectue presque tout ce que vous voulez, mais que vous avez besoin de quelques fonctionnalités supplémentaires, vous pouvez modifier ou ajouter des fonctionnalités au contrôle d’origine en le sous-classant. Une sous-classe peut avoir toutes les fonctionnalités d’une classe existante, ainsi que toutes les fonctionnalités supplémentaires que vous souhaitez lui donner.

Ce document décrit la façon dont les sous-classes sont créées et inclut les rubriques suivantes.

Sous-classification des contrôles avant ComCtl32.dll version 6

Vous pouvez placer un contrôle dans une sous-classe et stocker des données utilisateur dans un contrôle. Vous le faites lorsque vous utilisez des versions de ComCtl32.dll antérieures à la version 6. La création de sous-classes avec des versions antérieures de ComCtl32.dll présente certains inconvénients.

Pour créer un nouveau contrôle, il est préférable de commencer par l’un des contrôles windows courants et de l’étendre pour répondre à un besoin particulier. Pour étendre un contrôle, créez un contrôle et remplacez sa procédure de fenêtre existante par une nouvelle. La nouvelle procédure intercepte les messages du contrôle et agit sur ceux-ci ou les transmet à la procédure d’origine pour traitement par défaut. Utilisez la fonction SetWindowLong ou SetWindowLongPtr pour remplacer le WNDPROC du contrôle. L’exemple de code suivant montre comment remplacer un WNDPROC.

OldWndProc = (WNDPROC)SetWindowLongPtr (hButton,
GWLP_WNDPROC, (LONG_PTR)NewWndProc);

Stockage des données utilisateur

Vous souhaiterez peut-être stocker les données utilisateur avec une fenêtre individuelle. Ces données peuvent être utilisées par la nouvelle procédure de fenêtre pour déterminer comment dessiner le contrôle ou où envoyer certains messages. Par exemple, vous pouvez utiliser des données pour stocker un pointeur de classe C++ vers la classe qui représente le contrôle. L’exemple de code suivant montre comment utiliser SetProp pour stocker des données avec une fenêtre.

SetProp (hwnd, TEXT("MyData"), (HANDLE)pMyData);

Inconvénients de l’ancienne approche de sous-classification

La liste suivante souligne certains des inconvénients de l’utilisation de l’approche décrite précédemment pour sous-classer un contrôle.

  • La procédure de fenêtre ne peut être remplacée qu’une seule fois.
  • Il est difficile de supprimer une sous-classe après sa création.
  • L’association de données privées à une fenêtre est inefficace.
  • Pour appeler la procédure suivante dans une chaîne de sous-classes, vous ne pouvez pas convertir l’ancienne procédure de fenêtre et l’appeler, vous devez l’appeler à l’aide de la fonction CallWindowProc .

Sous-classification des contrôles à l’aide de ComCtl32.dll version 6

Notes

ComCtl32.dll version 6 est Unicode uniquement. Les contrôles communs pris en charge par ComCtl32.dll version 6 ne doivent pas être sous-classés (ou surclassés) avec les procédures de fenêtre ANSI.

 

ComCtl32.dll version 6 contient quatre fonctions qui facilitent la création de sous-classes et éliminent les inconvénients décrits précédemment. Les nouvelles fonctions encapsulent la gestion impliquée avec plusieurs jeux de données de référence. Par conséquent, le développeur peut se concentrer sur les fonctionnalités de programmation et non sur la gestion des sous-classes. Les fonctions de sous-classification sont les suivantes :

SetWindowSubclass

Cette fonction est utilisée pour sous-classer initialement une fenêtre. Chaque sous-classe est identifiée de manière unique par l’adresse du pfnSubclass et de son uIdSubclass. Ces deux paramètres sont des paramètres de la fonction SetWindowSubclass . Plusieurs sous-classes peuvent partager la même procédure de sous-classe et l’ID peut identifier chaque appel. Pour modifier les données de référence, vous pouvez effectuer des appels ultérieurs à SetWindowSubclass. L’avantage important est que chaque sous-classe instance a ses propres données de référence.

La déclaration d’une procédure de sous-classe est légèrement différente d’une procédure de fenêtre normale, car elle contient deux éléments de données supplémentaires : l’ID de sous-classe et les données de référence. Les deux derniers paramètres de la déclaration de fonction suivante le montrent.

LRESULT CALLBACK MyWndProc (HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass,
DWORD_PTR dwRefData);

Chaque fois qu’un message est reçu par la nouvelle procédure de fenêtre, un ID de sous-classe et des données de référence sont inclus.

Notes

Toutes les chaînes passées à la procédure sont des chaînes Unicode même si Unicode n’est pas spécifié en tant que définition de préprocesseur.

 

L’exemple suivant montre une implémentation squelette d’une procédure de fenêtre pour un contrôle sous-classé.

LRESULT CALLBACK OwnerDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam,
                               LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (uMsg)
    {
    case WM_PAINT:
        .
        .
        .
        return TRUE;
    // Other cases...
    } 
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

La procédure de fenêtre peut être attachée au contrôle dans le gestionnaire WM_INITDIALOG de la procédure de dialogue, comme illustré dans l’exemple suivant.

case WM_INITDIALOG:
{
    HWND button = GetDlgItem(hDlg, IDC_OWNERDRAWBUTTON);
    SetWindowSubclass(button, OwnerDrawButtonProc, 0, 0);
    return TRUE;
}

GetWindowSubclass

Cette fonction récupère des informations sur une sous-classe. Par exemple, vous pouvez utiliser GetWindowSubclass pour accéder aux données de référence.

RemoveWindowSubclass

Cette fonction supprime les sous-classes. RemoveWindowSubclass en combinaison avec SetWindowSubclass vous permet d’ajouter et de supprimer dynamiquement des sous-classes.

DefSubclassProc

La fonction DefSubclassProc appelle le gestionnaire suivant dans la chaîne de sous-classe. La fonction récupère également l’ID et les données de référence appropriées, puis transmet les informations à la procédure de fenêtre suivante.