Página 1 de 1

[SOLUCIONADO] Mover la selección en mi combobox

Publicado: 21 Mar 2012, 11:07
por mitchito
Buenos días,

He estado mirando la ayuda y varios foros pero no encuentro la instrucción para lo que quiero hacer, os explico. Tengo mi GUI y quisiera que una vez se inicia una función, modificara la opción seleccionada en el Combobox de mi GUI.

Gracias!!

Re: Mover la selección en mi combobox

Publicado: 21 Mar 2012, 12:42
por Ximorro
No es por nada pero un poco de código siempre viene bien para tener algo con lo que empezar...

Bueno se me ocurren tres o cuatro maneras, dependiendo de lo que te interese.
Con las funciones básicas de AutoIt se puede establecer el valor por defecto del combo, que puedes cambiar cuando quieras. Desgraciadamente no sé cómo hacerlo sin redefinir el contenido de los items, así que no me gusta mucho, a menos que sean combos de pocos datos fijos.
Se haría:

Código: Seleccionar todo

$items = "|item1|item2|item3"
$comb = GUICtrlCreateCombo("", 10, 10, 160)
GUICtrlSetData(-1, $items, "item3")
...
GUICtrlSetData($comb, $items, "item1")
En este caso cuando lo creo pongo por defecto "item3", más adelante en otro punto del programa lo cambio a "item1". Como ves el problema es que el segundo parámetro de GuiCtrlSetData es obligatorio, así que tengo que poner otra vez los items. Para simplificarlo los tengo en la variable $items, aún así no me gusta mucho esta solución. Si alguien sabe cómo utilizar GuiCtrlSetData en un combo para cambiar el valor por defecto sin redefinir los items que lo diga. En ese caso sí sería bastante interesante este método.

Las otras maneras se hacen mandando mensajes windows al combo. También es con las funciones básicas de AutoIt, pero es con la genérica GUICtrlSendMsg. Afortunadamente tenemos los valores de los mensajes ya definidos en la udf ComboConstants.au3.

Una manera es por posición, cambiando al índice correspondiente, empezando a contar desde cero. Es el mensaje CB_SETCURSEL, así que se hace así:
GUICtrlSendMsg($comb, $CB_SETCURSEL, $indice, 0)
$indice puede valer desde 0 hasta el número de items menos 1.
El último parámetro (lParam) no se usa en este mensaje, pero no es opcional para la función así que lo pongo a cero.

