Del básico al intermedio: Eventos de mouse
Introducción
En el artículo anterior, Del básico al intermedio: Puntero a función, hablamos sobre cómo implementar eventos en un script. Pero, sobre todo, se explicó cómo podemos utilizar un tipo de dato muy especial. El conocido puntero. Como quiero, y pretendo, que tú, mi querido lector, estudies con mucha calma lo que se mostró en el artículo anterior, ya que ese tipo de cosas es muy importante, sobre todo si pretendes profundizar en programación que hace uso de objetos gráficos, en este artículo actual vamos a centrarnos en otra cosa, un poco más simple.
El tema principal aquí será objetos y eventos de mouse. Para mantener las cosas debidamente separadas, vamos a empezar por lo que será el primer tema de este artículo.
Eventos de mouse
Bien, empecemos por entender una cosa: el mouse es un ser idiota, molesto, horroroso y salido de lo más profundo de los infiernos. Es algo completamente aleatorio y sin ningún tipo de consideración, tanto por el código como por el programador. Aunque es algo muy útil y nos permite bastante agilidad cuando se trata de interfaz gráfica, MetaTrader 5 no genera por defecto eventos de mouse para ninguna aplicación que se ejecute en la plataforma. ¿Pero por qué? El motivo es justamente que MetaTrader 5 tiene como objetivo ser una plataforma con excelente performance y rendimiento. Y el mouse, bueno, el mouse acaba interfiriendo en eso. Sobre todo cuando las aplicaciones colocadas en el gráfico tienden a estar muy mal optimizadas para eventos relacionados con el mouse.
Tal vez tú, mi querido y estimado lector, no tengas una idea clara de cuánto pueden llegar a ser un problema los eventos de mouse cuando una aplicación está mal optimizada para manejarlos. Sin embargo, a lo largo de los artículos veremos esto más de cerca. Pero, antes, necesitamos entender otras cosas.
La primera de ellas será algo que quizá estés pensando: Bien, mi buen amigo autor, creo que puedes estar equivocado en cuanto al uso del mouse en la plataforma. Cuando presionamos el botón derecho sobre un gráfico, tenemos acceso a un conjunto de cosas que podemos usar allí de inmediato. Además, podemos enviar y manipular órdenes usando para ello el recurso One Click de MetaTrader 5. Entonces, eso de decir que el mouse es un problema no pasa de ser pura falta de conocimiento por tu parte.
Bien, debo estar de acuerdo contigo. Tienes razón en esta afirmación, mi querido lector. Sin embargo, yo no dije que el mouse sea un problema para la plataforma. Dije que el mouse es un problema para las aplicaciones que se ejecutan en un gráfico. Más aún cuando el manejador de eventos de esa aplicación está mal optimizado. O, como mínimo, muy desordenado. Y, cuanto mayor es el código, mayor es el desorden. Por eso, siempre procuro crear código relativamente corto y buscar la simplicidad por encima de todo. Y el motivo es precisamente este: evitar tener un código mal optimizado por alguna negligencia de mi parte.
Siguiente punto: como MetaTrader 5 no dispara por defecto eventos de mouse para las aplicaciones que se ejecutan en un gráfico, siempre nos vemos obligados a implementar código que garantice, o le indique a MetaTrader 5, que queremos recibir eventos de mouse. Y, una vez registrado que un gráfico deberá recibir eventos de mouse, tú, como programador, al implementar un código que haya activado el evento de mouse en MetaTrader 5, necesitas indicarle, cuando la aplicación se cierre, que los eventos de mouse deben desactivarse.
Lo que, la mayoría de las veces, no ocurre. Esto hace que MetaTrader 5 siga disparando eventos de mouse para el gráfico, porque tu aplicación no desactivó lo que había activado antes. Así que sé educado y organizado. Si lo activaste, desactívalo. No esperes que la plataforma encuentre la manera de resolver el problema por ti.
Siguiente punto: no intentes activar ni usar más recursos de los necesarios. Existen pequeñas diferencias entre los eventos que MetaTrader 5 genera al disparar eventos de mouse. Si tu aplicación no necesita utilizar ciertos recursos, no los actives. Mantén todo simple y básico. Activa solo aquello que realmente necesitas usar.
Bien, esta breve introducción, aunque pueda parecer un poco brusca, realmente debe exponerse de forma clara. Para que tú, que estás aprendiendo a programar, empieces tu carrera de la manera correcta. Ya he visto a mucha gente hacer cosas más allá de lo necesario y luego quejarse de que el programa va lento o no tiene el rendimiento esperado.
Cuando nos detenemos a ver qué ocurre, acabamos notando que el problema es el exceso de recursos asignados de forma completamente innecesaria. Al eliminar las partes innecesarias, la aplicación, como por arte de magia, pasa a tener el rendimiento esperado. Y no me estoy refiriendo necesariamente a programas para MetaTrader 5. Hablo de esto de forma general.
Bien, entonces vamos a empezar, teniendo en cuenta que los eventos de mouse solo pueden ser capturados por el manejador OnChartEvent. Por lo tanto, solo dos tipos de aplicación pueden capturar eventos de mouse. Uno sería el Asesor Experto, que trataremos más adelante. Y el otro sería un indicador. Pero todo lo que se diga aquí también se aplica al Asesor Experto, ya que todo estará dirigido al manejador de eventos OnChartEvent. Es importante que entiendas esto, mi querido lector, para que no te quedes pensando: Vaya, explicaste cómo trabajar con el mouse en un indicador. Sin embargo, todavía no explicaste cómo hacer esto en un Asesor Experto.
Todo comienza con el código que se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_Prefix "Demo" 05. //+------------------------------------------------------------------+ 06. int OnInit() 07. { 08. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 09. 10. return INIT_SUCCEEDED; 11. }; 12. //+------------------------------------------------------------------+ 13. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 14. { 15. return rates_total; 16. }; 17. //+------------------------------------------------------------------+ 18. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 19. { 20. switch (id) 21. { 22. case CHARTEVENT_MOUSE_MOVE: 23. break; 24. case CHARTEVENT_MOUSE_WHEEL: 25. break; 26. } 27. }; 28. //+------------------------------------------------------------------+ 29. void OnDeinit(const int reason) 30. { 31. }; 32. //+------------------------------------------------------------------+
Código 01
Aquí tenemos lo que podríamos llamar el esqueleto básico de un indicador que utilizará el mouse en sus operaciones. Presta atención a lo siguiente: dentro del manejador de eventos OnChartEvent, tenemos dos tipos de eventos de mouse que pueden capturarse. El primero es el que aparece en la línea 22 y el segundo, en la línea 24. El hecho de que uses un evento u otro no influye en cómo se ejecutará o compilará el código. Sin embargo, tal como está este código, MetaTrader 5 no disparará ninguno de estos dos eventos en ningún momento. Esto se debe a que ambos están desactivados por defecto. Para que OnChartEvent reciba uno de estos dos eventos, necesitamos activar el tipo de evento que queremos recibir.
Activar y desactivar estos eventos es algo muy simple y fácil de hacer. Sin embargo, la forma de manejar estos eventos es un poco diferente. El evento CHARTEVENT_MOUSE_WHEEL, por algún motivo, tiene un funcionamiento ligeramente distinto del evento CHARTEVENT_MOUSE_MOVE. Pero no te preocupes por eso en este momento. Pronto lo entenderás y hasta te divertirás pensando en cómo usar el mouse en cada vez más aplicaciones, de distintas maneras. Porque, bien programado, es una herramienta muy útil y versátil. Más aún en una plataforma gráfica.
Muy bien, para que podamos ver el mouse en acción y, así, entender diversas otras cosas que resultan más fáciles de comprender cuando las vemos ocurrir, vamos a activar uno de los eventos de mouse y, al mismo tiempo, vamos a imprimir algunas cosas directamente en el gráfico. Así, aprenderás en la práctica cómo funciona realmente. Para ello, vamos a modificar el código 01 para convertirlo en el código 02, que se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_Prefix "Demo" 05. //+------------------------------------------------------------------+ 06. int OnInit() 07. { 08. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 09. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 10. 11. return INIT_SUCCEEDED; 12. }; 13. //+------------------------------------------------------------------+ 14. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 15. { 16. return rates_total; 17. }; 18. //+------------------------------------------------------------------+ 19. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 20. { 21. string sz = ""; 22. 23. switch (id) 24. { 25. case CHARTEVENT_MOUSE_MOVE: 26. Comment(sz); 27. sz += "Mouse position X: " + (string)(short)lparam; 28. sz += "\nMouse position Y: " + (string)(short)dparam; 29. Comment(sz); 30. break; 31. case CHARTEVENT_MOUSE_WHEEL: 32. break; 33. } 34. }; 35. //+------------------------------------------------------------------+ 36. void OnDeinit(const int reason) 37. { 38. Comment(""); 39. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 40. }; 41. //+------------------------------------------------------------------+
Código 02
Cuando este código 02 se ejecute en un gráfico, verás un resultado parecido al que aparece en la siguiente animación.

