Galería de interfaces de usuario escritas en MQL - página 77

 
Douglas Prager #:
Suena genial, Peter. Creo que cuando uses VE para construir tú mismo, te dará valiosas ideas sobre cómo funciona el diseño de tu interfaz de usuario.
Espero con impaciencia la próxima actualización del desarrollo.
Gracias, Douglas. Tienes razón. Hay un "obstáculo" técnico mínimo que superar.

Yo también seguiré con interés su desarrollo fundamental.
 
Doerk Hilger #:
UI sigue siendo 100% puro MQL.
Todo basado en vectores, totalmente escalable y ajustable a cualquier pantalla.
Todas las pantallas visuales funcionan asychronously dentro de una clase principal que maneja y distribuye todos los eventos MQL a los objetos, en función de su configuración de suscripción y sobre la base de eventos-prioridades.

Espero no estar robando el hilo muy interesante y perdóname Peter si lo hago, no va a ser una discusión sólo espero una respuesta corta para el interés theorethical - ¿quieres decir que tienes una especie de clase estática que conoce (realiza un seguimiento de todos los punteros de objeto) todos los objetos de clase instansiated en el sistema y cada objeto tiene acceso a suscribirse a los eventos requeridos en esa clase estática de control y que la clase estática de control singleton sólo entrega los eventos a todos los objetos? Si es así, ¿lo consideras correcto en términos de programación orientada a objetos o es una programación orientada a eventos aceptable? Ya que escribiste sobre ello, supongo que querrás aceptar preguntas al respecto y si es así por favor hagámoslo lo más corto posible para no secuestrar este hilo, aunque está relacionado.

 
Amir Yacoby #:

Espero no estar robando el hilo muy interesante y perdóname Peter si lo hago, no será una discusión sólo espero una respuesta corta para el interés theorethical - ¿quieres decir que tiene una especie de clase estática que conoce (realiza un seguimiento de todos los punteros de objeto) todos los objetos de clase instansiated en el sistema y cada objeto tiene acceso a suscribirse a los eventos requeridos en esa clase estática de control y que la clase singleton de control estático sólo entrega los eventos a todos los objetos? Si es así, ¿lo consideras correcto en términos de programación orientada a objetos o es una programación orientada a eventos aceptable? Ya que escribiste sobre ello, supongo que querrás aceptar preguntas al respecto y si es así por favor hagámoslo lo más corto posible para no secuestrar este hilo, aunque está relacionado.

Sí, eso es exactamente lo que es.
Breve descripción:

El núcleo recibe todos los eventos de MetaTrader y cualquier objeto puede suscribirse al núcleo. Por lo tanto la clase CObject tuvo que ser rediseñada/modificada también, para que cualquier objeto tenga una función llamada "public: virtual void OnEACycle(CCycleParams * cpm)". Este ciclo puede ser un evento gráfico, init, deinit, etc. Cada objeto también puede tener un "public: virtual void OnEATick()". El efecto secundario es que se obtiene una característica extra, ya que se puede suscribir al final de cualquier ciclo, no importa cual sea. Muy útil para cerrar un archivo o terminar cualquier otra cosa, simplemente al final de cualquier ciclo.

Además, cada objeto CObject puede tener hijos y también suscriptores. Esto significa que un objeto puede activar sus propios eventos, como cuando se hace clic en algo o similar. Entonces simplemente ejecutas un object.SubEvent(STH_CLICKED, params). De esta forma, al objeto en sí no le importa quién necesita esta información, simplemente se distribuye a los suscriptores, que reciben un OnSubEvent(int msg, CSubEventParams * sep) y pueden hacer con ello lo que quieran.

En definitiva, esta forma de codificación está más relacionada con la que conocemos de C#, donde también se utiliza .Invoke() para disparar eventos y no te preocupas por quién los recibe.

En realidad no es tan super-complicado de implementar, pero por supuesto los detalles son el reto al final, ya que es un núcleo / base para cada EA o indicador para el futuro que tiene que funcionar en todos los escenarios.

 
Para entenderlo un poco mejor, esta es la clase base para cualquier EA o indicador después de la implementación.

