le TComboBox Le composant combine une zone d'édition avec une liste déroulante de «sélection». Les utilisateurs peuvent sélectionner un élément dans la liste ou taper directement dans le boîte d'édition.
La liste déroulante
Lorsqu'une zone de liste déroulante est dans un état déroulant, Windows dessine un type de contrôle de zone de liste pour afficher les éléments de la zone de liste déroulante pour la sélection.
le Propriété DropDownCount spécifie le nombre maximal d'éléments affichés dans la liste déroulante.
le largeur de la liste déroulante serait, par défaut, égal à la largeur de la zone de liste déroulante.
Lorsque la longueur (d'une chaîne) des éléments dépasse la largeur de la zone de liste déroulante, les éléments sont affichés comme coupés!
TComboBox ne fournit pas un moyen de définir la largeur de sa liste déroulante :(
Fixer la largeur de la liste déroulante ComboBox
Nous pouvons définir la largeur de la liste déroulante en envoyant un message spécial Message Windows dans la zone de liste déroulante. Le message est
CB_SETDROPPEDWIDTH et envoie la largeur minimale autorisée, en pixels, de la zone de liste d'une zone de liste déroulante.Pour coder en dur la taille de la liste déroulante à, disons, 200 pixels, vous pouvez faire:
SendMessage (theComboBox. Poignée, CB_SETDROPPEDWIDTH, 200, 0);
Ce n'est correct que si vous êtes sûr que tous vos theComboBox. Les objets ne dépassent pas 200 px (lorsqu'ils sont dessinés).
Pour nous assurer que la liste déroulante est toujours suffisamment large, nous pouvons calculer la largeur requise.
Voici une fonction pour obtenir la largeur requise de la liste déroulante et la définir:
procédure ComboBox_AutoWidth (const theComboBox: TCombobox); const
HORIZONTAL_PADDING = 4; var
itemsFullWidth: entier; idx: entier; itemWidth: entier; commencer
itemsFullWidth: = 0; // obtenir le maximum nécessaire avec des éléments dans l'état déroulantpour idx: = 0 à -1 + theComboBox. Articles. Compter fairecommencer
itemWidth: = theComboBox. Toile. TextWidth (theComboBox. Éléments [idx]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) ensuite itemsFullWidth: = itemWidth; fin; // définir la largeur de la liste déroulante si nécessairesi (itemsFullWidth> theComboBox. Largeur) alors. commencer// vérifier s'il y aurait une barre de défilementsi theComboBox. DropDownCount ensuite
itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox. Handle, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); fin; fin;
La largeur de la chaîne la plus longue est utilisée pour la largeur de la liste déroulante.
Quand appeler ComboBox_AutoWidth?
Si vous pré-remplissez la liste des éléments (au moment de la conception ou lors de la création du formulaire), vous pouvez appeler la procédure ComboBox_AutoWidth dans le formulaire OnCreate gestionnaire d'événements.
Si vous modifiez dynamiquement la liste des éléments de la zone de liste déroulante, vous pouvez appeler la procédure ComboBox_AutoWidth dans le OnDropDown gestionnaire d'événements - se produit lorsque l'utilisateur ouvre la liste déroulante.
Un examen
Pour un test, nous avons 3 zones de liste déroulante sur un formulaire. Tous ont des éléments dont le texte est plus large que la largeur réelle de la zone de liste déroulante. La troisième zone de liste déroulante est placée près du bord droit de la bordure du formulaire.
La propriété Items, pour cet exemple, est pré-remplie - nous appelons notre ComboBox_AutoWidth dans le gestionnaire d'événement OnCreate pour le formulaire:
// OnCreate du formulaireprocédure TForm. FormCreate (expéditeur: TObject); commencer
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); fin;
Nous n'avons pas appelé ComboBox_AutoWidth pour Combobox1 pour voir la différence!
Notez que lors de l'exécution, la liste déroulante de Combobox2 sera plus large que Combobox2.
La liste déroulante entière est coupée pour "Placement sur le bord presque droit"
Pour Combobox3, celle placée près du bord droit, la liste déroulante est coupée.
L'envoi de CB_SETDROPPEDWIDTH étendra toujours la zone de liste déroulante vers la droite. Lorsque votre zone de liste déroulante est près du bord droit, étendre la zone de liste vers la droite entraînerait la coupure de l'affichage de la zone de liste.
Nous devons en quelque sorte étendre la zone de liste vers la gauche lorsque c'est le cas, pas vers la droite!
Le CB_SETDROPPEDWIDTH n'a aucun moyen de spécifier dans quelle direction (gauche ou droite) étendre la zone de liste.
Solution: WM_CTLCOLORLISTBOX
Juste au moment où la liste déroulante doit être affichée, Windows envoie le message WM_CTLCOLORLISTBOX à la fenêtre parent d'une zone de liste - à notre zone de liste déroulante.
Le fait de pouvoir gérer WM_CTLCOLORLISTBOX pour la zone de liste déroulante proche du bord droit résoudrait le problème.
La fenêtre toute-puissante
Chaque contrôle VCL expose la propriété WindowProc - la procédure qui répond aux messages envoyés au contrôle. Nous pouvons utiliser la propriété WindowProc pour remplacer ou sous-classer temporairement la procédure de fenêtre du contrôle.
Voici notre WindowProc modifié pour Combobox3 (celui près du bord droit):
// ComboBox3 WindowProc modifiéprocédure TForm. ComboBox3WindowProc (var Message: TMessage); var
cr, lbr: TRect; commencer// dessiner la zone de liste avec les éléments de la zone de liste
si Message. Msg = WM_CTLCOLORLISTBOX alors. commencer
GetWindowRect (ComboBox3.Handle, cr); // rectangle de list box
GetWindowRect (Message. LParam, lbr); // le déplacer vers la gauche pour correspondre à la bordure droitesi cr. Droite <> lbr. Droite ensuite
MoveWindow (Message. LParam, lbr. Gauche- (lbr. Clbr droite. À droite), lbr. Haut, lbr. Droite-lbr. Gauche, lbr. Bottom-lbr. Top, True); finautre
ComboBox3WindowProcORIGINAL (Message); fin;
Si le message que notre zone de liste déroulante reçoit est WM_CTLCOLORLISTBOX, nous obtenons le rectangle de sa fenêtre, nous obtenons également le rectangle de la zone de liste à afficher (GetWindowRect). S'il apparaît que la zone de liste apparaît plus à droite - nous la déplaçons vers la gauche pour que la zone de liste déroulante et la bordure droite de la zone de liste soient identiques. Aussi simple que ça :)
Si le message n'est pas WM_CTLCOLORLISTBOX, nous appelons simplement la procédure de gestion des messages d'origine pour la zone de liste déroulante (ComboBox3WindowProcORIGINAL).
Enfin, tout cela peut fonctionner si nous l'avons correctement défini (dans le gestionnaire d'événement OnCreate du formulaire):
// OnCreate du formulaireprocédure TForm. FormCreate (expéditeur: TObject); commencer
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // attacher WindowProc modifié / personnalisé pour ComboBox3
ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; fin;
Où, dans la déclaration du formulaire, nous avons (entier):
type
TForm = classe(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox;procédure FormCreate (expéditeur: TObject); privé
ComboBox3WindowProcORIGINAL: TWndMethod; procédure ComboBox3WindowProc (var Message: TMessage); Publique{Déclarations publiques}fin;
Et c'est tout. Tous traités :)