Página 1 de 1

problemas al crear un historial cronológico

Publicado: 09 Ago 2011, 14:05
por taoru
hola!,
ando con el siguiente problema que no puedo resolver.

estoy creando un audiojuego (un juego para personas ciegas) de cartas online, para llevar un hilo del juego creo tipo un historial sobre todo los sucesos del juego, que carta jugó cada uno y que es lo que se hizo, en orden cronológico.
mi tema es que al agregar una nueva línea se pone donde está el cursor y no al final.
ejemp: creo un campo edit (de solo lectura):

$ttl="cartas - Online: esperando por jugadores"
$online = GUICreate($ttl, 633, 454, 193, 125)
$texto="creaste una nueva sala de juego online."
$monitor = GUICtrlCreateEdit($texto, 16, 64, 593, 193, BitOR($ES_READONLY, $ES_WANTRETURN, $WS_VSCROLL, $ES_AUTOVSCROLL))

luego le agrego el texto que quiero mostrar a la variable $hist y con esta línea lo agrego al final:

GUICtrlSetData($monitor,$hist,1)

pero si el usuario se encuentra leyendo justo por el medio, agrega el texto ahí,, y no al final, como hago para obligar a que el cursor vaya al final del edit antes de agregar el nuevo texto?, así se va formando el historial en forma cronológica.

Re: problemas al crear un historial cronológico

Publicado: 10 Ago 2011, 09:41
por Ximorro
Lo que hay que hacer es posicionarse al final del Edit antes de insertar. Es fácil pero no evidente, porque se hace enviando un mensaje al control.

Para mandar mensajes a controles tenemos la función GUICtrlSendMsg(), que es la que voy a usar, pero te recomiendo que le eches un vistazo a la ayuda de la función ControlCommand(), que tiene integrado en AutoIt algunos mensajes muy usados, con lo que se hace más fácil acceder a esos valores.

Para ver qué mensajes acepta el Edit echa un vistazo a EditConstants.au3, en el apartado "Messages to send to edit control" tienes los mensajes específicos de este tipo de control. Con los nombres que ves ahí ya intuyes qué te puede servir, y con la inestimable ayuda de la MSDN ves exactamente qué hacen y cómo se usan.

Para colocarme al final uso el mensaje $EM_SETSEL, pasándole la posición del último carácter como inicio y final de selección.
http://msdn.microsoft.com/en-us/library ... 85%29.aspx

La posición del último carácter es lo mismo que el número de caracteres, así que en principio lo hacía leyendo el texto del control y viendo su longitud con StringLen(), pero dando vueltas por la MSDN me he encontrado el mensaje $WM_GETTEXTLENGTH, que no es específico de un ControlEdit, sino que es más genérico. Resulta que este mensaje ya está definido en WindowsConstants.au3, así que he incluido la librería en vez de especificarlo a mano.

Aunque parezca todo muy complicado en realidad lo único raro es lo de tener que usar $EM_SETSEL, y si acaso lo de $WM_GETTEXTLENGTH para la longitud, cosa que recomiendo porque así no hay que extraer el texto cada vez.

Lo extraño de todo este asunto es que suponía que después de insertar habría que poner el cursor otra vez en su sitio, pero flipo porque no hace falta :smt031 .
Me estaba pegando con $EM_GETSEL (con "get", no "set"), sacando la posición de la palabra baja y alta... pero me he dado cuenta de que sorprendentemente no hace falta...
De hecho no sólo mantiene la posición del cursor, sino también una selección, si la hay (eso es normal porque en este caso posición y selección es lo mismo). Lo que no comprendo para nada es que se mantenga si yo estoy cambiando esa selección para ponerme al final, ¡no lo entiendo! pero funciona, al menos en mi sistema.

Este es el código que he hecho para probarlo, mantengo el foco todo el rato en el Edit para que se vea el cursor continuamente (al insertar texto apretando un botón pierde el foco, cosa que no te pasará a ti porque vas insertando de otra manera):

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>