class CEAMain : public CObject
   {
   public: CEAMain()
      {
      m_classname="CEAMain";
      SubscribeToCycle(EA_CYCLE_LOAD);
      SubscribeToCycle(EA_CYCLE_PARAMS);   
      SubscribeToCycle(EA_CYCLE_INIT);   
      SubscribeToCycle(EA_CYCLE_ACTIVATE);
      SubscribeToCycle(EA_CYCLE_TICK);
      SubscribeToCycle(EA_CYCLE_DEINIT);
      SubscribeToCycle(EA_CYCLE_UNLOAD);
      }
      //+------------------------------------------------------------------+
      //| Cycles handler                                                   |
      //+------------------------------------------------------------------+
      public: virtual void OnEACycle(CEACycleParams * cpm)
         {
         switch (cpm.Cycle)
            {
            case EA_CYCLE_LOAD:        cpm.CycleResult(OnEALoad(PTR(cpm.Init))); break;
            case EA_CYCLE_PARAMS:      cpm.CycleResult(OnEAParams()); break;
            case EA_CYCLE_INIT:        cpm.CycleResult(OnEAInit(PTR(cpm.Init))); break;
            case EA_CYCLE_ACTIVATE:    OnEAActivate(); break;
            case EA_CYCLE_DEINIT:      OnEADeinit(PTR(cpm.Deinit)); break;
            case EA_CYCLE_UNLOAD:      OnEAUnload(PTR(cpm.Deinit)); break;
            case EA_CYCLE_BOOKEVENT:   OnEABookEvent(PTR(cpm.BookEvent)); break;
            }
         }
      //+------------------------------------------------------------------+
      //| Cycles override                                                  |
      //+------------------------------------------------------------------+
      protected: virtual bool OnEALoad(CEAInitParams * ipm)                   { return true; }
      protected: virtual bool OnEAParams(void)                                { return true; }
      protected: virtual bool OnEAInit(CEAInitParams * ipm)                   { return true; } 
      protected: virtual void OnEAActivate(void)                              {}
      protected: virtual void OnEADeinit(CEADeinitParams * dpm)               {}
      protected: virtual void OnEAUnload(CEADeinitParams * dpm)               {}
      protected: virtual void OnEAChartEvent(CEAChartEventParams * cep)       {}
      protected: virtual void OnEABookEvent(CEABookEventParams * cpm)         {}
         
   };
Y un EA final se ve así entonces:

class CMain : public CEAMain
   {
      public: CMain()
         {
         m_classname="MainEA";
         }
      public: ~CMain()
         {
         }         

      //+------------------------------------------------------------------+
      //| Load                                                             |
      //+------------------------------------------------------------------+
      protected: virtual bool OnEALoad(CEAInitParams * ipm)
         {
         Print("Welcome :)");
         return true;
         }
      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      protected: virtual bool OnEAInit(CEAInitParams * ipm)
         { 
         if (ipm.IsFirstInit) return true;
         //--- Account changed init
         if (ipm.IsAccountChanged)
            {
            }
         //--- Symbol change init
         else if (ipm.IsSymbolChanged)    
            {
            }
         return true;
        }
        
      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      protected: virtual void OnEADeinit(CEADeinitParams * dpm)
        {
        }
      protected: virtual void OnEAUnload(CEADeinitParams * dpm)
         {
         DeInit();
         Print("Bye.");
         }  
      ...
      ...
};

// Create the main EA object on a global scope. 
CMain __MainEA;
 
Por supuesto, Load/Unload/Activate etc. son personalizados, pero desde que tienes este event-core, tienes mucha más flexibilidad que sin él y mucho más control sobre absolutamente todo.
Si hubiera tenido tiempo, escribiría un artículo y proporcionaría las fuentes. No es un secreto, no hay magia en absoluto.
 
Doerk Hilger control sobre absolutamente todo.
He visto la GUI que has creado. Me gusta mucho. Dime, ¿lo escribiste tu mismo o usaste algunas librerías MQL?
 
Реter Konow #:
He visto la GUI que has creado. Me gusta mucho. Dime, ¿lo escribiste tú mismo o usaste algunas librerías MQL?

Gracias.
No, no hay bibliotecas. Diseñado desde cero por mí mismo. En realidad sólo se adapta CCanvas de los originales, nada más.

 
Doerk Hilger #:

Gracias.
No, nada de bibliotecas. Lo he desarrollado yo mismo desde cero. En realidad, sólo CCanvas está adaptado de los originales, nada más.

No es fácil hacer algo así. )

Hasta donde yo sé, en la clase estándar Ccanvas no hay funcionalidad para dibujar un gradiente de color, ¿cómo resolviste el problema con un gradiente en tu GUI?
 
Реter Konow #:
No es fácil hacer algo así. )

Hasta donde yo sé, en la clase estándar Ccanvas no hay funcionalidad para dibujar un gradiente de color, ¿cómo resolviste el problema con un gradiente en tu GUI?

¿Te refieres a los efectos de luz? Bueno, luz añadida :D Como se ha descrito, CCanvas también está adaptado sólo en sus fundamentos y su estructura, no en sus detalles.

