Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Detectar tipo de componente en aplicación externa (https://www.clubdelphi.com/foros/showthread.php?t=78797)

BrunoBsso 17-05-2012 16:05:56

Detectar tipo de componente en aplicación externa
 
Hola foro, qué tal?
Estuve googleando esto y buscando en los foros, pero ni siquiera encontré algo que se asemeje a lo que busco.
Tengo una aplicación que hace una carga automática de datos sobre una plataforma hecha en JavaScript + C#.Net + JSP + no sé qué otro lenguaje, todo en una página web. Yo supongo que está hecha en esos lenguajes y no tengo forma de comprobarlo.
Mi aplicación se basa en clickear algunos botones para abrir formularos, pegar texto con CopyPaste, settear el cursor sobre campos de texto y pegar otro texto, clickear OK, etc.
Todo eso lo hace correctamente, pero el problema está en que se hace a través de máquinas virtuales montadas en servidores con conexión por internet, así que cuando la conexión es un poco lenta tengo el problema de que no sé si cuando hice el proceso de "Posicionar cursor sobre campo de texto > Clickear" se haya hecho correctamente. Hice unos métodos que detectan si se abrió X ventana, si el cursor está posicionado donde debe y otras validaciones más. Pero no encuentro la forma de saber si tengo el "foco de Windows" sobre un campo de texto o no. ¿Se entiende? No tengo forma certera de saber si cuando hice "Posicionar cursor sobre campo DESCRIPTION > Hacer click" efectivamente se hizo el click y el foco está puesto sobre dicho campo de texto.
Mi duda es si habrá alguna forma, por más rebuscada que sea, de verificar que el "foco de Windows" (no sé si se dirá así, por eso las comillas) está posicionado sobre un campo de texto para decirle a mi aplicación "listo amigo, ahora podés escribir". Ojalá alguno tenga una idea loca que me lo solucione.

Cualquier duda sobre mi aplicación que les parezca necesaria para entender mejor me avisan.

Saludos y gracias a cualquiera que se vaya a quemar las neuronas un rato por mí jeje!!!
Y si a ninguno se le ocurre nada bueno, no pasa nada, no se empeora la situación ;)

ElDioni 17-05-2012 17:21:01

Hola, yo no se si entiendo lo que quieres hacer, puede que en este hilo encuentres un poco de luz.

http://www.clubdelphi.com/foros/showthread.php?t=26354

Saludos.

BrunoBsso 17-05-2012 17:28:39

Cita:

Empezado por ElDioni (Mensaje 432808)
Hola, yo no se si entiendo lo que quieres hacer, puede que en este hilo encuentres un poco de luz.

http://www.clubdelphi.com/foros/showthread.php?t=26354

Saludos.

Gracias ElDioni, pero lo que yo necesito es conocer el tipo de campo en una aplicación externa, y eso es para la aplicación propia.
El tema sería yo tengo mi aplicación A y además está abierta la aplicación B que no es mía.
Yo desde A hago que el cursor se posicione sobre un campo de texto en B, se hace doble click y por teoría el campo B.CampoDeTexto debe quedar seleccionado. La idea sería poder hacer A.IsCampoTexto(B.CampoFocuseado) para asegurarme que la ventana no se movió, que la velocidad de conexión no hizo que se "perdiera" el doble click y que el campo no se haya seleccionado, etc.
Voy a ver si encuentro alguna manera de hacer eso mediante el handle (que lo tengo).

Saludos.

roman 17-05-2012 17:51:04

¿No te serviria usar GetFocus() para encontrar la ventana con el foco y luego GetClassName para encontrar el nombre de la clase de dicha ventana ?

// Saludos

BrunoBsso 17-05-2012 19:19:18

Cita:

Empezado por roman (Mensaje 432813)
¿No te serviria usar GetFocus() para encontrar la ventana con el foco y luego GetClassName para encontrar el nombre de la clase de dicha ventana ?

// Saludos

La ventana sé 100% que está focuseada, porque la abro yo programáticamente y además hice un método WaitUntilWindowOpen que me avisa cuando está abierta. Además, tengo el handle de la ventana siempre a mano. ¿Con GetClassName no obtendría solamente el nombre de la clase de la ventana? Yo necesito saber si el componente actual donde esté seteado el foco es un componente de texto o no.
La ventana que se abre tiene un campo tipo TEdit para "Nombre", un campo tipo TMemo para "Descripción", uno tipo TMemo para "Resultados" y tres botones. Yo sé que posiciono el cursor sobre el campo "Descripción" porque al hacer SetCursorPos(X,Y) uso otro método WaitUntilCursorPos(X, Y) para validarlo. Luego de eso simulo un doble click. El asunto es que no tengo un "WaitUntilTextAreaFocused", que eso sería lo que necesito. Al hacer el doble click (el campo ese de texto se activa con doble click) no tengo la certeza de que se hayan efectuado correctamente los 2 clicks, no tengo la certeza de que en esa ventana el foco esta seteado en ese componente.
Creo que no se entiende porque mientras lo escribo me parece que no puedo dejarlo claro jaja

Saludos.

roman 17-05-2012 19:34:12

Un Edit también es una ventana. De hecho, todo TWinControl es una ventana, y sólo una ventana puede tener el foco. Entonces, si tienes un formulario con un Edit dentro y seleccionas éste, la ventana con el foco es el Edit, no el formulario.

Haz la prueba, poniendo este código en un SpeedButton (para que el clic en el botón no te mueva el foco):

Código Delphi [-]
var
  Buffer: array[Byte] of Char;

begin
  ZeroMemory(@Buffer, SizeOf(Buffer));
  GetClassName(GetFocus(), Buffer, 255);
  ShowMessage(Buffer);
end;

Verás que el nombre de lcase que obtienes es el del control seleccionado.

// Saludos

BrunoBsso 17-05-2012 19:40:57

Cita:

Empezado por roman (Mensaje 432829)
Un Edit también es una ventana. De hecho, todo TWinControl es una ventana, y sólo una ventana puede tener el foco. Entonces, si tienes un formulario con un Edit dentro y seleccionas éste, la ventana con el foco es el Edit, no el formulario.

Haz la prueba, poniendo este código en un SpeedButton (para que el clic en el botón no te mueva el foco):

Código Delphi [-]
var
  Buffer: array[Byte] of Char;

begin
  ZeroMemory(@Buffer, SizeOf(Buffer));
  GetClassName(GetFocus(), Buffer, 255);
  ShowMessage(Buffer);
end;

Verás que el nombre de lcase que obtienes es el del control seleccionado.

// Saludos

En este momento no puedo, pero ni bien pueda lo pruebo. No tenía idea que todo TWinControl era una ventana, me dejaste pasmado.
Mil gracias roman!

BrunoBsso 18-05-2012 14:58:10

Hola. Espero que este mensaje no lo tomen como un mensaje basura. Vengo a avisar solamente que todavía no pude probar la solución de roman porque estoy tapado de trabajo. Solamente eso, así no piensan que solucioné mi problema sin explicar cómo.

Saludos!

BrunoBsso 20-05-2012 21:59:37

Bueno, les comento que ya solucioné mi problema. Chau.



















Jajaja no me voy a ir así nomás :p

Lo solucioné con la ayuda de roman haciendo un leve cambio. En vez de utilizar GetFocus() usé una variable THandle y le asigné la ventana con GetForegroundWindow.
Les muestro precisamente cómo quedó y cómo funciona:
Código Delphi [-]
procedure TForm1.WaitUntilFieldFocused(sFieldName: String);
var
  Handle: THandle;
  Buffer: array[Byte] of Char;
begin
  Handle := GetForegroundWindow;
  Buffer := '';
  while (Buffer <> sFieldName) do
  begin
    ZeroMemory(@Buffer, SizeOf(Buffer));
    GetClassName(Handle, Buffer, 255);
    Sleep(250);
  end;
end;

Solamente recibe el nombre (que lo obtuve usando otra mini aplicación con GetClassName(Handle, Buffer, 255) y las mismas variables) y espera hasta que aparece focuseado, que por la lógica de mi aplicación es 100% seguro que va a estar focuseado aunque tarde mucho tiempo.
El procedimiento lee el nombre del TWinControl (agradecimiento enorme a roman por explicarme que todo componente es una ventana ;) ) y lo compara con el nombre que le pedís que encuentre. Si no lo encuentra se pausa 0.0250 segundos y vuelve a mirar. Nada más, muy simple.

Muchas gracias a los que aportaron, a los que lo leyeron y no pudieron responder pero pensaron a ver si se les ocurría algo, a todos.

Si algún moderador pudiera editar el nombre del topic y ponerle al principio "[RESUELTO]" y cerrarlo sería grandioso y que quede como ejemplo :D

Saludos!!!!!!!!!!!!!!

roman 21-05-2012 18:12:02

Pero tú código no puede funcionar tal como está. La obtención del Handle debe estar dentro del ciclo.

// Saludos

BrunoBsso 22-05-2012 03:39:59

Cita:

Empezado por roman (Mensaje 433104)
Pero tú código no puede funcionar tal como está. La obtención del Handle debe estar dentro del ciclo.

// Saludos