GUICreate("Insertar al final en Edit", 400, 300)
$texto = "Una línea." & @CRLF & "Otra línea." & @CRLF & "Y otra línea más."
$edit = GUICtrlCreateEdit($texto, 10, 10, 380, 250, BitOR($ES_READONLY, $ES_WANTRETURN, $WS_VSCROLL, $ES_AUTOVSCROLL))
$boton = GUICtrlCreateButton("Inserta línea al final", 140, 270, 120)
GUISetState()
GUICtrlSetState($edit, $GUI_FOCUS)

$lin = 1
While 1
	Switch GUIGetMsg()
		Case $boton
			;Buscamos posición final = tamaño del texto
			;$longitud = StringLen(GUICtrlRead($edit)) ;Mejor con mensajes como hago en la siguiente línea
			$longitud = GUICtrlSendMsg($edit, $WM_GETTEXTLENGTH, 0, 0)

			;Nos posicionamos en el final e insertamos
			GUICtrlSendMsg($edit, $EM_SETSEL, $longitud, $longitud)
			GUICtrlSetData($edit, @CRLF & "Inserto línea " & $lin, 1)
			$lin += 1

			GUICtrlSetState ($edit, $GUI_FOCUS) ;porque le ha quitado el foco el botón

		Case $GUI_EVENT_CLOSE
			ExitLoop
	EndSwitch
WEnd

Re: problemas al crear un historial cronológico

Publicado: 10 Ago 2011, 12:03
por Ximorro
Me ha picado la curiosidad y me he puesto a comprobar el rendimiento de mirar la longitud del texto del Edit con StringLen o con el mensaje WM_GETTEXTLENGTH.
Pues bien, como esperaba ¡es mucho mejor usar el mensaje!
Lo esperaba porque suponía que el mensaje no extrae el texto, como hay que hacer con el otro método.

Unas pruebas rápidas me dan por ejemplo para 500 caracteres, hacer la consulta 10000 veces:
StringLen: 40.2173 ms *** GUICtrlSendMsg: 25.011 ms

Lógicamente cuanto más texto más le cuesta al primer método... pero el del mensaje se queda igual, porque como no lo extrae no depende del tamaño (seguramente el control lo tiene almacenado en algún sitio para su gestión interna). Para 2000 caracteres me sale:
StringLen: 64.0509 ms *** GUICtrlSendMsg: 25.0818 ms

Para textos pequeños sigue siendo mejor con mensajes, con 50 caracteres:
StringLen: 33.3515 ms *** GUICtrlSendMsg: 25.0651 ms

Con CERO:
StringLen: 32.7913 ms *** GUICtrlSendMsg: 25.1474 ms

Re: problemas al crear un historial cronológico

Publicado: 10 Ago 2011, 18:08
por jamaro
Como siempre, una excelente explicación Ximorro. Ese oscuro y escondido mundo de los "mensajes".

¡Gracias por la clase!

Re: problemas al crear un historial cronológico

Publicado: 10 Ago 2011, 18:31
por Chefito
Una curiosidad que recuerdo de cuando programaba en vb.
Si pones en el primer parámetro un número negativo menor que -1 y en el segunto parámetro -1 o menos (lo suyo es -1, como indica en el msdn), tiene el mismo efecto que dice Ximorro pero sin necesidad de utilizar $WM_GETTEXTLENGTH.
Por ejemplo:

Código: Seleccionar todo

GUICtrlSendMsg($edit, $EM_SETSEL, -2, -1)
No hace falta mucha explicación. Ya lo dice ms, que si el último parámetro es -1 se coloca al final, y si el penúltimo es menor que -1 pues igual (cosecha propia :smt005 ).

Igualmente Ximorro se lo ha currado mucho. Yo no creo que lo hubiese hecho por mensajes. Soy más perro que el que :smt002 .

Saludos.

Re: problemas al crear un historial cronológico

Publicado: 11 Ago 2011, 08:33
por Ximorro
De nada jamaro. Me alegro de que sea útil.

Claro que si llega a verlo Chefito antes lo soluciona de un plumazo, qué tío, siempre nos enseña algo.
Aunque tengo que decir que a mí la MSDN no me parece nada clara con eso. Lo único que dice es que si el inicio es 0 y el final -1 se selecciona todo, y que si el inicio es -1 todo se deselecciona.
Parecían códigos especiales para seleccionar o deseleccionar todo, no dice expresamente que se posicione al final.
¿Y por qué -2,-1? ¿Por qué no -2,-2 o -1,-1? Vaya, de hecho -2,-2 funciona, pero -1,-1 no... ¿? Si -1 significa "al final", también debería funcionar, pero no. Este es el misterio número 2.