Animación 01
Observa, en la esquina superior izquierda, que, a medida que movemos el mouse, la indicación de dónde está irá cambiando. Sin embargo, hay regiones en las que la indicación no cambiará. ¿Por qué? El motivo es que esas regiones en las que notas que la indicación de posición no cambia quedan fuera de lo que se considera la región del área cliente.
Y sí, mi querido lector, una ventana gráfica se divide en regiones. Este tipo de cosas se ve cuando se estudia programación para entornos gráficos, como la programación para crear aplicaciones Windows, por ejemplo. Es algo con muchos detalles involucrados. Sin embargo, intentaré simplificar al máximo lo que necesita explicarse. De esta manera, podrás entender qué es realmente importante aquí para programar en MQL5.
En una interfaz gráfica, como ocurre en el sistema operativo Windows, tenemos una región inmensa llamada Desktop. O, para los legos, área de pantalla. Cada píxel de esta región corresponde a una posición en esa llamada área de Desktop. Bien, dentro de esta región, inicialmente tenemos otras dos. Una es la región donde se encuentra la barra de tareas, y la otra es la región donde estarán las ventanas de las aplicaciones. No importa si tu configuración ocultará o no esa región que corresponde a la barra de tareas. Cualquier cosa fuera de ella se considera región de aplicación.
Bien, para que esto resulte más plausible, piensa en el siguiente ejemplo: supongamos que estás en una pantalla de 1920 x 1080 píxeles, es decir, una pantalla Full HD. Si la región de la barra de tareas ocupa 48 píxeles, entonces el área útil de tu pantalla será de 1920 x 1032 píxeles. Así, cualquier aplicación que esté en una ventana maximizada y con la barra de tareas visible podrá ocupar estas dimensiones mencionadas hace un momento, es decir, menos que la pantalla Full HD. El efecto es casi imperceptible. Pero, como curiosidad, si estás viendo una imagen de 1920 x 1080 píxeles en esta pantalla un poco menor, quedará ligeramente diferente, ya que tenemos que compensar los 48 píxeles que faltan.
Bien, dentro de esta área cliente, que normalmente se configura como el cuarto cuadrante, y más adelante hablaremos sobre esta cuestión de los cuadrantes, podemos colocar ventanas de programas. Esta ventana también tiene regiones. Básicamente, hay tres regiones que deben considerarse. La primera región es la barra de título, la segunda es el borde de la ventana y la tercera es el área cliente.
Del mismo modo que el Desktop, estas ventanas van quedando cada vez más pequeñas, ya que cada región que no forme parte del área cliente restará área útil disponible. El área que realmente podemos usar es precisamente aquella que hace que el valor de la posición del mouse cambie, y va desde 0 x 0, que se encuentra en la esquina superior izquierda, hasta un valor máximo cualquiera, que se encuentra en la esquina inferior derecha. Esto ocurre cuando usamos el modelo de trazado estándar, que se encuentra en el cuarto cuadrante.
Así, si mueves el mouse fuera del área cliente de una ventana, usando para ello una aplicación de MetaTrader 5, el mouse dejará de responder a los eventos dirigidos a esa ventana. Existe una forma de evitar esto y hacer que el mouse siga respondiendo a eventos incluso fuera del área cliente de la ventana donde está el manejador de eventos. Pero eso es tema para otro momento. Quién sabe, quizá en el futuro llegue a mostrar cómo hacerlo.
Entonces, esta es la parte más simple y fácil de entender. Un detalle: no importa dónde esté posicionada la ventana cliente. MetaTrader 5 siempre corregirá los valores de posición en pantalla, hasta el punto de que nuestra aplicación siga creyendo que está utilizando toda esa región que pertenece a la pantalla principal. Es decir, el Desktop.
Al hacer este ajuste por nosotros, MetaTrader 5 nos ahorra mucho trabajo. Un trabajo que, en un entorno de programación distinto de MQL5, quizá tendrías que hacer manualmente. De este modo se evita que la aplicación interprete que está recibiendo eventos cuando, en realidad, no debería estar respondiendo a ellos.
Creo que ya ha quedado claro. Pero ¿y los botones? ¿Cómo podemos saber cuándo se ha presionado uno u otro botón? La cuestión de los botones se resuelve usando una máscara. Y la forma más simple es utilizar alguna macro en el código. Así, resulta más fácil programar y filtrar distintos eventos, ya que podemos estar haciendo clic en algo y, al mismo tiempo, arrastrando ese mismo elemento.
Ahora, antes de entrar en esta cuestión, observa que, en la línea nueve del código 02, activamos el evento de mouse. En la línea 39, en cambio, lo desactivamos. Y, como la información se coloca en distintos tipos de datos, necesitamos convertir esos datos de manera que muestren valores acordes con lo que esperamos. Por eso, estamos usando conversiones explícitas de tipo, como se puede ver en las líneas 27 y 28. Así de simple.
Botones del mouse
La cuestión de los botones del mouse es un tema un tanto controvertido. Y el motivo también lo es. Algunos usuarios quizá imaginan que es sencillo implementar funciones relacionadas con el mouse. Sin embargo, en la práctica, esto es un poco más complicado de lo que parece. Y el motivo es algo aparentemente extraño a primera vista. No es raro que muchas aplicaciones usen los botones del mouse con objetivos particulares. O incluso el propio sistema operativo. En el caso de MetaTrader 5, el botón central es responsable de crear la cruz de análisis simple. El botón derecho, en cambio, abre un menú para diversas manipulaciones y configuraciones del gráfico.
Sin embargo, puede que tu aplicación quiera usar esos mismos botones con otros objetivos, también particulares. Y esto genera un cierto conflicto de intereses entre tú, el usuario y MetaTrader 5. Y, en algunos casos, también podemos incluir al sistema operativo en esta disputa. Bien, en lo que respecta a MetaTrader 5, no le importa que tú, como programador, tomes prestados esos botones para cualquier uso y durante un determinado período de tiempo. Sin embargo, es de muy mal gusto no devolverlos cuando tu aplicación se elimina del gráfico. Salvo que se rompa. En ese caso, no hay cómo.
Tu aplicación se llevará consigo esos botones que tomó prestados. Impedirá que el usuario tenga acceso a ellos durante ese período de uso de MetaTrader 5, en ese gráfico específico. Para recuperar los botones que tu aplicación tomó y no devolvió, por haberse roto, el usuario tendrá que cerrar el gráfico del símbolo y volver a abrirlo. Solo así MetaTrader 5 retomará el control de esos botones. Por eso, necesitas tener cuidado al programar estas cosas, mi querido lector. De lo contrario, tendrás, o generarás, una experiencia de uso muy desagradable para el usuario de tu aplicación.
Bien, creo que ya has entendido el problema. Pero entonces, ¿cómo se hace? Si quiero, por cualquier motivo, tomar el control de los botones derecho y central, ¿cómo debo proceder? Y, para devolver el control de esos mismos botones a MetaTrader 5, ¿cuál es el mejor camino? Bien, estas son muy buenas preguntas, mi querido lector. Y, ya que viene al caso, voy a explicar otra cosa también bastante interesante. En los artículos en los que hablé del evento de teclado, no mencioné el hecho de que tú también puedes asumir un control aún mayor sobre el teclado. Pero, como vamos a tomar el control de los botones del mouse, así como de otras cosas, creo que es una buena oportunidad para mostrar cómo tomar el control total de los elementos de interacción con el usuario. Esto se hace usando el código que se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_Prefix "Demo" 05. //+------------------------------------------------------------------+ 06. int OnInit() 07. { 08. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 09. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 10. //+----------------+ 11. ChartSetInteger(0, CHART_MOUSE_SCROLL, false); 12. ChartSetInteger(0, CHART_CONTEXT_MENU, false); 13. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false); 14. //+----------------+ 15. ChartSetInteger(0, CHART_KEYBOARD_CONTROL, false); 16. ChartSetInteger(0, CHART_QUICK_NAVIGATION, false); 17. //+----------------+ 18. 19. return INIT_SUCCEEDED; 20. }; 21. //+------------------------------------------------------------------+ 22. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 23. { 24. return rates_total; 25. }; 26. //+------------------------------------------------------------------+ 27. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 28. { 29. string sz = ""; 30. 31. switch (id) 32. { 33. case CHARTEVENT_MOUSE_MOVE: 34. Comment(sz); 35. sz += "Mouse position X: " + (string)(short)lparam; 36. sz += "\nMouse position Y: " + (string)(short)dparam; 37. Comment(sz); 38. break; 39. case CHARTEVENT_MOUSE_WHEEL: 40. break; 41. } 42. }; 43. //+------------------------------------------------------------------+ 44. void OnDeinit(const int reason) 45. { 46. Comment(""); 47. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 48. //+----------------+ 49. ChartSetInteger(0, CHART_MOUSE_SCROLL, true); 50. ChartSetInteger(0, CHART_CONTEXT_MENU, true); 51. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true); 52. //+----------------+ 53. ChartSetInteger(0, CHART_KEYBOARD_CONTROL, true); 54. ChartSetInteger(0, CHART_QUICK_NAVIGATION, true); 55. //+----------------+ 56. }; 57. //+------------------------------------------------------------------+
Código 03
Este código 03, mientras se ejecute, impedirá que el usuario use elementos y controles definidos por defecto en MetaTrader 5, como, por ejemplo, la cruz de análisis simple o incluso la posibilidad de presionar la tecla ENTER para cambiar el símbolo actual del gráfico. Entonces, veamos cómo se consiguió esto: primero, en la línea 11, le decimos a MetaTrader 5 que el usuario ya no podrá arrastrar el gráfico para visualizar barras que no se muestran. Para volver a activar este comportamiento predeterminado de MetaTrader 5, usamos la línea 49.
En la línea 12, estamos desactivando el menú contextual del gráfico en el que se está ejecutando el código. A este menú se accede cuando presionas el botón derecho del mouse. Para volver a activar este recurso predeterminado de MetaTrader 5, usamos la línea 50. En la línea 13, estamos desactivando la cruz de análisis simple, a la que se accede cuando presionamos el botón central. Para volver a activar este recurso, usamos la línea 51.
Ahora, en la línea 15, estamos desactivando los recursos relacionados con el desplazamiento y el cambio de escala mediante el teclado. Para volver a activarlos, usamos la línea 53. Y, por último, en la línea 16, estamos desactivando ese recurso que permite al usuario presionar ENTER y escribir el nombre de un símbolo o un marco temporal. Para volver a activar este mismo recurso, usamos la línea 54.
Este tipo de código es más fácil de entender si lo utilizas de forma directa, probando el gráfico antes y durante la ejecución de este código 03. En el archivo adjunto tendrás acceso a este código tal como se muestra, y no veo una forma más sencilla de facilitar tu aprendizaje sobre cómo manejar este tipo de eventos. Solo experimentando y viendo lo que ocurre podrás entender cómo resolver pequeños problemas. Digo esto porque puedes activar y desactivar estos recursos en cualquier momento. Puede resultar interesante activarlos en determinados momentos y desactivarlos en otros. De todos modos, aquí solo los estamos demostrando, con el objetivo de que todo resulte lo más didáctico posible.
Ahora sí, podemos centrarnos en una cuestión más amplia, que es la de los botones del mouse. Pero vamos a añadir también el teclado. Así, podrás probar todo el sistema de una forma mucho más completa. Esto se hace usando el código que se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_Prefix "Demo" 05. //+------------------------------------------------------------------+ 06. int OnInit() 07. { 08. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 09. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 10. //+----------------+ 11. ChartSetInteger(0, CHART_MOUSE_SCROLL, false); 12. ChartSetInteger(0, CHART_CONTEXT_MENU, false); 13. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false); 14. //+----------------+ 15. ChartSetInteger(0, CHART_KEYBOARD_CONTROL, false); 16. ChartSetInteger(0, CHART_QUICK_NAVIGATION, false); 17. //+----------------+ 18. 19. return INIT_SUCCEEDED; 20. }; 21. //+------------------------------------------------------------------+ 22. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 23. { 24. return rates_total; 25. }; 26. //+------------------------------------------------------------------+ 27. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 28. { 29. string sz = ""; 30. 31. switch (id) 32. { 33. case CHARTEVENT_KEYDOWN: 34. Comment(sz); 35. sz += "Key press: " + (string)lparam; 36. Comment(sz); 37. break; 38. case CHARTEVENT_MOUSE_MOVE: 39. Comment(sz); 40. sz += "Mouse position X: " + (string)(short)lparam; 41. sz += "\nMouse position Y: " + (string)(short)dparam; 42. sz += StringFormat("\nHexadecimal mask of mouse buttons is: 0x%02X", (uchar)sparam); 43. Comment(sz); 44. break; 45. case CHARTEVENT_MOUSE_WHEEL: 46. break; 47. } 48. }; 49. //+------------------------------------------------------------------+ 50. void OnDeinit(const int reason) 51. { 52. Comment(""); 53. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 54. //+----------------+ 55. ChartSetInteger(0, CHART_MOUSE_SCROLL, true); 56. ChartSetInteger(0, CHART_CONTEXT_MENU, true); 57. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true); 58. //+----------------+ 59. ChartSetInteger(0, CHART_KEYBOARD_CONTROL, true); 60. ChartSetInteger(0, CHART_QUICK_NAVIGATION, true); 61. //+----------------+ 62. }; 63. //+------------------------------------------------------------------+
Código 04
Como este código 04, al igual que el código 03, puede llegar a estresar mucho a más de un principiante, primero vamos a ver cómo finalizarlo o quitarlo de un gráfico. No podrás hacerlo de la manera a la que probablemente estás acostumbrado con otros indicadores. Para poder detener este código anterior, donde se bloquean por completo las funciones predeterminadas de MetaTrader 5, tú, mi querido lector, necesitarás acceder a lo que se ve en la siguiente imagen.

Imagen 01
Si seleccionas esta opción que se ve en la imagen 01 en MetaTrader 5, en el caso de estar usando un indicador con bloqueo total, podrás acceder a esa lista. Si se trata de un Asesor Experto, tendrás que acceder a Expert List. Cuando lo hagas, tendrás acceso a la lista de indicadores o Asesores Expertos presentes en el gráfico, o abiertos en la plataforma. Así, podrás quitarlos del gráfico. Algo que, de otro modo, no sería posible. Porque bloqueamos por completo el acceso del usuario a todo aquello que forma parte del comportamiento predeterminado de MetaTrader 5.
Bien, una vez explicado esto, veamos a continuación una demostración de lo que hace el código 04.

Animación 02
Es importante que notes lo siguiente, mi querido lector: esta presentación que se ve en la animación 02 tiene como único objetivo mostrar cómo MQL5 interpretaría el mouse y el teclado. Es imprescindible que pruebes este indicador que vemos en el código 04 para entender lo que puede hacer la combinación de botones y teclado. Esto se debe a que resulta algo difícil explicar ciertas cosas, por más simples que puedan parecer. Lo ideal es que lo pruebes y entiendas cómo pueden combinarse estos elementos.
Pero, al ver la combinación entre botones y teclado, notarás que esta línea 42 del código 04 a veces mostrará un resultado y, en otros casos, verás otro distinto. Parece algo extraño. Pero esto ocurre cuando presionamos las teclas SHIFT y/o CTRL. Estas dos teclas tienen una característica interesante. Cuando las presiones, sin mover el mouse, notarás que aparecerán como resultado de la línea 35.
Sin embargo, si mueves el mouse, MetaTrader 5 disparará un evento que activará la línea 42. ¿Por qué? El motivo es que estas dos teclas, SHIFT y CTRL, están vinculadas al mouse y forman parte de la máscara de bits. Entender esto te permitirá crear ciertas cosas que, de otro modo, serían mucho más complicadas de hacer. Por lo tanto, es muy importante que, si realmente quieres entender cómo funcionan el mouse y el teclado en MQL5, procures estudiar los resultados presentados por este código 04.
Sin embargo, todavía falta hablar de otro tipo de evento. Y es el que se activa en la línea 45 del código 04. Pero este evento de la rueda del mouse es, por decirlo así, un tanto extraño. Al menos aquí, en MQL5. Se dispara y tiene una composición de datos un poco distinta de la que podrías esperar. Quizá por eso no se utilice tanto en aplicaciones escritas en MQL5.
Para entenderlo, vamos a añadir al manejador de eventos el código necesario para poder visualizar esta diferencia que existe entre CHARTEVENT_MOUSE_MOVE y CHARTEVENT_MOUSE_WHEEL. Y, créeme, es algo realmente muy interesante de ver en la práctica. Así, el código que se utilizará se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_Prefix "Demo" 05. //+------------------------------------------------------------------+ 06. int OnInit() 07. { 08. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 09. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 10. ChartSetInteger(0, CHART_EVENT_MOUSE_WHEEL, true); 11. //+----------------+ 12. ChartSetInteger(0, CHART_MOUSE_SCROLL, false); 13. ChartSetInteger(0, CHART_CONTEXT_MENU, false); 14. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false); 15. //+----------------+ 16. ChartSetInteger(0, CHART_KEYBOARD_CONTROL, false); 17. ChartSetInteger(0, CHART_QUICK_NAVIGATION, false); 18. //+----------------+ 19. 20. return INIT_SUCCEEDED; 21. }; 22. //+------------------------------------------------------------------+ 23. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 24. { 25. return rates_total; 26. }; 27. //+------------------------------------------------------------------+ 28. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 29. { 30. string sz = ""; 31. 32. switch (id) 33. { 34. case CHARTEVENT_KEYDOWN: 35. Comment(sz); 36. sz += "Key press: " + (string)lparam; 37. Comment(sz); 38. break; 39. case CHARTEVENT_MOUSE_MOVE: 40. Comment(sz); 41. sz += " **** Chart Event Mouse Move ****"; 42. sz += "\nMouse position X: " + (string)(short)lparam; 43. sz += "\nMouse position Y: " + (string)(short)dparam; 44. sz += StringFormat("\nHexadecimal mask of mouse buttons is: 0x%02X", (uchar)sparam); 45. Comment(sz); 46. break; 47. case CHARTEVENT_MOUSE_WHEEL: 48. Comment(sz); 49. sz += " **** Chart Event Mouse Wheel ****"; 50. sz += "\nMouse position X: " + (string)(short)lparam; 51. sz += "\nMouse position Y: " + (string)(short)(lparam >> 16); 52. sz += "\nMouse Delta: " + (string) dparam; 53. sz += StringFormat("\nHexadecimal mask of mouse buttons is: 0x%02X", (uchar)(lparam >> 32)); 54. Comment(sz); 55. break; 56. } 57. }; 58. //+------------------------------------------------------------------+ 59. void OnDeinit(const int reason) 60. { 61. Comment(""); 62. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 63. ChartSetInteger(0, CHART_EVENT_MOUSE_WHEEL, false); 64. //+----------------+ 65. ChartSetInteger(0, CHART_MOUSE_SCROLL, true); 66. ChartSetInteger(0, CHART_CONTEXT_MENU, true); 67. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true); 68. //+----------------+ 69. ChartSetInteger(0, CHART_KEYBOARD_CONTROL, true); 70. ChartSetInteger(0, CHART_QUICK_NAVIGATION, true); 71. //+----------------+ 72. }; 73. //+------------------------------------------------------------------+
Código 05
Y aquí está, mi querido lector. Este código 05 cierra lo que quiero mostrar en este artículo. Observa que aquí no estoy haciendo ningún tipo de manipulación para trabajar con el mouse o el teclado. Usamos un enfoque limpio, simple y directo para que puedas entender lo que ocurre. Al usar este código 05, podrás ver algo parecido a lo que se muestra en la siguiente animación.

Animación 03
Fíjate en que entre el código 04 y este código 05 hay muy poca diferencia. Pero esa pequeña diferencia hace que ambos códigos tengan finalidades muy distintas.En la línea 10 de este código 05, activamos el evento para recibir cualquier movimiento que el usuario haga con la rueda del mouse. Del mismo modo, en la línea 63, desactivamos la recepción de esos mismos eventos. Sin embargo, quiero llamar tu atención, mi querido lector, sobre lo que se ve en el manejador de eventos. Porque allí tenemos una diferencia crucial.
Observa que el manejador de CHARTEVENT_MOUSE_WHEEL se parece mucho al de CHARTEVENT_MOUSE_MOVE. Sin embargo, fíjate de dónde vienen los valores. La ubicación de los valores de posición y de los botones presionados es diferente en ambos casos. Pero es aquí donde la diferencia se vuelve realmente muy grande. SOLO RECIBIRÁS UN EVENTO CHARTEVENT_MOUSE_WHEEL si, y solo si, se produce algún evento en la rueda del mouse. Fuera de eso, todos los demás eventos del mouse se dirigirán a CHARTEVENT_MOUSE_MOVE. Por eso es tan poco común ver aplicaciones o código que use el evento CHARTEVENT_MOUSE_WHEEL. Esto se debe a que no recibimos actualizaciones de otros estados del mouse, como el movimiento o la pulsación de los botones, a menos que se produzca un evento en la rueda del mouse.
Entonces, como se dijo antes, el mouse es un gran aliado. Sin embargo, dependiendo de lo que quieras implementar, puede ser algo salido de lo más profundo del infierno para atormentarte.
Consideraciones finales
Tal vez este artículo haya sido, hasta este momento, uno de esos en los que definitivamente no basta con ver el código y estudiarlo para entender lo que ocurre. De hecho, es necesario crear una aplicación ejecutable y usarla en cualquier gráfico. Esto, para poder entender pequeños detalles que, de otro modo, son muy complicados de comprender. Como, por ejemplo, la combinación del teclado con el mouse para construir ciertos tipos de cosas.
Porque, al entender cómo puede darse esta combinación, tú, con toda seguridad, entenderás por qué ciertos códigos no necesitan incluir el manejador CHARTEVENT_KEYDOWN para verificar si la tecla SHIFT y la tecla CTRL están o no presionadas. También podrás crear combinaciones de los propios botones del mouse para construir recursos mucho más elaborados y de uso particular.
En el archivo adjunto, tendrás acceso a los códigos que vimos aquí. Así que procura estudiar el resultado que cada uno de los códigos produce en el gráfico. Experimenta combinaciones de movimiento y pulsación de botones y teclas, para poder asimilar adecuadamente principios que, en teoría, parecen completamente tediosos, pero que en la práctica se muestran muy interesantes y perfectamente comprensibles.
| Archivo MQL5 | Descripción |
|---|---|
| Code 01 | Demostración del mouse |
Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/16000
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Utilizando redes neuronales en MetaTrader
Simulación de mercado: iniciando SQL en MQL5 (II)
Particularidades del trabajo con números del tipo double en MQL4
Herramientas de trading de MQL5 (Parte 1): Creación de una herramienta interactiva de asistencia para operaciones con órdenes pendientes
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso