
Del básico al intermedio: Struct (III)
Introducción
En el artículo anterior, "Del básico al intermedio: Indicador (IV)", se mostró cómo hacer algo que para muchos principiantes sería extremadamente complicado de manera simple y fácil de entender. Ahora todos conocen una manera simple y fácil de hacerlo, por lo que pueden poner en práctica sus ideas. Se trataba de crear un indicador cuyo objetivo era proporcionar una indicación, mediante colores, de algún tipo de sistema de negociación. Claro que allí mostré cómo implementar el modelo de inside bar. Pero ese conocimiento puede aplicarse a cualquier modelo cuyo patrón de colores de las velas indica, o no, la posibilidad de negociación.
Muy bien, aquello fue de hecho bastante divertido. Sin embargo, creo que podemos abordar otro tema, que, en mi opinión, también es bastante divertido e interesante. Y el tema comenzó a tratarse al final del artículo anterior. Pero antes de entrar en la cuestión que veremos a partir de este artículo, necesitamos volver un poco en el tiempo y hacer una breve retrospectiva.
En los artículos sobre estructuras, especialmente en "Del básico al intermedio: Struct (II)", se explicó cómo trabajar con estructuras para crear bloques de registro. Durante aquellos dos artículos, que trataban exclusivamente sobre estructuras, mencioné que estas serían un tipo especial de dato en el que podríamos colocar diversas informaciones, pero organizándolas de manera lógica y simplificada. Sin embargo, debido a que no se mostraron otras cosas antes, sería complicado, e incluso innecesario, entrar en más detalles sobre las estructuras. Pero en el artículo anterior se creó una brecha lo suficientemente adecuada como para que podamos entrar más profundamente en algunas cuestiones. Básicamente, el objetivo ahora es mostrar que las estructuras pueden utilizarse para hacer muchas más cosas que simplemente organizar datos de registro.
Así que, tras esta breve introducción, por fin podemos entrar en materia y empezar a entender por qué surgieron las clases. ara ello, empezaremos con el primer tema sobre este asunto.
Código estructurado
Muy probablemente, una de las cosas que más me desanima es cuando veo un código todo desordenado. En la época del antiguo BASIC, que DIOS lo tenga, de cierta forma tenía sentido un código sin una estructura previamente definida. Esto se debe a la propia naturaleza del lenguaje. En lenguaje del tipo BATCH, como lenguajes de script por lotes —un ejemplo sería SQL— de cierta manera, podemos no tener una estructura muy bien definida. Ya que, en la mayoría de las veces, las tareas a ser ejecutadas son relativamente simples, así como los códigos, que normalmente son bastante cortos.
Sin embargo, la cosa se complica cuando entramos en lenguajes con objetivos más profundos, como sería el caso de MQL5. En este caso, muchas veces tenemos un objetivo que difícilmente se alcanzará con pocas líneas de código, incluso cuando se hace uso de un archivo de cabecera para ocultar gran parte de la complejidad involucrada. Sin embargo, hay algunos aspectos que hacen que la programación sea tediosa y agotadora. Una de ellas es la tendencia frecuente de los programadores principiantes a repetir fragmentos de código que podrían estar mejor estructurados.
Y cuando hablo de código estructurado, no me refiero al uso de funciones o procedimientos para mantener una cierta organización en el código. En este caso, me refiero a incluir el código dentro de estructuras para que sea más fácil de mantener y trabajar. Muchos orientadores o instructores de programación dicen que el hecho de utilizar funciones y procedimientos en un código ya lo vuelve estructurado. Sin embargo, esto no significa necesariamente que el código esté estructurado. Solo está mejor organizado. Nada más.
Para conseguir un código realmente estructurado, necesitamos utilizar métodos y conceptos que muchos consideran una locura o, como mínimo, demasiado complicados. Uno de estos medios sería la utilización de clases. Sin embargo, aún no es momento de hablar sobre clases. Esto se debe a que las clases no surgieron porque un día algunos programadores se despertaron y dijeron: «Vamos a crear algo para complicar la vida de quien esté empezando. Así seremos los más grandes». No, querido lector, las clases surgieron para solucionar una limitación a la hora de crear un código verdaderamente estructurado.
Para entender esta limitación, necesitamos empezar a abordar cuestiones más avanzadas. Así que prepárate, porque a partir de ahora las cosas se van a poner realmente divertidas e interesantes.
Tal vez estés mirando con cierta desconfianza sin entender qué es lo que quiero mostrarte. Pero no te preocupes, iremos paso a paso, ya que es extremadamente necesario que logres entender lo que vamos a hacer. De lo contrario, te quedarás completamente confundido con lo que comenzaremos a modelar para alcanzar la programación orientada a objetos.
En el artículo anterior, vimos el siguiente código.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. input bool user01 = true; //Show time scale 05. input bool user02 = true; //Show price scale 06. //+----------------+ 07. struct st_Mem 08. { 09. long View_DateScale, 10. View_PriceScale; 11. }gl_StyleGraphic; 12. //+------------------------------------------------------------------+ 13. int OnInit() 14. { 15. gl_StyleGraphic.View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE); 16. gl_StyleGraphic.View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE); 17. 18. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, user01); 19. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, user02); 20. 21. return INIT_SUCCEEDED; 22. }; 23. //+------------------------------------------------------------------+ 24. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 25. { 26. return rates_total; 27. }; 28. //+------------------------------------------------------------------+ 29. void OnDeinit(const int reason) 30. { 31. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, gl_StyleGraphic.View_DateScale); 32. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, gl_StyleGraphic.View_PriceScale); 33. ChartRedraw(); 34. }; 35. //+------------------------------------------------------------------+
Código 01
Este código es bastante simple. Sin embargo, si de verdad eres curioso, habrás buscado información sobre las propiedades del gráfico para intentar crearlo y manipular su apariencia directamente mediante código. Si de hecho has llegado a hacerlo, debo felicitarte, ya que esta es una de las premisas para quien quiera ser un buen profesional en el futuro.
Sin embargo, a pesar de la aparente simplicidad de este código, muchos lo consideran un código estructurado. En mi opinión, lo que se ve en el código 01 no es, en realidad, un código estructurado, sino más bien un código bien organizado. A pesar de su simplicidad, no es exactamente el tipo de código que, en mi opinión, sería ideal para comenzar a explicar un código estructurado. Para ello, vamos a recurrir a algo aún más simple: los scripts. Esto se debe a que los scripts tienen y responden únicamente al evento Start. Al final de este evento, el código se termina. Más simple que esto: IMPOSIBLE.
Entonces, vamos a comenzar con el código visto justo abajo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. struct st_Mem 07. { 08. long View_DateScale, 09. View_PriceScale; 10. }StyleGraphic; 11. 12. StyleGraphic.View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE); 13. StyleGraphic.View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE); 14. 15. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false); 16. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false); 17. ChartRedraw(); 18. 19. Sleep(2000); 20. 21. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, StyleGraphic.View_DateScale); 22. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, StyleGraphic.View_PriceScale); 23. ChartRedraw(); 24. } 25. //+------------------------------------------------------------------+
Código 02
Este código es mucho más simple que el del ejemplo 01 y tiene el mismo objetivo: ocultar y luego reponer la escala de precios y la de tiempo. Cuando ejecutes este script en un gráfico, verás algo parecido a lo mostrado en la animación de abajo.
Animación 01
Como puedes ver, todo es muy fácil de entender: la línea 19 es la responsable de hacer que las escalas queden ocultas por unos instantes. En ella, indicamos que queremos una pausa de aproximadamente dos segundos antes de que el código se vuelva a ejecutar. Sin embargo, quiero que prestes atención a dos cosas, mi querido lector: las líneas 17 y 23. En el artículo anterior, mencioné por qué se debe utilizar este comando en un código. Sin embargo, aquí estamos trabajando con un script y el tiempo de espera es corto, por lo que este comando, presente en ambas líneas mencionadas, es muy importante. Sin él, es muy probable que no viéramos cómo se ocultan y se muestran de nuevo las escalas de precio y tiempo.
Bien. Hasta ahí todo está muy bien pensado y comprendido. Pero este código 02, en mi opinión, no es un código estructurado, aunque en la línea seis estemos declarando una estructura. Entonces, vamos a comenzar a escribir lo que muchos consideran un código estructurado. Para ello, cambiaremos el código 02 por el que se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. struct st_Mem 05. { 06. long View_DateScale, 07. View_PriceScale; 08. }; 09. //+------------------------------------------------------------------+ 10. void OnStart(void) 11. { 12. st_Mem StyleGraphic; 13. 14. StyleGraphic = SAVE(); 15. 16. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false); 17. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false); 18. ChartRedraw(); 19. 20. Sleep(2000); 21. 22. RESTORE(StyleGraphic); 23. } 24. //+------------------------------------------------------------------+ 25. st_Mem SAVE(void) 26. { 27. st_Mem local; 28. 29. local.View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE); 30. local.View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE); 31. 32. return local; 33. } 34. //+------------------------------------------------------------------+ 35. void RESTORE(const st_Mem &arg) 36. { 37. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, arg.View_DateScale); 38. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, arg.View_PriceScale); 39. 40. ChartRedraw(); 41. } 42. //+------------------------------------------------------------------+
Código 03
Este código 03 producirá el mismo tipo de resultado que podemos ver en la animación 01, pero tiene un pequeño detalle. A diferencia del código 02, aquí tenemos una mejor organización, ya que podemos utilizar la función de la línea 25 en diversos momentos, así como el procedimiento de la línea 35 en cualquier momento. La principal ventaja de este tipo de modelado e implementación, que podemos ver en el código 03, es precisamente el hecho de que podemos guardar y restaurar todos los valores de las propiedades del gráfico sin preocuparnos por cuáles serán los valores que se modificarán. Esto evita tener que crear una gran cantidad de líneas que siempre contengan el mismo tipo de código.
Sin embargo, existe un pequeño problema en este enfoque, que se observa en el código 03. El problema es el siguiente: estamos trabajando con una estructura para contener los datos. Hasta ahí, todo bien. Pero, ¿cuál es el sentido de implementar la función de la línea 25 y el procedimiento de la línea 35 si el objetivo es trabajar directamente con los datos presentes en la estructura?
Al principio, esto no parece molestar a los programadores principiantes ni a los más experimentados, sobre todo cuando trabajamos con códigos simples, pero termina convirtiéndose en un verdadero tormento cuando comenzamos a trabajar con códigos más elaborados. Esto se debe a que empezamos a implementar cosas que no tienen mucho sentido fuera del contexto de los datos con los que estamos trabajando.
Este código 03 es muy bueno para explicar esto y para que tú, mi querido lector, llegues a comprender el concepto que hay detrás de lo que vamos a hacer dentro de poco. Observa lo siguiente: tenemos una estructura que se puede utilizar en varios puntos distintos del código. El objetivo de esta estructura es guardar y restablecer la condición en la que se encuentra el gráfico en un momento dado. Por esta razón, podemos implementar el código como se muestra arriba.
Sin embargo, conforme vamos creando más cosas, la función SAVE y el procedimiento RESTORE comienzan a salirse del contexto. También podemos llegar a necesitar crear otra función y otro procedimiento con exactamente el mismo nombre, pero con un objetivo diferente al de guardar y restaurar las propiedades del gráfico. En ese momento, podemos utilizar la sobrecarga, pero esto complicará el código de manera completamente innecesaria. Es en este punto donde surge la cuestión de si el código está estructurado o no.
En un código estructurado, las funciones SAVE y RESTORE dejarían de declararse como podemos ver en el código 03, donde no están debidamente ligadas al contexto de la estructura definida en la línea cuatro, y pasarían a declararse, o mejor dicho, a implementarse dentro del contexto de dicha estructura. Como esto no se puede mostrar poco a poco, iremos directamente a la solución que se ha visto en los demás códigos, solo que ahora en un modelo completamente estructurado. Esto se puede observar en el código que aparece a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. struct st_PropertyGraphics 05. { 06. long View_DateScale, 07. View_PriceScale; 08. //+----------------+ 09. void SAVE(void) 10. { 11. View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE); 12. View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE); 13. } 14. //+----------------+ 15. void RESTORE(void) 16. { 17. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, View_DateScale); 18. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, View_PriceScale); 19. 20. ChartRedraw(); 21. } 22. //+----------------+ 23. }; 24. //+------------------------------------------------------------------+ 25. void OnStart(void) 26. { 27. st_PropertyGraphics StyleGraphic; 28. 29. StyleGraphic.SAVE(); 30. 31. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false); 32. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false); 33. ChartRedraw(); 34. 35. Sleep(2000); 36. 37. StyleGraphic.RESTORE(); 38. } 39. //+------------------------------------------------------------------+
Código 04
¡Vaya! Qué cosa más loca y sin sentido. Hombre, ahora me ha dado un cortocircuito en el cerebro, porque hasta donde yo había entendido, una estructura sería como una variable de tipo especial que se puede organizar para crear pequeños bancos de registro. Pero lo que estoy viendo en el código 04 no tiene el menor sentido para mí.
Bien, en este momento, el listón acaba de subir. Quien no haya estado practicando y estudiando lo que se está mostrando ahora no tendrá otra forma de progresar, ya que, desde este momento en adelante, las posibilidades se multiplican de forma muy rápida y exponencial. Sin embargo, no hay motivo para tenerle miedo a este código 04. Estoy intentando hacer las cosas de la forma más didáctica posible, precisamente para evitar tener que estar explicando cosas y poder enfocarnos en algo más interesante.
Así que vamos a ver qué está ocurriendo en este código 04. En primer lugar, este código 04 funcionará de la misma forma que los demás códigos vistos anteriormente. Sin embargo, aquí tenemos una ventaja, ya que ahora esos mismos procedimientos y funciones, cuyo propósito es almacenar las propiedades gráficas, están y siempre estarán dentro del contexto de la propia estructura que va a contener esos datos. A esto es a lo que llamamos programación estructurada.
Por ahora, ignoraremos la estructura definida en la línea cuatro y nos centraremos en el manejador de eventos OnStart. En la línea 27, declaramos la estructura de la misma forma que antes. Es decir, la creación de nuestra variable o registro especial se hará del mismo modo. Pero fíjate en las líneas 29 y 37. ¿Qué estás pensando al ver estas líneas? Probablemente estés pensando: Bien, en la línea 29 estoy pidiendo que se guarde algo y, en la línea 37, que se restaure. Si ese fue tu pensamiento, vamos por buen camino.
Entonces, vuelve a mirar esas mismas líneas. ¿Qué es lo que estamos pidiendo guardar y restaurar? Efectivamente, se trata de una variable que declaré en la línea 27. Hum, interesante. Entonces, déjame ver si lo he entendido. En la línea 27, declaro una variable. Cuando se ejecuta la línea 29, se pide que esa misma variable sea guardada. De acuerdo, como esta variable es de tipo registro de propiedades gráficas,
Entonces, en la línea 29, estoy pidiendo que se guarden las propiedades gráficas. Así, en las líneas 31 y 32, puedo modificar las propiedades sin preocuparme por posibles cambios. Genial, creo que empiezo a entender. Cuando ejecutamos la línea 37, pedimos que se restauren esas mismas propiedades guardadas, descartando así cualquier cambio efectuado entre las líneas 29 y 37. ¿Es eso? ¿Entendí correctamente lo que se está haciendo aquí en el manejador de eventos OnStart? Sí, mi querido lector, tu entendimiento fue de hecho bastante adecuado.
Genial. Pero ahora tengo una duda. Al comparar el código 03 con el código 04, he notado que la forma de declarar las cosas aquí es diferente, en lo que respecta a las rutinas SAVE y RESTORE. ¿Por qué hay esta diferencia entre ambos códigos? Ya que, en principio, ambos tienen el mismo tipo de objetivo y comportamiento. Aún no logro comprenderlo.
Me alegra que hayas notado eso, querido lector, porque ahora, gracias a que has comprendido el código de OnStart, ha llegado el momento de explicar el código de la estructura declarada en la línea cuatro. Así que, esta vez, quiero que ignores cualquier otra cosa presente en el código 04 y nos centremos únicamente en el bloque de la estructura.
Observa que he cambiado el nombre de la estructura para simplificar las cosas. Sin embargo, puedes usar el nombre que quieras. Lo importante es que la estructura esté en el ámbito global. Incluso puede estar presente en un archivo de cabecera. Pero, por ahora, no nos preocuparemos de esto. Solo observa y presta atención a lo que se explicará.
Observa que mantenemos las mismas variables que en los códigos anteriores. Estas variables siguen siendo accesibles y perfectamente funcionales, igual que en el código 03. Incluso puedes trabajar con ellas, pero eso se verá en otro momento. Lo importante es lo que ocurre dentro de las rutinas. En este caso, tenemos la rutina SAVE en la línea nueve y la rutina RESTORE en la línea quince. Fíjate en que se parecen mucho a las del código 03.
Sin embargo, aquí es donde la cosa se pone interesante: las variables View_DateScale y View_PriceScale ya no necesitan ser declaradas como se muestra en el código 03. ¿Por qué? El motivo es que estas variables forman parte de un contexto para el compilador y para un programador. En este caso, el contexto es precisamente la estructura st_PropertyGraphics.
Es decir, como estamos trabajando con un contexto que tiene sentido dentro de la estructura, NO ES NECESARIO DECLARAR LAS VARIABLES como se hacía en el código 03, donde se hacía en las líneas 29, 30, 37 y 38. , necesitábamos indicar el tipo de datos a los que se vincularían las variables, ya que en el código 03 tanto la rutina SAVE como la rutina RESTORE no formaban parte del contexto de la estructura, cosa que en el código 04 ya no tiene sentido, ya que ambas rutinas pertenecen a la estructura.
Esto es lo que podemos llamar programación estructurada, ya que ahora podemos trabajar con los elementos de forma completamente contextualizada, sin necesidad de imaginarlos ni de leer todo el código para comprender lo que ocurre.
Siéntete libre de hacer cambios y experimentar con este código, mi querido lector, para comprender realmente lo que está ocurriendo. Pero antes de terminar este artículo, quiero mostrar otra cosa, esta vez utilizando otro código. Sin embargo, como esto involucra otras cuestiones, lo abordaremos en un nuevo tema.
Manipulaciones simples de estructuras
En el tema anterior, expliqué cómo se contextualiza el código al crear un código estructurado. Pero, a pesar de toda su belleza, hay algunos aspectos que deben tenerse en cuenta. Claro que, precisamente debido a estos cuidados, surgió la necesidad de crear las clases. Pero eso lo veremos en otro momento. Ahora, vamos a ver algunos de estos cuidados.
En primer lugar, dentro de una estructura, todos los datos siguen un criterio muy sencillo: pueden ser públicos o privados. Generalmente, cuando declaramos una estructura simple, siempre tendremos datos públicos. Sin embargo, cuando trabajamos con programación estructurada, NO QUEREMOS datos públicos. De hecho, en este tipo de casos, lo que deseamos es garantizar que los datos van a permanecer íntegros durante todo su periodo de vida.
Para garantizar esta integridad, podemos cambiar el tipo de acceso a los datos. Ahora, presta atención, querido lector. Lo que se verá aquí NO DEBE utilizarse en estructuras simples, como las vistas anteriormente. Solo úsalo cuando implementes código estructurado y quieras tener un mayor control sobre el funcionamiento del código. Si no tienes los conocimientos necesarios, utilizar lo que se mostrará aquí complicará algo que, en principio, es bastante simple.
Para explicar esto de manera adecuada, vamos a ver un código que sea simple, pero apropiado para lo que quiero explicar en este momento. El mismo puede verse justo abajo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. struct st_PropertyGraphics 05. { 06. long View_DateScale, 07. View_PriceScale, 08. Chart_Mode; 09. //+----------------+ 10. void SAVE(void) 11. { 12. View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE); 13. View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE); 14. Chart_Mode = ChartGetInteger(0, CHART_MODE); 15. } 16. //+----------------+ 17. void RESTORE(void) 18. { 19. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, View_DateScale); 20. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, View_PriceScale); 21. ChartSetInteger(0, CHART_MODE, Chart_Mode); 22. 23. ChartRedraw(); 24. } 25. //+----------------+ 26. }; 27. //+------------------------------------------------------------------+ 28. void OnStart(void) 29. { 30. st_PropertyGraphics StyleGraphic; 31. 32. StyleGraphic.SAVE(); 33. 34. StyleGraphic.Chart_Mode = CHART_LINE; 35. 36. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false); 37. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false); 38. ChartSetInteger(0, CHART_MODE, CHART_BARS); 39. ChartRedraw(); 40. 41. Sleep(2000); 42. 43. StyleGraphic.RESTORE(); 44. } 45. //+------------------------------------------------------------------+
Código 05
Observa que el código 05 se parece bastante al código 04. Sin embargo, para ejemplificar lo que quiero mostrar, he añadido una nueva propiedad gráfica a la estructura. Esta propiedad se declara en la línea ocho de este código 05. Observa que, junto con ella, también se han añadido nuevas líneas en las rutinas SAVE y RESTORE. No son cambios demasiado importantes que merezcan grandes explicaciones. También se produjeron pequeños cambios en el procedimiento OnStart, que son sencillos de entender y no es necesario entrar en detalles sobre ellos. Sin embargo, cuando ejecutes este script en un gráfico, verás algo parecido a lo que se muestra en la animación de abajo.
Animación 02
¡Epá! Paramos todo. Rebobinemos la cinta, porque acabamos de obtener un resultado inesperado y quiero entender por qué el gráfico no se restableció a su estado original, ya que mantenemos el mismo tipo de principio e idea que en el código 04. Sin embargo, creo que el error puede estar en esta nueva propiedad que acabamos de añadir. Bien, mi querido lector, es más o menos eso. Pero no es exactamente ese el problema. El problema se conoce como fuga de datos o fallo de encapsulamiento; es decir, se está haciendo algo que antes no se podía hacer. Y esto es lo que está causando el resultado que se observa en la animación 02.
Presta atención: en la línea 32 guardamos las propiedades gráficas y en la 43 las restauramos, del mismo modo que en el código 04. Sin embargo, aquí tenemos un problema: la línea 34. Pero no veo ningún problema ahí. ¿Será que si eliminamos esta línea todo vuelve a la normalidad? Sí, si eliminamos la línea 34, todo vuelve a la normalidad. Pero ese no es el punto.
La cuestión es cómo se guardan los datos en la variable StyleGraphics. Esta variable está directamente relacionada con un pequeño banco de registros que se encuentra entre las líneas seis y ocho. Cualquier cambio que realicemos en estos registros afectará al contenido de la variable StyleGraphics.
Así, cuando solicitamos la restauración de los datos en la línea 43, se utilizarán todos los datos del registro. Sin embargo, debido al cambio realizado en la línea 34, se perdió el registro original. Por esta razón, ahora tenemos un valor diferente del que se guardó y que se está aplicando al gráfico, restableciéndolo con información incorrecta.
Este tipo de problema es muy serio y, al mismo tiempo, muy habitual. Para resolverlo, debemos cambiar la cláusula de declaración de los valores dentro de la estructura. Recuerda que, por defecto, todos los valores son públicos. Sin embargo, si cambiamos el código 05 por lo que se muestra a continuación, las cosas serán diferentes.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. struct st_PropertyGraphics 05. { 06. private: 07. //+----------------+ 08. long View_DateScale, 09. View_PriceScale, 10. Chart_Mode; 11. //+----------------+ 12. public: 13. //+----------------+ 14. void SAVE(void) 15. { 16. View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE); 17. View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE); 18. Chart_Mode = ChartGetInteger(0, CHART_MODE); 19. } 20. //+----------------+ 21. void RESTORE(void) 22. { 23. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, View_DateScale); 24. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, View_PriceScale); 25. ChartSetInteger(0, CHART_MODE, Chart_Mode); 26. 27. ChartRedraw(); 28. } 29. //+----------------+ 30. }; 31. //+------------------------------------------------------------------+ 32. void OnStart(void) 33. { 34. st_PropertyGraphics StyleGraphic; 35. 36. StyleGraphic.SAVE(); 37. 38. StyleGraphic.Chart_Mode = CHART_LINE; 39. 40. ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false); 41. ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false); 42. ChartSetInteger(0, CHART_MODE, CHART_BARS); 43. ChartRedraw(); 44. 45. Sleep(2000); 46. 47. StyleGraphic.RESTORE(); 48. } 49. //+------------------------------------------------------------------+
Código 06
En este caso, al compilar el código se mostrará una advertencia muy similar a la que se muestra a continuación.
Imagen 01
Observa que hay un error, ya que en la línea 38 intentamos acceder a un valor que ya no es público; esto se debe a que incluimos una cláusula private en la línea seis. Sin embargo, si eliminamos la línea 38 del código 06, podremos compilar el código, ya que las rutinas SAVE y RESTORE son públicas, precisamente porque incluimos la cláusula public en la línea doce. Sé que en este momento puede resultar confuso, pero créeme, es mucho más simple de lo que imaginas, sobre todo porque a partir de aquí empezamos a utilizar una forma de programación estructural al incluir las cláusulas public y private en nuestro código.
Consideraciones finales
Bien, llegamos al final de este artículo. Sin embargo, este artículo es especial. Esto se debe a que en este momento entramos en lo que se conoce como programación estructural, donde creamos pequeñas estructuras de datos y las contextualizamos mediante el uso de procedimientos y funciones orientados única y exclusivamente a tratar, mantener y analizar los datos presentes dentro de una estructura de código.
Sé que, en un primer momento, todo esto puede resultar muy complicado y confuso, sobre todo porque para muchos ha sido el primer contacto real con esta forma de implementación de código. En el anexo tienes acceso a los principales códigos vistos aquí, para que puedas entrenar, practicar y estudiar con más calma cada detalle mostrado en este artículo.
Es muy importante que tú, querido lector, crees un concepto adecuado sobre el contenido de este artículo. Si se comprende debidamente, los próximos pasos serán mucho más sencillos. Además, la comprensión de las clases, que se explicarán más adelante, será mucho más fácil y sencilla. De cualquier manera, aquí solo se ha hecho una breve introducción al tema.
En el próximo artículo, entraremos en más detalles sobre lo visto aquí. Sin embargo, no dejes de estudiar esta base inicial, ya que te facilitará bastante la comprensión de los contenidos de los próximos artículos.
Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/15847





- 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