Je, con el cambio de Chefito ahora el código es ultra compacto, con lo que ha costado y ahora al ver la versión final parece una chorrada :smt005
En este caso $WM_GETTEXTLENGTH no hace falta, pero me lo apunto que ha sido un descubrimiento interesante. Ya no voy a volver a sacar el texto de un control para ver su longitud :smt023

Lo que sigo sin entender y de hecho no tiene ningún sentido, es el misterio número 1: que si cambiamos la posición del cursor, en este caso al final pero he comprobado que da igual donde ¿por qué después de hacer un inserción vuelve donde estaba? Yo flipo.

Demasiados misterios, como dice jamaro, este oscuro mundo de los mensajes... :smt021

Re: problemas al crear un historial cronológico

Publicado: 11 Ago 2011, 15:09
por taoru
muchas gracias por toda la ayuda!.
creo que me marié un poco en la explicación. pero con el ejemplo quedó mas entendido, ahora me pondré a leer un poco mas sobre el tema y hacer pruebas sobre este ejemplo para lograr entender bien.
gracias por la manito!,
saludos!

Re: problemas al crear un historial cronológico

Publicado: 11 Ago 2011, 21:03
por Chefito
Ximorro escribió:Claro que si llega a verlo Chefito antes lo soluciona de un plumazo, qué tío, siempre nos enseña algo.
jajajaja....que va. Si tu lo haces ya mejor que yo :smt002 .
Como ya te he dicho antes, yo soy más perro y le hubiese dado otra solución. Pienso que antes de haber tratado los mensajes directamente es mejor que le hubieses dicho que hay una udf llamada guiedit.au3 que trae autoit, en la ayuda con sus ejemplos (funciones que empiezan por _guictrledit_). Para alguien que no se quiera liar mucho con los mensajes, estas funciones es la mejor solución :smt002 . Además, si te das cuenta y miras los códigos de las funciones, logicamente están implementadas tratando los mensajes del edit. Pero no está mal enseñar a la gente a enviar mensajes a los objetos :smt003 , aunque en este caso no veo mucho la necesidad :smt001 . Os recomiendo que mireis la función _guictrledit_appendtext para este caso :smt002 .

Como siempre decimos, no inventemos lo que ya está inventado (el típico ejemplo de la rueda :smt003 ). Si ya está implementado en el propio lenguaje, con ayuda y ejemplos, para que molestarse en este caso? :smt003 .
Ximorro escribió:Aunque tengo que decir que a mí la MSDN no me parece nada clara con eso. Lo único que dice es que si el inicio es 0 y el final -1 se selecciona todo, y que si el inicio es -1 todo se deselecciona.Parecían códigos especiales para seleccionar o deseleccionar todo, no dice expresamente que se posicione al final.
Exacto. Por eso digo que es una curiosidad que sabía de hace tiempo. Ya lo digo en el mensaje, el último parámetro es de microsoft, y el penúltimo es cosecha propia :smt005 .
Ximorro escribió:¿Y por qué -2,-1? ¿Por qué no -2,-2 o -1,-1? Vaya, de hecho -2,-2 funciona, pero -1,-1 no... ¿? Si -1 significa "al final", también debería funcionar, pero no. Este es el misterio número 2.
Si lees detalladamente mi mensaje anterior digo que:
Chefito escribió:Si pones en el primer parámetro un número negativo menor que -1 y en el segunto parámetro -1 o menos (lo suyo es -1, como indica en el msdn)
Vamos, que digo lo que tu estás diciendo. Que vale cualquier número negativo en el primer parámetro excepto el -1 (menor que -1) y en el segunto vale cualquier negativo.
Y como ejemplo pongo -2 y -1, pudiendo haber puesto cualquier otra cosa.
Ximorro escribió:Lo que sigo sin entender y de hecho no tiene ningún sentido, es el misterio número 1: que si cambiamos la posición del cursor, en este caso al final pero he comprobado que da igual donde ¿por qué después de hacer un inserción vuelve donde estaba? Yo flipo.
Eso ya no lo se. Cosas que ocurren :smt005 .
Piensa que le das el foco por código. Por lo que he visto, no puedes ir con el tabulador a un edit, tienes que cliquearlo para darle el foco. Y según le cliquees se posiciona el cursor en un sitio u otro.
Tampoco me voy a calentar mucho la cabeza con esto, ya que no lo veo muy importante, por lo menos en este caso.

Saludos.

Re: problemas al crear un historial cronológico

Publicado: 12 Ago 2011, 08:59
por Ximorro
Ah, sí, también está GuiEdit.au3 ;-)

taoru, usa lo que veas más cómodo. Efectivamente échale un vistazo a la udf que encontrarás muchas cosas interesantes. En este caso si acabas entendiendo lo de los mensajes, dado lo simple del código utilizarlos directamente es una buena alternativa. La udf te lo da hecho pero para mi gusto es demasiada sobrecarga en este caso que se soluciona de forma tan sencilla.

Sí, Chefito, si tú lo has explicado muy bien, simplemente me preguntaba que si "-1" significa "al final", y como para posicionar el cursor sin seleccionar se usa inicio=fin de selección, por qué diablos -1,-1 no funciona. Es que no son coherentes...

Lo de mantenerse en posición creo que en este caso sí es importante porque comenta que el usuario está leyendo en una parte del Edit y él quiere insertar en otra. La cosa es no quitarle al usuario lo que está leyendo.
Y no hago clic para volver al Edit, eso efectivamente cambiaría el cursor a la posición de clic del ratón. Lo hago cambiándole el estado, y vuelve a la posición de antes de la inserción...
Y por cierto, por aclarar las cosas, sí puedes ir a un Edit con TAB, lo que pasa es que en este caso es de sólo lectura, y entonces sí que se lo salta. Si lo habilitas para edición sí que llega con TAB.

Re: problemas al crear un historial cronológico

Publicado: 12 Ago 2011, 16:07
por Chefito
Ximorro escribió:Sí, Chefito, si tú lo has explicado muy bien, simplemente me preguntaba que si "-1" significa "al final", y como para posicionar el cursor sin seleccionar se usa inicio=fin de selección, por qué diablos -1,-1 no funciona. Es que no son coherentes...
Pues el -1 no funciona porque, como tu bien has comentado en un post anterior, microsoft ha dicho que es para deseleccionar lo que esté seleccionado. Como se le ha asignado esa función, pues no vale.....no hay tu tía :smt005 .
Ximorro escribió:Y por cierto, por aclarar las cosas, sí puedes ir a un Edit con TAB, lo que pasa es que en este caso es de sólo lectura, y entonces sí que se lo salta. Si lo habilitas para edición sí que llega con TAB.
Jajajaja....menudo despistado :smt021 :smt015 :smt005 . No le miré los estilos al edit. Creía que había encontrado un supermegabug :smt005 :smt005 . Por desgracia, todos nos equivocamos.....y solemos hacerlo mucho :smt002 . Para eso están los compis. Gracias por la corrección Ximorro :smt002 .
Ximorro escribió:Lo de mantenerse en posición creo que en este caso sí es importante porque comenta que el usuario está leyendo en una parte del Edit y él quiere insertar en otra. La cosa es no quitarle al usuario lo que está leyendo.
Ok ok. He investigado un poco y parece que el problema está en que se le debe dar el foco antes de trabajar con él, no después. Os dejo la corrección:

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>

GUICreate("Insertar al final en Edit", 400, 300)
$texto = "Una línea." & @CRLF & "Otra línea." & @CRLF & "Y otra línea más."
$edit = GUICtrlCreateEdit($texto, 10, 10, 380, 250, BitOR($ES_READONLY, $ES_WANTRETURN, $WS_VSCROLL, $ES_AUTOVSCROLL))
$boton = GUICtrlCreateButton("Inserta línea al final", 140, 270, 120)
GUISetState()
GUICtrlSetState($edit, $GUI_FOCUS)

$lin = 1
While 1
   Switch GUIGetMsg()
      Case $boton
         ;Buscamos posición final = tamaño del texto
         ;$longitud = StringLen(GUICtrlRead($edit)) ;Mejor con mensajes como hago en la siguiente línea
;~          $longitud = GUICtrlSendMsg($edit, $WM_GETTEXTLENGTH, 0, 0)
         GUICtrlSetState ($edit, $GUI_FOCUS) ;porque le ha quitado el foco el botón

         ;Nos posicionamos en el final e insertamos
         GUICtrlSendMsg($edit, $EM_SETSEL, -2, -1)
         GUICtrlSetData($edit, @CRLF & "Inserto línea " & $lin, 1)
         $lin += 1

      Case $GUI_EVENT_CLOSE
         ExitLoop
   EndSwitch
WEnd
No ha estado mal el post. Hemos descubierto como mantener la posición del cursor y como reposicionarlo :smt005 .

EDITO: Mirar lo que he encontrado buscando en el foro de habla inglesa información para otro post. Son interesantes los códigos de Melba23 y Yashied: http://www.autoitscript.com/forum/topic ... line-edit/

Saludos.

Re: problemas al crear un historial cronológico

Publicado: 16 Ago 2011, 09:22
por Ximorro
No entiendo lo de la corrección del foco, a mí me funcionaba de maravilla, el cursor se mantenía en su sitio... ¿Es que no te iba?
De hecho sin darle el foco también funcionaba, lo que pasa es que no ves el cursor, pero vi que volvía a su sitio. Al darle el foco simplemente el cursor se hace visible, pero estar igualmente estaba ahí.
No sé si me he explicado, no decía que no funcionara, sino que no entiendo por qué funciona, porque si hemos cambiado la posición para insertar, no entiendo por qué luego vuelve a donde estaba, debería quedarse al final... ¿?
Pero se quedaba donde queríamos sin cambiar nada del foco, al menos en mi XP

Interesante cómo usar EM_GETSEL, ahí me quedé, pensando cómo pasar las variables por referencia, pero como se posicionaba bien no me molesté en seguir mirándolo. Melba23 usa _GUICtrlEdit_GetSel(), donde he visto que se crea una estructura para cada coordenada, aunque sea un simple entero, pero así luego pueden pasarlo por referencia con DllStructGetPtr.
No hace falta complicarse porque la librería da las funciones necesarias, pero interesante mecanismo que habrá que tener en cuenta.

La de cosas que he aprendido en este post ;-)

Insertar texto edit y mantener posicion cursor o poner al fi

Publicado: 16 Ago 2011, 11:05
por Chefito
Jejejeje....vale vale. Sí me mantiene la posición con tu código. Otra vez te entendí mal. Creía que no querías mantener la posición, que debía cambiar a donde se insertaba el texto. Serán las vacaciones las que me ponen la cabeza loca? No tendría que ser al revés? :smt005 :smt005 .
Bueno, por lo menos, como dije en el post anterior, ya sabemos como mantener la posición y como darle la última del texto insertado. Nunca se sabe si podremos necesitar una u otra.

Saludos.

Re: problemas al crear un historial cronológico

Publicado: 16 Ago 2011, 12:34
por Ximorro
Si esto es bueno, significa que estás consiguiendo desconectar en vacas. No se te va la olla, es que está en modo relax :smt015

Yo de ser taoru (si es que aún está por aquí después de tanto marearle :smt005 ) aunque parece que funciona sin hacer nada, me aseguraría de que el cursor vuelve al sitio, usando lo de _GUICtrlEdit_GetSel() y _GUICtrlEdit_SetSel() (o equivalentes). Quién sabe si el otro comportamiento tan extraño algún día dejará de funcionar...

Re: problemas al crear un historial cronológico

Publicado: 04 Mar 2012, 04:19
por taoru
hola!, gracias por su enooorme ayuda siempre!.
perdón, entre la universidad y el trabajo me dejaron sin tiempo...ensima luego me enfrenté a un problema, el tema de comunicarse entre sockets, pero ya con esta gran ayuda, ya voy un paso adelante.

ya puse esta solución y la verdad que queda todo un historial visible y recorrible con el lector de pantalla.

gracias gracias!

Re: problemas al crear un historial cronológico

Publicado: 05 Mar 2012, 09:29
por Ximorro
¡Hace 8 meses de esto!
Ya no sabía ni de qué iba, creía que te habías equivocado de entrada al comentar ;-)

Bueno pues me alegro de que haya servido, después de la investigación que le pegamos.