//+------------------------------------------------------------------+
//| Macro to generate color                                          |
//+------------------------------------------------------------------+
#define XRGB(r,g,b)    (0xFF000000|(uchar(r)<<16)|(uchar(g)<<8)|uchar(b))
#define ARGB(a,r,g,b)  ((uchar(a)<<24)|(uchar(r)<<16)|(uchar(g)<<8)|uchar(b))
#define TRGB(a,rgb)    ((uchar(a)<<24)|(rgb))
#define GETRGB(clr)    ((clr)&0xFFFFFF)
#define GETRGBA(clr)   uchar((clr)>>24)
#define GETRGBR(clr)   uchar((clr)>>16)
#define GETRGBG(clr)   uchar((clr)>>8)
#define GETRGBB(clr)   uchar(clr)
#define COLOR2RGB(clr) (0xFF000000|(uchar(clr)<<16)|(uchar((clr)>>8)<<8)|uchar((clr)>>16))
#define RGB2COLOR(rgb) ((uchar(rgb)<<16)|(uchar((rgb)>>8)<<8)|uchar((rgb)>>16))


//+------------------------------------------------------------------+
//| Add light to rectangular area                                    |
//+------------------------------------------------------------------+
void CCanvasExt::AddLight(int x1, int y1, int x2, int y2, bool updown=true, double intensity=.5, int isoftedge=20, color lightcolor=C'255,255,255')
   {
   if (intensity==0)
      return;
      
   int tmp;
//--- sort vertexes
   if(x2<x1)
     {
      tmp=x1;
      x1 =x2;
      x2 =tmp;
     }
   if(y2<y1)
     {
      tmp=y1;
      y1 =y2;
      y2 =tmp;
     }
//--- out of screen boundaries
   if(x2<0 || y2<0 || x1>=m_width || y1>=m_height)
      return;
//--- stay withing screen boundaries
   if(x1<0)
      x1=0;
   if(y1<0)
      y1=0;
   if(x2>=m_width)
      x2=m_width -1;
   if(y2>=m_height)
      y2=m_height-1;


//--- calculate softedge
   isoftedge=MIN(100,isoftedge);
   int softedge=isoftedge>0 ? isoftedge*(y2-y1)/100 : 0;

//--- correct height
   y2-=(y2-y1)/2;
   y2+=(softedge/2);
   y2++;
   y2=MIN(m_height-1,y2);   
   
//--- prepare 
   COLOR_RGBA rgb=_ColorLumaMult(lightcolor,ABS(intensity));
   double r=(int)GETRGBR(rgb);
   double g=(int)GETRGBG(rgb);
   double b=(int)GETRGBB(rgb);  
   
   if (intensity<0)
      {
      r=0-r;
      g=0-g;
      b=0-b;
      }
   uint pixel;     
   int istart;
   int iend;
   int i;

//--- check direction
   if (updown)
      {
   //--- add main light   
      for(;y1<y2-softedge;y1++)
         {
         istart=y1*m_width+x1;
         iend=istart+(x2-x1);
         for (i=istart;i<=iend;i++)
            {
            pixel=m_pixels[i];
            m_pixels[i]=ARGB(GETRGBA(pixel),MIN(GETRGBR(pixel)+r,0xFF),MIN(GETRGBG(pixel)+g,0xFF),MIN(GETRGBB(pixel)+b,0xFF));// m_pixels[i]+=XRGB(r,g,b);
            //m_pixels[i]|=rgb;
            }
         }
      if (softedge==0)
         return;
   
   //-- Add soft edge 
      double decr=r/softedge;
      double decg=g/softedge;
      double decb=b/softedge;
   
   //--- Loop rows separate and adjust color each row   
      for (;y1<=y2;y1++)
         {
         r-=decr; r=MAX(0,r); 
         g-=decg; g=MAX(0,g); 
         b-=decb; b=MAX(0,b); 
         
         istart=y1*m_width+x1;
         iend=istart+(x2-x1);
         for (i=istart;i<=iend;i++)
            {
            pixel=m_pixels[i];
            m_pixels[i]=ARGB(GETRGBA(pixel),MIN(GETRGBR(pixel)+r,0xFF),MIN(GETRGBG(pixel)+g,0xFF),MIN(GETRGBB(pixel)+b,0xFF));// m_pixels[i]+=XRGB(r,g,b);
            }
         }
      }   
  }   
 
Doerk Hilger #:¿Te refieres a los efectos de iluminación? Bueno, luz añadida :D Como se ha dicho, CCanvas también se adapta sólo en lo básico y la estructura, pero no en los detalles.
Ya veo, gracias. )