El código funciona tal como está. Handle := GetForegroundWindow; me devuelve el handle de una ventana que acabo de abrir. Después de abrir esa ventana hago doble click sobre el componente de texto. En ese momento tengo 100% asegurado que la ventana está abierta, focuseada y ontop, y que hice doble click en el componente de texto. Lo único que resta esperar es que se focusee ese campo de texto.
El handle lo agarro con GetForegroundWindow sí o sí, porque la ventana abierta y activa es la que tiene el componente.
No te preocupes, ya lo probé y funciona como debe.

Saludos.

escafandra 22-05-2012 08:05:31

Concuerdo con roman al advertir que ese código tiene algo que llama la atención. Handle tiene el valor de la ventana que deseas siempre que le de tiempo a estar abierta en ese momento. Pero el código, tal como está me hace pensar que o bien el bucle sobra, o la obtención del Hanle debe realizarse dentro del mismo. Si la función pretende esperar a que el nombre de la clase del Handle obtenido sea el que esperas, entonces tu función debe ser modificada a algo como esto:

Código Delphi [-]
procedure TForm1.WaitUntilFieldFocused(sFieldName: String);
var
  Handle: THandle;
  Buffer: array[Byte] of Char;
begin
  Buffer := '';
  while (Buffer <> sFieldName) do
  begin
    Handle := GetForegroundWindow;
    ZeroMemory(@Buffer, SizeOf(Buffer));
    GetClassName(Handle, Buffer, 255);
    Sleep(250);
  end;
end;

Saludos.

BrunoBsso 22-05-2012 14:49:47

Cita:

Empezado por escafandra (Mensaje 433161)
Concuerdo con roman al advertir que ese código tiene algo que llama la atención. Handle tiene el valor de la ventana que deseas siempre que le de tiempo a estar abierta en ese momento. Pero el código, tal como está me hace pensar que o bien el bucle sobra, o la obtención del Hanle debe realizarse dentro del mismo. Si la función pretende esperar a que el nombre de la clase del Handle obtenido sea el que esperas, entonces tu función debe ser modificada a algo como esto:

Código Delphi [-]
procedure TForm1.WaitUntilFieldFocused(sFieldName: String);
var
  Handle: THandle;
  Buffer: array[Byte] of Char;
begin
  Buffer := '';
  while (Buffer <> sFieldName) do
  begin
    Handle := GetForegroundWindow;
    ZeroMemory(@Buffer, SizeOf(Buffer));
    GetClassName(Handle, Buffer, 255);
    Sleep(250);
  end;
end;

Saludos.

Escafandra, el bucle en esa función es solamente para darle tiempo al SO de mostrar bien la ventana dado que todo el proceso es a través de máquinas virtuales.
El handle, por otra parte, lo consigo correctamente y sin problemas porque justo antes de entrar en la función abro la ventana. No entiendo por qué les cuesta tanto creer que funciona perfectamente...

maeyanes 22-05-2012 15:37:34

Hola...

Será que es por que si en ese preciso momento alguna otra ventana se coloca al frente (un popup de alguna otra aplicación), tu método puede recibir el handle de la ventana incorrecta y fallar.


Saludos...

roman 22-05-2012 15:46:46

Cita:

Empezado por BrunoBsso (Mensaje 433180)
No entiendo por qué les cuesta tanto creer que funciona perfectamente...

No es una cuestión de creer o no creer. Todas las vueltas de tu bucle se ejecutan con exactamente el mismo contexto. GetClassName obtendrá siempre el mismo valor, así que no tiene ningún caso estar calculándolo una y otra vez. Quizá lo que tenga algo que ver es el sleep, o simplemente el ligero tiempo que toma entrar al bucle, pero, desde luego, no la llamada reiterada a GetClassName.

Pero, en todo caso, si así te sirve, pues ¿quiénes somos nosotros para contradecirte? :)

// Saludos

BrunoBsso 22-05-2012 16:09:30

Cita:

Empezado por roman (Mensaje 433183)
No es una cuestión de creer o no creer. Todas las vueltas de tu bucle se ejecutan con exactamente el mismo contexto. GetClassName obtendrá siempre el mismo valor, así que no tiene ningún caso estar calculándolo una y otra vez. Quizá lo que tenga algo que ver es el sleep, o simplemente el ligero tiempo que toma entrar al bucle, pero, desde luego, no la llamada reiterada a GetClassName.

Pero, en todo caso, si así te sirve, pues ¿quiénes somos nosotros para contradecirte? :)

// Saludos

Exactamente lo que tiene que ver ahí es el Sleep(250) por el retardo que tienen las VM que uso. GetClassName debería devolver siempre el mismo valor, pero ese bucle es solamente una forma de asegurarse de que ya lo tiene focuseado. Al hacer doble click sobre el componente de texto (en el caso de un usuario interactuando con la plataforma) el componente tarda unos instantes en focusearse, por eso mi aplicación pone ese bucle que en definitiva solamente espera hasta que Buffer sea el nombre del componente que acabo de clickear.

