2011-04-07 16 views
10

¿Cómo puedo tener TComboBox con algunos elementos que están deshabilitados? Necesito que el usuario vea estos elementos, pero no pueda seleccionarlos.Delphi: ¿Es posible tener un cuadro combinado con elementos desactivados?

Gracias!

+1

No es evidente por el título de la pregunta o de sus etiquetas, pero aquí es una implementación de un componente derivado de TComboBox con el apoyo elemento deshabilitado: http: // stackoverflow. com/questions/4356364 –

+1

No haga esto. Viola lo que los usuarios esperan de los cuadros combinados. Encontrar otra forma. En cualquier caso, los comboboxes no son una buena forma de presentar datos al usuario de todos modos; si necesita que vean una descripción general de lo que pueden y no pueden hacer, no deberían tener que realizar un paso adicional (es decir, no tener presionar un botón desplegable). Todo se trata de la experiencia del usuario, ¡no te metas con eso! –

Respuesta

15

Sí, y así es como se hace:

Caiga una TComboBox en su forma, y ​​establecer Style a csOwnerDrawFixed. A continuación, añadir los controladores de eventos

procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer; 
    Rect: TRect; State: TOwnerDrawState); 
const 
    INDENT = 3; 
begin 
    with TComboBox(Control) do 
    begin 
    FillRect(Canvas.Handle, Rect, GetStockObject(WHITE_BRUSH)); 
    inc(Rect.Left, INDENT); 
    if boolean(Items.Objects[Index]) then 
     SetTextColor(Canvas.Handle, clBlack) 
    else 
     SetTextColor(Canvas.Handle, clGray); 
    DrawText(Canvas.Handle, 
     PChar(Items[Index]), 
     length(Items[Index]), 
     Rect, 
     DT_SINGLELINE or DT_LEFT or DT_VCENTER or DT_END_ELLIPSIS) 
    end; 
end; 

y

procedure TForm1.ComboBox1CloseUp(Sender: TObject); 
begin 
    with TComboBox(Sender) do 
    if (ItemIndex <> -1) and not boolean(Items.Objects[ItemIndex]) then 
    begin 
     beep; 
     Perform(CB_SHOWDROPDOWN, integer(true), 0); 
    end; 
end; 

Además, en la sección de interfaz de su formulario, antes de la declaración de la clase de formulario, agregue

TComboBox = class(StdCtrls.TComboBox) 
protected 
    procedure WndProc(var Message: TMessage); override; 
end; 

y aplicar el WndProc como

procedure TComboBox.WndProc(var Message: TMessage); 

    function NextItemIsDisabled: boolean; 
    begin 
    result := (ItemIndex < Items.Count - 1) and 
     not boolean(Items.Objects[ItemIndex + 1]); 
    end; 

    procedure SelectNextEnabledItem; 
    var 
    i: Integer; 
    begin 
    for i := ItemIndex + 1 to Items.Count - 1 do 
     if boolean(Items.Objects[i]) then 
     begin 
     ItemIndex := i; 
     Exit; 
     end; 
    beep; 
    end; 

    procedure KillMessages; 
    var 
    msg: TMsg; 
    begin 
    while PeekMessage(msg, 
     Handle, 
     WM_KEYFIRST, 
     WM_KEYLAST, 
     PM_REMOVE) do; 
    end; 

    function PrevItemIsDisabled: boolean; 
    begin 
    result := (ItemIndex > 0) and 
     not boolean(Items.Objects[ItemIndex - 1]); 
    end; 

    procedure SelectPrevEnabledItem; 
    var 
    i: Integer; 
    begin 
    for i := ItemIndex - 1 downto 0 do 
     if boolean(Items.Objects[i]) then 
     begin 
     ItemIndex := i; 
     Exit; 
     end; 
    beep; 
    end; 

begin 
    case Message.Msg of 
    WM_KEYDOWN: 
     case Message.WParam of 
     VK_DOWN: 
      if NextItemIsDisabled then 
      begin 
      SelectNextEnabledItem; 
      KillMessages; 
      Exit; 
      end; 
     VK_UP: 
      if PrevItemIsDisabled then 
      begin 
      SelectPrevEnabledItem; 
      KillMessages; 
      Exit; 
      end; 
     end; 
    end; 
    inherited; 
end; 

Para probar el cuadro combinado, escribir, por ejemplo

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    ComboBox1.Items.AddObject('Alpha', TObject(true)); 
    ComboBox1.Items.AddObject('Beta', TObject(true)); 
    ComboBox1.Items.AddObject('Gamma', TObject(false)); 
    ComboBox1.Items.AddObject('Delta', TObject(true)); 
end; 

Creo que se obtiene el significado de true y false aquí - que significa simplemente enabled.

+5

+1 por el esfuerzo, Andreas, aunque te dispararía si trabajáramos juntos y lo usaste (y también lo harían mis usuarios). Están acostumbrados a cuadros combinados que actúan como cuadros combinados. No publiqué nada cerca del código; Pensé que si alguien quería eludir los estándares de esta forma, debería tener que trabajar para descifrarlo. –

+0

@Ken: Probablemente tampoco lo use, pero he visto este tipo de comboboxes no estándar cada vez más en los últimos años, especialmente en Internet (HTML + CSS + JavaScript), así que creo que no es * que * malo. –

+0

Pero la aplicación de escritorio es * Windows *, que tiene estándares de interfaz de usuario para estas cosas. HTML/CSS/JS no lo hacen; prácticamente haces lo que quieres con ellos. (Pero te di el +1, aunque no estoy de acuerdo, tu respuesta fue acertada para la pregunta original.) :) –

5

No es fácil (y es una mala idea, ya que no es así como se comportan las cajas combinadas en Windows).

Tendría que dibujar usted mismo el cuadro combinado. Utilice la matriz Items.Objects para almacenar si el elemento está habilitado o deshabilitado, y verifique esa matriz antes de dibujar cada elemento para establecer los colores de manera apropiada.

También necesitaría manejar los eventos OnChange y OnClick, y agregar una forma de rastrear el último ItemIndex seleccionado. En OnChange/OnClick, desconecte el controlador de eventos, verifique el valor Objects[ItemIndex] para ver si se permite una selección, si no configuró el ItemIndex de nuevo en el último ItemIndex seleccionado, y luego vuelve a habilitar el controlador de eventos.

+4

¿Qué sucede si el usuario hace clic en el elemento aparentemente desactivado en el cuadro desplegable desplegable? El cuadro se cerrará y es posible que el usuario no se dé cuenta de que se revertió al último valor seleccionado. ¡Eso es confuso! –

+0

Puede encontrar información adicional en el grupo de noticias aquí: http://groups.google.com/group/comp.lang.pascal.delphi.misc/browse_thread/thread/ea67221a7d3f7e13/17418f924fc64f43?lnk=raot&pli=1 – pritaeas

+0

@Cosmin : De acuerdo. Como dije, no es así como funcionan los cuadros combinados en Windows. Por eso dije que era una idea terrible, y la tuya era mejor.También dije que no fue fácil. –

0

sólo tiene que añadir siguiente código en KeyPress procedimiento

procedure Tform1.Combobox1editKeyPress(Sender: TObject; var Key: Char); 
begin 
    Key:=#0; 
end; 
Cuestiones relacionadas