El componente TComboBox combina un cuadro de edición con una lista desplazable de "selección". Los usuarios pueden seleccionar un elemento de la lista o escribir directamente en el cuadro de edición.
Cuando un cuadro combinado está en estado desplegable, Windows dibuja un tipo de control de cuadro de lista para mostrar los elementos del cuadro combinado para su selección.
los Propiedad DropDownCount especifica el número máximo de elementos que se muestran en la lista desplegable.
los ancho de la lista desplegable sería, por defecto, igual al ancho del cuadro combinado.
Cuando la longitud (de una cadena) de elementos excede el ancho del cuadro combinado, los elementos se muestran como límite!
TComboBox no proporciona una forma de establecer el ancho de su lista desplegable :(
Podemos establecer el ancho de la lista desplegable enviando un mensaje especial de Windows al cuadro combinado. El mensaje es CB_SETDROPPEDWIDTH y envía el ancho mínimo permitido, en píxeles, del cuadro de lista de un cuadro combinado.
Para codificar el tamaño de la lista desplegable a, digamos, 200 píxeles, puede hacer lo siguiente:
SendMessage (theComboBox.Handle, CB_SETDROPPEDWIDTH, 200, 0);
Esto solo está bien si está seguro de que todos sus ComboBox. Los artículos no tienen más de 200 px (cuando se dibujan).
Para garantizar que siempre tengamos la lista desplegable con un ancho suficiente, podemos calcular el ancho requerido.
Aquí hay una función para obtener el ancho requerido de la lista desplegable y configurarlo:
procedimiento ComboBox_AutoWidth (const theComboBox: TCombobox); const HORIZONTAL_PADDING = 4; var itemsFullWidth: entero; idx: entero; itemWidth: entero; empezar itemsFullWidth: = 0; // obtener el máximo necesario con los elementos en estado desplegable para idx: = 0 a -1 + theComboBox.Items.Count hacer empezar itemWidth: = theComboBox.Canvas.TextWidth (theComboBox.Items [idx]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) luego itemsFullWidth: = itemWidth; final; // establece el ancho del menú desplegable si es necesario Si (itemsFullWidth> theComboBox.Width) luego empezar // verifica si habría una barra de desplazamiento Si theComboBox.DropDownCount < theComboBox.Items.Count luego itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox.Handle, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); final; final;
El ancho de la cadena más larga se usa para el ancho de la lista desplegable.
Cuándo llamar a ComboBox_AutoWidth?
Si rellena previamente la lista de elementos (en tiempo de diseño o al crear el formulario), puede llamar al procedimiento ComboBox_AutoWidth dentro del formulario OnCreate controlador de eventos.
Si cambia dinámicamente la lista de elementos del cuadro combinado, puede llamar al procedimiento ComboBox_AutoWidth dentro del OnDropDown controlador de eventos: ocurre cuando el usuario abre la lista desplegable.
Una prueba
Para una prueba, tenemos 3 cuadros combinados en un formulario. Todos tienen elementos con su texto más ancho que el ancho real del cuadro combinado. El tercer cuadro combinado se coloca cerca del borde derecho del borde del formulario.
La propiedad Items, para este ejemplo, está precargada: llamamos a nuestro ComboBox_AutoWidth en el controlador de eventos OnCreate para el formulario:
// OnCreate del formulario procedimiento TForm.FormCreate (Remitente: TObject); empezar ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); final;
No hemos llamado ComboBox_AutoWidth para Combobox1 para ver la diferencia!
Tenga en cuenta que, cuando se ejecuta, la lista desplegable para Combobox2 será más amplia que Combobox2.
Para Combobox3, el que se encuentra cerca del borde derecho, la lista desplegable se corta.
Enviar el CB_SETDROPPEDWIDTH siempre extenderá el cuadro de lista desplegable a la derecha. Cuando su cuadro combinado está cerca del borde derecho, extender el cuadro de lista más a la derecha daría como resultado que se corte el cuadro de lista.
Necesitamos extender de alguna manera el cuadro de lista a la izquierda cuando este sea el caso, no a la derecha!
CB_SETDROPPEDWIDTH no tiene forma de especificar en qué dirección (izquierda o derecha) extender el cuadro de lista.
Justo cuando se muestra la lista desplegable, Windows envía el mensaje WM_CTLCOLORLISTBOX a la ventana principal de un cuadro de lista, a nuestro cuadro combinado.
Ser capaz de manejar el WM_CTLCOLORLISTBOX para el cuadro combinado casi a la derecha resolvería el problema.
El Todopoderoso WindowProc
Cada control VCL expone la propiedad WindowProc, el procedimiento que responde a los mensajes enviados al control. Podemos usar la propiedad WindowProc para reemplazar o subclasificar temporalmente el procedimiento de ventana del control.
Aquí está nuestro WindowProc modificado para Combobox3 (el que está cerca del borde derecho):
// ComboBox3 WindowProc modificado procedimiento TForm.ComboBox3WindowProc (var Mensaje: TMessage); var cr, lbr: TRect; empezar // dibujar el cuadro de lista con elementos del cuadro combinado if Message.Msg = WM_CTLCOLORLISTBOX entonces empezar GetWindowRect (ComboBox3.Handle, cr); // rectángulo de cuadro de lista GetWindowRect (Message.LParam, lbr); // muévelo a la izquierda para que coincida con el borde derecho Si cr.Right lbr.Right luego MoveWindow (Message.LParam, lbr.Left- (lbr.Right-clbr.Right), lbr.Top, lbr.Right-lbr.Left, lbr.Bottom-lbr.Top, True); final más ComboBox3WindowProcORIGINAL (Mensaje); final;
Si el mensaje que recibe nuestro cuadro combinado es WM_CTLCOLORLISTBOX, obtenemos el rectángulo de su ventana, también obtenemos el rectángulo del cuadro de lista que se mostrará (GetWindowRect). Si parece que el cuadro de lista aparecerá más a la derecha, lo movemos a la izquierda para que el cuadro combinado y el borde derecho del cuadro de lista sean los mismos. Tan fácil como eso :)
Si el mensaje no es WM_CTLCOLORLISTBOX, simplemente llamamos al procedimiento de manejo de mensajes original para el cuadro combinado (ComboBox3WindowProcORIGINAL).
Finalmente, todo esto puede funcionar si lo hemos configurado correctamente (en el controlador de eventos OnCreate para el formulario):
// OnCreate del formulario procedimiento TForm.FormCreate (Remitente: TObject); empezar ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // adjuntar WindowProc modificado / personalizado para ComboBox3 ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; final;
Donde en la declaración del formulario tenemos (completo):
tipo TForm = clase(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox; procedimiento FormCreate (remitente: TObject); privado ComboBox3WindowProcORIGINAL: TWndMethod; procedimiento ComboBox3WindowProc (var Mensaje: TMessage); público Declaraciones públicas final;
Y eso es. Todo manejado :)