BrunoBsso 22-05-2012 16:12:54

Cita:

Empezado por maeyanes (Mensaje 433181)
Hola...

Será que es por que si en ese preciso momento alguna otra ventana se coloca al frente (un popup de alguna otra aplicación), tu método puede recibir el handle de la ventana incorrecta y fallar.


Saludos...

Ese caso está contemplado en otra porción de código que detecta los pop-ups y los cierra, así que si aparece un pop-up la aplicación lo va a cerrar y el bucle va a seguir utilizando el handle de la ventana correspondiente. Se puede poner el Handle := GetForegroundWindow; dentro del bucle, pero no quise dar más instrucciones a un bucle que se ejecutará como máximo máximo (por la lentitud de las VM) 3 veces.

Igualmente, más allá de que los pop-ups están contemplados, la plataforma con la que trabaja la aplicación es OnTop y en ese preciso momento no tiene forma de devolver ningún pop-up. Es decir, los únicos pop-ups/raise que tira son en otras circunstancias, como por ejemplo al presionar botones.

roman 22-05-2012 16:29:52

Cita:

Empezado por BrunoBsso (Mensaje 433189)
por eso mi aplicación pone ese bucle que en definitiva solamente espera hasta que Buffer sea el nombre del componente que acabo de clickear.

Esto es lo que no es cierto. Tu programa está funcionando debido al sleep. El valor de Buffer es el mismo que obtienes desde que llamaste a GetForegroundWindow. Si, por alguna razón, Buffer no tuviera el valor que esperas, nunca lo obtendrá dentro del ciclo y éste jamás terminará.

Por otro lado, hay algo que no queda claro. Si tú tienes un formulario con un control de edición, GetForegroundWindow y GetFocus no devuelven lo mismo. El primero te devolverá el formulario y el segundo el control de edición.

Seguramente percibes que tu programa funciona bien, y me alegro por ello. Pero cuando algo funciona por las razones equivocadas, habría que poner atención en ello en lugar de obstinarse, pues en algún momento o circunstancia, te puede fallar.

// Saludos

BrunoBsso 22-05-2012 19:17:36

Cita:

Empezado por roman (Mensaje 433198)
Esto es lo que no es cierto. Tu programa está funcionando debido al sleep. El valor de Buffer es el mismo que obtienes desde que llamaste a GetForegroundWindow. Si, por alguna razón, Buffer no tuviera el valor que esperas, nunca lo obtendrá dentro del ciclo y éste jamás terminará.

Por otro lado, hay algo que no queda claro. Si tú tienes un formulario con un control de edición, GetForegroundWindow y GetFocus no devuelven lo mismo. El primero te devolverá el formulario y el segundo el control de edición.

Seguramente percibes que tu programa funciona bien, y me alegro por ello. Pero cuando algo funciona por las razones equivocadas, habría que poner atención en ello en lugar de obstinarse, pues en algún momento o circunstancia, te puede fallar.

// Saludos

Empecemos por no llamarme obstinado, no hay por qué.
Con el procedimiento WaitUntilFieldFocused intento poner un modo de asegurar que esté seleccionado el campo, nada más. Es muy probable que sea innecesario ese procedimiento, pero lo uso para asegurarme que ningún retraso o lag del SO interfiera con lo que hago.
GetForegroundWindow lo uso para obtener el handle de la ventana como varias veces dije. En ningún momento usé el GetFocus. El handle lo llamo desde ahí solamente para poder pasárselo al GetClassName, pero en todo momento sé cuál es el handle, antes y después del procedimiento.
Entonces, si GetClassName me pide un handle, guardo en una variable el handle de la ventana que abrí yo mismo. Como GetClassName me va a devolver el nombre del campo de texto, antes de llamar al procedimiento hago doble click en ese campo de texto. Teóricamente siempre que llame a WaitUntilFieldFocused voy a estar en ese campo de texto, por lo que teóricamente no es necesario. Pero repito que es pura y exclusivamente para asegurarme.

Remarco, dejá de llamar obstinados a las personas porque no hagan las cosas de la misma manera que vos lo harías. No podemos ser todos tan perfectos como vos.
Tu actitud me hace recordar un topic sobre los users que no aparecen más por el foro, y que la gran mayoría se fueron a otros foros. Tal vez debas rever tu actitud para con las personas.

Hasta acá llegaron mis ganas de usar este foro. Ya me encontré anteriormente con vos y otros users "sabiondos" que se ponen en posición absolutamente pedante y rebajan a los que preguntan. Eso no es un foro.

Suerte a todos.


FIN


La franja horaria es GMT +2. Ahora son las 01:13:40.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi