- Descripción de recursos mediante la directiva #resource
- Uso compartido de recursos de distintos programas MQL
- Variables de recursos
- Conectar indicadores personalizados como recursos
- Creación de recursos dinámicos: ResourceCreate
- Eliminar recursos dinámicos: ResourceFree
- Leer y modificar datos de recursos: RecursoReadImage
- Guardar imágenes en un archivo: ResourceSave
- Fuentes y salida de texto a recursos gráficos
- Aplicación de recursos gráficos en trading
Fuentes y salida de texto a recursos gráficos
Además de renderizar píxeles individuales en un array de un recurso gráfico, podemos utilizar funciones integradas para mostrar texto. Las funciones permiten cambiar la fuente actual y sus características (TextSetFont), obtener las dimensiones del rectángulo en el que se puede inscribir la cadena dada (TextGetSize), así como insertar directamente el pie de foto en la imagen generada (TextOut).
bool TextSetFont(const string name, int size, uint flags, int orientation = 0)
La función establece la fuente y sus características para el posterior dibujo de texto en el búfer de imagen mediante la función TextOut (véase más adelante). El parámetro name puede contener el nombre de una fuente integrada de Windows o un archivo de fuentes ttf (TrueType Font) conectado por la directiva de recursos (si el nombre empieza por «::»).
El tamaño (size) puede especificarse en puntos (unidad de medida tipográfica) o en píxeles (puntos de pantalla). Los valores positivos significan que la unidad de medida es un píxel, y los valores negativos se miden en décimas de punto. La altura en píxeles tendrá un aspecto diferente para los usuarios en función de las capacidades técnicas y los ajustes de sus monitores. La altura en puntos será aproximadamente («a ojo») la misma para todos.
Un punto tipográfico es una unidad física de longitud, tradicionalmente igual a 1/72 de pulgada. Por tanto, 1 punto equivale a 0.352778 milímetros. Un píxel en la pantalla es una medida virtual de longitud. Su tamaño físico depende de la resolución de hardware de la pantalla. Por ejemplo, con una densidad de pantalla de 96 PPP (puntos por pulgada), 1 píxel ocupará 0.264583 milímetros o 0.75 puntos. Sin embargo, la mayoría de las pantallas modernas tienen valores de PPP mucho más altos y, por tanto, píxeles más pequeños. Por ello, los sistemas operativos, incluido Windows, disponen desde hace tiempo de ajustes para aumentar la escala visible de los elementos de la interfaz. Así, si especifica un tamaño en puntos (valores negativos), el tamaño del texto en píxeles dependerá de la configuración de visualización y escala del sistema operativo (por ejemplo, «estándar» 100 %, «medio» 125 % o «grande» 150 %).
El zoom hace que los píxeles visualizados sean ampliados artificialmente por el sistema. Esto equivale a reducir el tamaño de la pantalla en píxeles, y el sistema aplica los PPP efectivos para conseguir el mismo tamaño físico. Si el escalado está habilitado, entonces son los PPP efectivos los que se notifican a los programas, incluyendo el terminal y después los programas MQL. Si es necesario, puede averiguar los PPP de la pantalla a partir de la propiedad TERMINAL_SCREEN_DPI (véase Especificaciones de la pantalla). Sin embargo, en realidad, al establecer el tamaño de la fuente en puntos, nos libramos de la necesidad de recalcular su tamaño en función de los PPP, ya que el sistema lo hará por nosotros.
La fuente por defecto es Arial y el tamaño por defecto es -120 (12 pt). Los controles, en particular los objetos integrados en los gráficos, también funcionan con tamaños de fuente en puntos. Por ejemplo, si en un programa MQL quiere dibujar un texto del mismo tamaño que el texto del objeto OBJ_LABEL, que tiene un tamaño de 10 puntos, debe utilizar el parámetro size igual a -100.
El parámetro flags establece una combinación de banderas que describen el estilo de la fuente. La combinación está formada por una máscara de bits que utiliza el operador OR ('|'). Las banderas se dividen en dos grupos: banderas de estilos y banderas de negritas.
En la tabla siguiente se enumeran las banderas de estilos. Se pueden mezclar.
Bandera |
Descripción |
---|---|
FONT_ITALIC |
Cursiva |
FONT_UNDERLINE |
Subrayado |
FONT_STRIKEOUT |
Tachado |
Las banderas de negritas tienen pesos relativos correspondientes (dados para comparar los efectos esperados).
Bandera |
Descripción |
---|---|
FW_DONTCARE |
0 (se aplicará el valor predeterminado del sistema) |
FW_THIN |
100 |
FW_EXTRALIGHT, FW_ULTRALIGHT |
200 |
FW_LIGHT |
300 |
FW_NORMAL, FW_REGULAR |
400 |
FW_MEDIUM |
500 |
FW_SEMIBOLD, FW_DEMIBOLD |
600 |
FW_BOLD |
700 |
FW_EXTRABOLD, FW_ULTRABOLD |
800 |
FW_HEAVY, FW_BLACK |
900 |
Utilice solamente uno de estos valores en una combinación de banderas.
El parámetro orientation especifica el ángulo del texto con respecto a la horizontal, en décimas de grado. Por ejemplo, orientación = 0 significa salida de texto normal, mientras que orientación = 450 dará lugar a una inclinación de 45 grados (en sentido contrario a las agujas del reloj).
Tenga en cuenta que los ajustes realizados en una llamada a TextSetFont afectarán a todas las llamadas posteriores a TextOut hasta que se modifiquen.
La función devuelve true si tiene éxito, o false si se producen problemas (por ejemplo, si no se encuentra la fuente).
Consideraremos un ejemplo de utilización de esta función, así como de las otras dos después de describirlas todas.
bool TextGetSize(const string text, uint &width, uint &height)
La función devuelve la anchura y la altura de la línea con la configuración de fuente actual (puede ser la fuente predeterminada o la especificada en la llamada anterior a TextSetFont).
El parámetro text pasa una cadena en la que se requiere la longitud y la anchura en píxeles. La función escribe los valores de las dimensiones basándose en las referencias de los parámetros width y height.
Debe tenerse en cuenta que la rotación (inclinación) del texto mostrado especificada por el parámetro orientation cuando se llama a TextSetFont no afecta al tamaño de ninguna manera. En otras palabras, si el texto debe girar 45 grados, el propio programa MQL debe calcular el cuadrado mínimo en el que cabe el texto. La función TextGetSize calcula el tamaño del texto en una posición estándar (horizontal).
bool TextOut(const string text, int x, int y, uint anchor, uint &data[], uint width, uint height, uint color, ENUM_COLOR_FORMAT color_format)
La función dibuja texto en el búfer gráfico en las coordenadas especificadas teniendo en cuenta el color, el formato y los ajustes previos (fuente, estilo y orientación).
El texto se pasa en el parámetro text y debe tener la forma de una línea.
Las coordenadas x y y especificadas en píxeles definen el punto del búfer gráfico donde se muestra el texto. El lugar de la inscripción generada en el punto (x, y) depende del método de vinculación en el parámetro anchor (véase más adelante).
El búfer está representado por el array data, y aunque el array es unidimensional, almacena un «lienzo» bidimensional con dimensiones de width x height puntos. Este array se puede obtener de la función ResourceReadImage, o asignado por un programa MQL. Una vez finalizadas todas las operaciones de edición, incluida la salida de texto, deberá crear un nuevo recurso basado en este búfer o aplicarlo a un recurso ya existente. En ambos casos, debe llamar a ResourceCreate.
El color del texto y la forma en que se maneja el color se establecen mediante los parámetros color y color_format (véase ENUM_COLOR_FORMAT). Tenga en cuenta que el tipo utilizado para el color es uint, es decir, para transmitir el color, debe convertirlo utilizando ColorToARGB.
El método de anclaje especificado por el parámetro anchor es una combinación de dos banderas de posición de texto: vertical y horizontal.
Las banderas de posición de texto en horizontal son:
- TA_LEFT - punto de anclaje en el lado izquierdo del rectángulo delimitador
- TA_CENTER - punto de anclaje en el centro entre los lados izquierdo y derecho del rectángulo
- TA_RIGHT - punto de anclaje en el lado derecho del rectángulo delimitador
Las banderas de posición vertical del texto son:
- TA_TOP - punto de anclaje en el lado superior del rectángulo delimitador
- TA_VCENTER - punto de anclaje en el centro entre la parte superior e inferior del rectángulo
- TA_BOTTOM - punto de anclaje en el lado inferior del rectángulo delimitador
En total, hay 9 combinaciones válidas de banderas para describir el método de anclaje.
Posición del texto de salida en relación con el punto de anclaje
Aquí, el centro de la imagen contiene un punto grande deliberadamente exagerado en la imagen generada con coordenadas (x, y). En función de las banderas, el texto aparece en relación con este punto en las posiciones especificadas (el contenido del texto corresponde al método de anclaje aplicado).
Para facilitar la consulta, todas las inscripciones se han realizado en la posición horizontal estándar. Sin embargo, nótese que también podría aplicarse un ángulo a cualquiera de ellos (orientation), y entonces la inscripción correspondiente giraría alrededor del punto. En esta imagen solo se gira la etiqueta centrada en ambas dimensiones.
Estas banderas no deben confundirse con la alineación del texto. El cuadro delimitador siempre tiene el tamaño adecuado para el texto, y su posición respecto al punto de anclaje es, en cierto sentido, la opuesta a la de los nombres de las banderas.
Veamos algunos ejemplos utilizando tres funciones.
Para empezar, vamos a comprobar las opciones más sencillas de configuración del estilo y la negrita de la fuente. El script ResourceText.mq5 permite seleccionar el nombre de la fuente y su tamaño, así como los colores del fondo y del texto en las variables de entrada. Las etiquetas se mostrarán en el gráfico durante el número de segundos especificado.
input string Font = "Arial"; // Font Name
|
El nombre de cada gradación de negrita se mostrará en el texto de la etiqueta, por lo que para simplificar el proceso (mediante EnumToString) se declara la enumeración ENUM_FONT_WEIGHTS.
enum ENUM_FONT_WEIGHTS
|
Las banderas de inscripción se recogen en el array rendering y de ella se seleccionan combinaciones aleatorias.
const uint rendering[] =
|
Para obtener un número aleatorio en un rango existe una función auxiliar Random.
int Random(const int limit)
|
En la función principal del script, encontramos el tamaño del gráfico y creamos un objeto OBJ_BITMAP_LABEL que abarca todo el espacio.
void OnStart()
|
A continuación, asignamos memoria al búfer de imagen, lo rellenamos con el color de fondo especificado (o lo dejamos transparente, por defecto), creamos un recurso basado en el búfer y lo vinculamos al objeto.
uint data[];
|
Por si acaso, tenga en cuenta que podemos establecer la propiedad OBJPROP_BMPFILE sin modificador (0 o 1) en la llamada a ObjectSetString, a menos que el objeto deba cambiar entre dos estados.
Todos los pesos de las fuentes se enumeran en el array weights.
const uint weights[] =
|
En el bucle, en orden, establecemos la siguiente gradación de negrita para cada línea utilizando TextSetFont, preseleccionando un estilo aleatorio. Una descripción de la fuente, incluyendo su nombre y peso, se dibuja en el búfer utilizando TextOut.
const int step = h / (nw + 2);
|
Actualice ahora el recurso y el gráfico.
ResourceCreate(name, data, w, h, 0, 0, w, COLOR_FORMAT_ARGB_RAW);
|
El usuario puede detener la demostración con antelación.
const uint timeout = GetTickCount() + Seconds * 1000;
|
Por último, el script elimina el recurso y el objeto.
ObjectDelete(0, name);
|
El resultado del script se muestra en la siguiente imagen.
Dibujar texto en diferentes pesos y estilos
En el segundo ejemplo de ResourceFont.mq5 haremos la tarea más difícil incluyendo una fuente personalizada como recurso y utilizando la rotación del texto en incrementos de 90 grados.
El archivo de fuentes se encuentra junto al script.
#resource "a_LCDNova3DCmObl.ttf" |
El mensaje puede modificarse en el parámetro de entrada.
input string Message = "Hello world!"; // Message |
Esta vez, OBJ_BITMAP_LABEL no ocupará toda la ventana y, por tanto, estará centrado tanto horizontal como verticalmente.
void OnStart()
|
Para empezar, se asigna el búfer del tamaño mínimo, justo para completar la creación de recursos. Más adelante lo ampliaremos para ajustarlo a las dimensiones de la inscripción, para lo que existen las variables reservadas width y height.
uint data[], width, height;
|
En un bucle con la cuenta atrás del tiempo de prueba necesitamos cambiar la orientación de la inscripción, para lo cual existe la variable angle (en ella se desplazarán los grados). La orientación cambiará una vez por segundo, la cuenta está en la variable remain.
const uint timeout = GetTickCount() + Seconds * 1000;
|
En el bucle, cambiamos constantemente la rotación del texto, y en el propio texto, mostramos un contador de segundos. Para cada nueva inscripción se calcula su tamaño mediante TextGetSize, en función del cual se reasigna el búfer.
while(!IsStopped() && GetTickCount() < timeout)
|
Tenga en cuenta que, si el texto es vertical, habrá que intercambiar las dimensiones. En términos más generales, con el texto girado en un ángulo arbitrario, se necesitaban más cálculos matemáticos para conseguir que el tamaño del búfer se ajustara a todo el texto.
Al final eliminamos también el objeto y el recurso.
ObjectDelete(0, name);
|
Uno de los momentos de la ejecución del script se muestra en la siguiente captura de pantalla:
Inscripción con fuente personalizada
Como ejemplo final, echemos un vistazo al script ResourceTextAnchOrientation.mq5 mostrando varias rotaciones y puntos de anclaje del texto.
El script genera el número especificado de etiquetas (ExampleCount) utilizando la fuente especificada.
input string Font = "Arial"; // Font Name
|
Los puntos de anclaje y las rotaciones se eligen aleatoriamente.
Para especificar los nombres de los puntos de anclaje en las etiquetas, existe la enumeración ENUM_TEXT_ANCHOR con todas las opciones válidas declaradas. Así, podemos llamar simplemente EnumToString a cualquier elemento seleccionado al azar.
enum ENUM_TEXT_ANCHOR
|
En el manejador OnStart se declara un array de estas nuevas constantes.
void OnStart()
|
La creación inicial de objetos y recursos es similar a la del ejemplo con ResourceText.mq5, así que vamos a omitirlos aquí. Lo más interesante ocurre en el bucle:
for(int i = 0; i < ExampleCount; ++i)
|
Solo queda actualizar la imagen y el gráfico, y luego esperar la orden del usuario y liberar recursos.
ResourceCreate(name, data, w, h, 0, 0, w, COLOR_FORMAT_ARGB_NORMALIZE);
|
Esto es lo que obtenemos como resultado:
Salida de texto con coordenadas, puntos de anclaje y ángulos aleatorios
Además, para un estudio independiente, el libro proporciona un editor de gráficos de juguete SimpleDrawing.mq5 diseñado como un indicador sin búfer y que utiliza en su trabajo las clases de formas consideradas anteriormente (véase el ejemplo con ResourceShapesDraw.mq5). Se colocan en el archivo de encabezado ShapesDrawing.mqh casi sin cambios. Anteriormente, las formas eran generadas aleatoriamente por el script. Ahora el usuario puede seleccionarlas y trazarlas en el gráfico. Para ello, se ha implementado una interfaz con una paleta de colores y una barra de botones en función del número de clases de formas registradas. La interfaz está implementada por la clase SimpleDrawing (SimpleDrawing.mqh).
Editor gráfico sencillo
El panel y la paleta pueden colocarse a lo largo de cualquier borde del gráfico, lo que demuestra la posibilidad de girar las etiquetas.
La selección de la siguiente forma que se va a dibujar se realiza pulsando el botón en el panel: el botón «se pega» en el estado pulsado, y su color de fondo indica el color de dibujo seleccionado. Para cambiar el color, haga clic en cualquier lugar de la paleta.
Cuando se selecciona uno de los tipos de forma en el panel (uno de los botones está «activo»), al hacer clic en el área de dibujo (el resto del gráfico, indicado por el sombreado) se dibuja una forma de tamaño predefinido en ese lugar. En ese momento, el botón se «apaga». En este estado, cuando todos los botones están inactivos, puede mover las formas por el espacio de trabajo utilizando el ratón. Si mantenemos pulsada la tecla Ctrl, la forma se redimensiona en lugar de moverse. El «punto caliente» se sitúa en el centro de cada forma (el tamaño del área sensible se establece mediante una macro en el código fuente y probablemente habrá que aumentarlo para pantallas con PPP muy elevados).
Tenga en cuenta que el editor incluye el ID de trazado (ChartID) en los nombres de los recursos generados. Esto permite ejecutar el editor en paralelo en varios gráficos.