2010-12-04 65 views
3

J'utilise Delphi7 et j'aimerais avoir un ComboBox avec des éléments de séparation (comme dans les menus contextuels).Création d'un contrôle ComboBox avec un ou plusieurs éléments de séparation?

Je l'ai vu magnifiquement mis en œuvre dans Mozilla Sunbird (je sais, ce n'est pas Delphi ...) de la façon suivante:

  1. L'élément de séparation est une simple ligne grise dessiné dans le centre de l'élément

  2. Si vous passez la souris sur le séparateur avec la souris, la sélection ne apparaissent

  3. Si l'utilisateur clique sur le separato r, il n'est pas non plus sélectionné et la combobox ne fait pas de gros plan.

Le numéro 1 pourrait être implémenté en utilisant DrawItem. Je pourrais vivre sans numéro 2 parce que je n'en ai aucune idée.

Pour le numéro 3, je demande votre aide. J'ai compris que juste après avoir fermé un message CBN_CLOSEUP est envoyé à la liste déroulante.

J'ai pensé à accrocher le proc de la fenêtre et si CBN_CLOSEUP est envoyé à un certain combobox puis en le contrecarrant. Mais je ne suis pas sûr si c'est la meilleure solution, ou peut-être il y a d'autres, des manières plus élégantes? Quelle que soit la solution, j'aimerais avoir un ComboBox standard qui prend en charge correctement les thèmes WinXP/Vista/7.

Merci!


Edit: Pour un composant de travail s'il vous plaît voir ce fil:

Can you help translating this very small C++ component to Delphi?

+1

Vous avez demandé une zone de liste déroulante standard, mais vous avez également demandé une zone de liste déroulante dotée de séparateurs. Ce sont des demandes mutuellement exclusives. La zone de liste déroulante de Mozilla peut le faire parce que ce n'est pas un contrôle fourni par le système d'exploitation; Mozilla fournit tout son propre code pour tous ses contrôles afin qu'il puisse fonctionner de manière cohérente sur toutes les plateformes supportées. –

+0

Les widgets de Mozilla sont une source constante d'irritation pour moi. Ils atteignent la cohérence dans le mauvais sens, ce qui est cohérent sur toutes les plates-formes, mais les utilisateurs ont tendance à fonctionner sur une plate-forme unique. La cohérence que vous voulez vraiment est avec la plate-forme native et ils ne peuvent pas le faire. Y a-t-il autre chose que Qt qui peut atteindre des widgets multiplateformes mais natifs? –

+1

La comboxbox améliorée de Mozilla s'intègre merveilleusement dans l'environnement Win et ajoute une idée géniale avec les séparateurs combobox. Mais je suis d'accord avec toi que iTunes/Safari pour Windows est très mauvais et déroutant (bien que son but soit évidemment de faciliter la transition d'un PC Win vers un Mac) ... – Steve

Répondre

1

Ce que vous voulez est un combobox dessiné par le propriétaire. Voir ceci: http://delphi.about.com/od/vclusing/a/drawincombobox.htm

En outre, cela semble résoudre faire l'élément unclicable: http://borland.newsgroups.archived.at/public.delphi.vcl.components.using.win32/200708/0708225320.html

Pour autant que je sais qu'il n'y a aucun moyen VCL de le faire, de sorte que vous aurez à sous-classe ComboBox. Ce serait bien de créer un composant encapsulant ces fonctionnalités pour pouvoir les réutiliser facilement.

Dieu bénisse

+0

Oui, j'ai également trouvé cette page via Google, mais comment empêcher la fermeture de la combobox, lorsque l'utilisateur clique sur l'élément séparateur? – Steve

+0

Merci, je pense que j'ai trouvé le composant que vous avez lié dans votre édition en même temps :-) – Steve

0

Si vous voulez que vos commandes pour regarder un bon usage du SpTBXLib libre. Il prend en charge les composants de style combo qui font apparaître un menu contextuel avec des lignes.

+2

Je ne pouvais pas être plus en désaccord; Il est essentiel que vos composants utilisent les thèmes de la plateforme native, à moins bien sûr que vous ne souhaitiez simuler iTunes/Safari pour Windows! –

+0

Jan vous n'avez pas bien lu mon message. J'ai dit que je m'en tenais aux thèmes standards de XP/Vista/7 et que j'évitais à tout prix les composants skinned/100% ownerdrawn! – Steve

+0

@Steve vous aurez besoin du propriétaire dessiné sûrement si bien que je suppose que vous devez entrer dans UXtheme codage qui est un cauchemar ruddy! –

1

J'ai joué avec la confection d'articles de séparation cliquables (comme décrit dans this answer) et a couru dans plusieurs défauts de l'interface utilisateur. Le problème est que les boîtes combo ont plusieurs aspects de leur comportement qui peuvent être difficiles à obtenir exactement droite:

  • En appuyant sur la et les touches fléchées la liste navigue alors que la liste est tombé vers le bas.
  • Appuyez sur Entrée pour fermer la liste déroulante et sélectionner l'élément actuel. Appuyez sur Échap pour fermer la liste déroulante, en sélectionnant l'élément actuel (si l'élément en cours a été choisi avec les touches fléchées haut et bas) ou le dernier élément sélectionné.
  • Si la zone de liste déroulante est active, appuyez sur les touches fléchées vers le haut et vers le bas pour modifier la sélection en cours sans afficher la liste.
  • Si la zone de liste déroulante a le focus, tout en tapant n'importe quoi sélectionne l'élément de zone de liste déroulante correspondant à ce qui frappe.
  • Si la zone de liste déroulante est active, appuyez sur la touche F4 pour faire tomber la liste déroulante, qui peut ensuite être contrôlée par le clavier ou la souris.

Veiller à ce que les éléments de séparation handicapés ne répondent pas à toute de ces événements (plus tout autre événement que je peux manquer, par exemple, les lecteurs d'écran?) Semble semé d'erreur.

Au lieu de cela, l'approche que je me sers est de tirer le séparateur dans le cadre de l'article:

  1. Utilisez un propriétaire à hauteur variable dessiner zone de liste déroulante.
  2. Ajoutez 3 pixels à la hauteur pour tous les éléments nécessitant des séparateurs. Dessinez une ligne horizontale en haut de chaque élément nécessitant un séparateur.

Voici un code C++ Builder pour accomplir ceci; la traduire en Delphi devrait être assez facile.

void __fastcall TForm1::ComboBox1DrawItem(TWinControl *Control, 
    int Index, TRect &Rect, TOwnerDrawState State) 
{ 
    bool draw_separator = NeedsSeparator(Index) && 
     !State.Contains(odComboBoxEdit); 

    TCanvas *canvas = dynamic_cast<TCustomCombo*>(Control)->Canvas; 
    canvas->FillRect(Rect); 

    TRect text_rect = Rect; 
    // Add space for separator if needed. 
    if (draw_separator) { 
    text_rect.Top += 3; 
    } 

    canvas->TextOut(text_rect.Left + 3, 
     (text_rect.Top + text_rect.Bottom)/2 - 
     canvas->TextHeight(ComboBox1->Items->Strings[Index])/2), 
     ComboBox1->Items->Strings[Index]); 

    // Draw a separator line above the item if needed. 
    if (draw_separator) { 
    canvas->Pen->Color = canvas->Font->Color; 
    canvas->MoveTo(Rect.Left, Rect.Top + 1); 
    canvas->LineTo(Rect.Right, Rect.Top + 1); 
    } 
} 

void __fastcall TForm1::ComboBox1MeasureItem(
    TWinControl * /* Control */, int Index, int &Height) 
{ 
    Height = ComboBox1->ItemHeight; 

    // Add space for the separator if needed. 
    if (Index != -1 && NeedsSeparator(Index)) { 
    Height += 3; 
    } 
}