Con ese mensaje te colocas por posición, pero también puedes buscar por contenido, eso se hace con el mensaje CB_SELECTSTRING:
GUICtrlSendMsg($comb, $CB_SELECTSTRING, $indice, $cadena)
En este caso $indice indica desde qué posición se empieza a buscar, se usa -1 para buscar en todo el combo. En $cadena pones el texto a buscar (busca subcadenas pero sólo desde el principio del item.

Te pongo un ejemplo en el que uso estos dos métodos. También está comentado el equivalente a CB_SELECTSTRING con GUICtrlSetData.

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <ComboConstants.au3>

Global $items, $msg, $comb, $bot1, $bot2
GUICreate("GUI combo", 180, 110)

$items = "|item1|item2|item3"
$comb = GUICtrlCreateCombo("", 10, 10, 160)
GUICtrlSetData(-1, $items, "item3")
$bot1 = GuiCtrlCreateButton('Selecciona "item1"', 10, 40)
$bot2 = GuiCtrlCreateButton("Selecciona segundo elemento", 10, 70)
GUISetState()

While 1
	$msg = GUIGetMsg()
	Switch $msg
		case $GUI_EVENT_CLOSE
			ExitLoop
		case $bot1
			;GUICtrlSetData($comb, $items, "item1")
			GUICtrlSendMsg($comb, $CB_SELECTSTRING, -1, "item1") ; Selecciona por texto
		case $bot2
			GUICtrlSendMsg($comb, $CB_SETCURSEL, 1, 0) ; Selecciona por posición (0 = primer elemento)
	EndSwitch
WEnd
Por último decir que hay una udf para trabajar con combos, GuiComboBox.au3, que tiene estas cosas y muchas más. Si vas a manejar el combo de maneras más complicadas te será muy útil. Si sólo vas a hacer lo de seleccionar el item yo no sobrecargaría el programa con esta udf tan completa, siendo que el problema se soluciona en una línea (el envío del mensaje). En cualquier caso aunque no uses la udf se puede aprender mucho de ella, por ejemplo veo que ellos hacen también esto con los mensajes, aunque curiosamente en vez de usar GUICtrlSendMsg hacen una llamada directamente a SendMessageW en user32.dll, complicación que se podrían haber ahorrado usando el soporte nativo en AutoIT, pero bueno, el resultado es el mismo.

Re: Mover la selección en mi combobox

Publicado: 21 Mar 2012, 13:54
por mitchito
Muchas gracias!! He utilizado la segunda opción y va perfecto!
GUICtrlSendMsg($combo, $CB_SETCURSEL, $indice, 0)

Re: [SOLUCIONADO] Mover la selección en mi combobox

Publicado: 21 Mar 2012, 15:15
por Ximorro
Vaya, vaya, veo que "has solucionado" el problema. Unos créditos habrían sido de agradecer, y más aún teniendo en cuenta que no has puesto absolutamente nada de código tuyo, aunque ahí también te lo pedían...

http://www.autoitscript.com/forum/topic ... _p__972848

Al menos les podías haber traducido los textos del programa a inglés...

Re: [SOLUCIONADO] Mover la selección en mi combobox

Publicado: 21 Mar 2012, 17:15
por Chefito
Mmmmm.....muy mal por parte de mitchito el no añadir créditos a los código que muestras, haciendo creer que lo has hecho tú :smt019 :smt019 :smt018 :smt021 :smt011 .
Por culpa de estas cosas no dan ganas de ayudar a usuarios con comportamientos como estos :smt018 .

Contestando a Ximorro:
Ximorro escribió: Si alguien sabe cómo utilizar GuiCtrlSetData en un combo para cambiar el valor por defecto sin redefinir los items que lo diga. En ese caso sí sería bastante interesante este método.
Simplemente poniendo el texto del item como segundo parámetro. No se añade, se situa. Y no me preguntes por qué. Se comporta así y punto :smt005 .

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <ComboConstants.au3>

Global $items, $msg, $comb, $bot1, $bot2
GUICreate("GUI combo", 180, 110)

$items = "|item1|item2|item3"
$comb = GUICtrlCreateCombo("", 10, 10, 160)
GUICtrlSetData(-1, $items, "item3")
$bot1 = GuiCtrlCreateButton('Selecciona "item1"', 10, 40)
GUISetState()

While 1
   $msg = GUIGetMsg()
   Switch $msg
      case $GUI_EVENT_CLOSE
         ExitLoop
      case $bot1
         GUICtrlSetData($comb, "item1") ; Selecciona por texto
   EndSwitch
WEnd
Saludos.

Re: [SOLUCIONADO] Mover la selección en mi combobox

Publicado: 22 Mar 2012, 09:47
por Ximorro
Voy a intentar ser bien pensado y como no ha dicho expresamente que la solución es suya, sólo que "He solucionado mi problema" y "La solución que he usado".
En fin, habría sido mejor "Mi problema ha sido solucionado", pero bueno.

Verás mitchito, no es necesario dar créditos por cualquier cosa, si te hubiera contestado en una línea diciendo "Usa GUICtrlSendMsg con CB_SETCURSEL" pues vale, pero lo que me fastidia un poco es que como verás la respuesta era bastante extensa, aunque no lo creas me llevó mi tiempo escribirla, y encima me tocó hacer el código desde cero porque ni siquiera ofreciste un GUI sobre el que trabajar. Y no me molesté en dar la primera solución que se me ocurrió, sino que como no me satisfacía mucho busqué otras y te las puse. Creo que ese esfuerzo requiere algo de reconocimiento cuando en otro foro haces la misma consulta y dices "He solucionado el problema". Por cierto, allí también te han pedido algo de código... tuyo.


¡Chefito, lo encontraste! Pues hubiera imaginado que eso redefinía el combo con sólo ese item, pero no, hace lo que queremos ¡interesante!
Pues entonces creo que esta es la solución más natural. Para ir por índice sí será mejor el de mensajes pero por texto este es más "tipo AutoIt"

Nota, para redefinir el combo con un sólo elemento habrá que usar el separador:
GUICtrlSetData($comb, "|item2")


Por cierto, que hay otra solución (es lo que estaba buscando cuando me encontré el post de mitchito en el otro foro, que no es que lo estuviera siguiendo, es que estaba investigando lo de los combos porque casualmente después me hizo falta para otra cosa, aunque algo más compleja).
Mi caso es algo más complicado porque quiero controlar el combo de una aplicación externa, en realidad el diálogo de imprimir de windows, donde seleccionas impresora.
Al no tratarse de mi código AutoIt no funciona GUICtrlSetData ni directamente GUICtrlSendMsg.
Sí se pueden enviar mensajes usando directamente SendMessage en user32.dll, como hacen en la UDF, ¡pero no funciona bien!. Resulta que sí selecciona el elemento en el combo, pero falta alguna notificación porque el formulario no se entera, al dar al botón de aceptar no se cambia la impresora, y de hecho dentro del formulario cuando seleccionas una impresora cambian algunas etiquetas informativas, pues mandando el mensaje el item se selecciona pero ni cambian esas etiquetas ¿? ¿?

Así que he encontrado otra solución, hay una función un poco rara porque es un cajón de sastre, tiene algunas cosas genéricas y otras específicas para combos, listas, edits, tabs, etc.
Se trata de ControlCommand.
En concreto podemos seleccionar por texto en un combo con:
ControlCommand($VentConfig, "", $hcombo, "SelectString", $imprNombre)
siendo $VentConfig el handle de mi ventana de configuración de impresoras y $hcombo el handle del combo. $imprNombre es el texto con el nombre de la impresora que quiero seleccionar.
Eso debería ser totalmente equivalente a:
_SendMessage($hcombo, $CB_SELECTSTRING, -1, $imprNombre, 0, "wparam", "wstr")
La función _SendMessage está en SendMessage.au3 y usa la dll antes comentada.

Pero no van igual, porque con ControlCommand además de seleccionar el item lo notifica, y las etiquetas cambian como toca, y lo que es más importante: al aceptar el diálogo selecciona la impresora.
La diferencia es que con _SendMessage recojo el índice donde encuentra el item, y me da -1 si no lo encuentra. ControlCommand no retorna el índice, pero al menos con @error sabemos si ha encontrado el texto.

¿Por qué no irá el mensaje?... raro raro. Pero al menos con ControlCommand lo he solucionado, esta es otra solución para mitchito, pues también funciona en un GUI propio, de todas maneras ahora la mejor solución para GUI propio creo que es GUICtrlSetData.

Para combos externos a la aplicación podéis probar _SendMessage, aunque ojo que en mi viejo XP en ese diálogo ya veis que no va del todo bien. Así que también tenemos ControlCommand con el comando "SelectString" que tiene toda la pinta de estar enviando el mensaje CB_SELECTSTRING, pero bueno.
Con ControlCommand también podemos seleccionar por índice con el comando "SetCurrentSelection", que sospecho está enviando el mensaje
CB_SETCURSEL, así que no sé por qué no funcionará bien enviar directamente el mensaje, debe faltar algo que notifique al formulario...