Un combobox o cuadro de lista desplegable es un control en que el usuario introduce o elige un valor de una lista para un campo determinado. Se suele usar cuando el campo corresponde a una clave ajena el fichero en que estamos y a menudo se restringe la introducción manual del valor dejando unicamente la selección del valor a introducir de la lista. Si se carga la lista con los posibles valores de la clave ajena, nos ahorramos la validación del campo pues unicamente dejamos al usuario introducir valores posibles. Un ejemplo de combobox se muestra en la siguiente figura:
Yo utilizaba comboboxes cuando el campo en cuestión era obligatorio al rellenar el formulario, como en este caso la matería del libro. Sin embargo los combos tienen un problema tremendo: ¿ Que pasa cuando el usuario desea introducir un valor que no está en la lista ?. Se también la solución que más de uno está pensando: Quitas la restricción de usar unicamente la lista y dejas que el usuario pique lo que quiera. Demasiado fácil. Si hago esto y el usuario mete un valor para el campo materia que no está en la lista, que hago con este valor ¿ darlo de alta en el fichero de materias ? Y si lo hago ¿ cómo se lo digo al usuario ? ¿ Quedará claro ? Siempre que he visto en un libro ejemplos de combos se hacen sobre datos estáticos, como provincias, estados, etc. Nunca se hacen sobre datos que puedan ser susceptibles de cambiar dinamicamente.
Además en la figura superior se ven unos bitmaps al lado de los campos Autor y Propietario. Al pincharlos el programa muestra un formulario de selección usuario recibe un formulario que le permite seleccionar un valor para el campo de entre los valores que están introducidos en el fichero correspondiente. Algo como esto:
En este formulario queda claro – o eso creo – que además de elegir el valor, se puede dar de alta, modificar o borrar un registro del fichero correspondiente.
mi solución
Mientras realizaba la última modificación de el Puchero surgió un problema adicional. El programa manejaba dos combos, uno de los cuales se tenía que cargar en función del valor de una serie de botones de selección. Lo difícil no era esto, era hacer el movimiento adelante – atrás por las recetas una vez que se entraba a editar una. Decidí dejar de usar comboboxes.
Había un problema añadido: usar bitmaps externos a los campos de edición trastocan mucho la estética del formulario. Es muy difícil conseguir una imagen de simetría correcta – ya explicaré esto un dia con detalle, lo prometo – con los dichosos bitmaps. La posible solución: usar la clase BtnGet de Ricardo Ramírez. No me convenció, pero su clase me aportó un trocito de código impagable.
Por aquellas fechas Patrick Mast puso en uno de los foros de Fivetech unos enlaces a pantallazos de su WinFakt donde mostraba lo que yo quería hacer y además explicaba como se hacia. Simplemente poniendo un bitmap al lado del get llevando cuidado de que se solapasen para que parecieran un sólo control. Una solución realmente elegante.
A partir de aquí fue todo muy sencillo y tuve resuelto mi problema: quitar los combos pero conservando la simetria de los dialogos, como muestro en la figura siguiente. El dialogo se despliega al hacer click en la imagen al lado del campo y queda claro que se pueden hacer altas, bajas y modificaciones de datos.
gracias a Ricardo
Al bajarme y probar la clase de BtnGet de Ricardo Ramirez encontré un trozo de código muy valioso, en que muestra como posicionar una ventana en la pantalla pegada a un control. Ahí va:
aPoint := AdjustWnd(oGet, oWndNew:nHorizontal, oWndNew:nVertical)
...
ACTIVATE DIALOG oWndNew ;
ON PAINT oWndNew:Move(aPoint[1],aPoint[2],,,.t.)
y ahora la función AdjustWnd(), que es de Ricardo Ramírez
Function AdjustWnd( oBtn, nWidth, nHeight )
Local nMaxWidth, nMaxHeight
Local aPoint
aPoint := { oBtn:nTop + oBtn:nHeight(), oBtn:nLeft }
clientToScreen( oBtn:oWnd:hWnd, @aPoint )
nMaxWidth := GetSysMetrics(0)
nMaxHeight := GetSysMetrics(1)
IF aPoint[2] + nWidth > nMaxWidth
aPoint[2] := nMaxWidth - nWidth
ENDIF
IF aPoint[1] + nHeight > nMaxHeight
aPoint[1] := nMaxHeight - nHeight
ENDIF
Return aPoint