Galerie der in MQL geschriebenen UIs - Seite 77

 
Hört sich toll an, Peter, ich denke, wenn Sie die VE verwenden, um sich selbst zu bauen, wird sie Ihnen definitiv einige wertvolle Einblicke geben, wie Ihr UI-Design funktioniert.
Ich freue mich auf das nächste Entwicklungsupdate.
 
Douglas Prager #:
Das klingt großartig, Peter. Ich denke, wenn Sie VE verwenden, um selbst zu bauen, wird es Ihnen wertvolle Einblicke geben, wie Ihr UI-Design funktioniert.
Ich freue mich schon auf das nächste Entwicklungsupdate.
Vielen Dank, Douglas. Sie haben Recht, das ist genau richtig. Es gibt einen minimalen technischen "Schwellenwert" zu überwinden.

Ich werde auch Ihre grundlegende Entwicklung mit Interesse verfolgen.
 
Doerk Hilger #:
UI ist immer noch 100% reines MQL.
Alles vektorbasiert, voll skalierbar und an jedes Display anpassbar.
Alle visuellen Anzeigen arbeiten asychron innerhalb einer Kernklasse, die alle MQL-Ereignisse behandelt und an Objekte verteilt, abhängig von ihren Abonnementeinstellungen und basierend auf Ereignisprioritäten.

Ich hoffe, ich stehle nicht den sehr interessanten Thread und verzeihen Sie mir, Peter, wenn ich es tue, es wird keine Diskussion sein, ich hoffe nur auf eine kurze Antwort für das theorethische Interesse - meinen Sie, Sie haben eine Art statische Klasse, die alle im System instanziierten Klassenobjekte kennt (behält alle Objektzeiger im Auge) und jedes Objekt hat Zugang, um sich für erforderliche Ereignisse auf dieser statischen Steuerklasse zu abonnieren, und diese statische Steuersingletonklasse liefert einfach die Ereignisse an alle Objekte? Wenn ja, sehen Sie das als korrekt im Sinne von OOP an oder ist es vielleicht akzeptable ereignisgesteuerte Programmierung? Da Sie darüber geschrieben haben, nehme ich an, dass Sie Fragen dazu annehmen möchten, und wenn ja, lassen Sie sie uns bitte so kurz wie möglich halten, um diesen Thread nicht zu entführen, obwohl er damit zusammenhängt.

 
Amir Yacoby #:

Ich hoffe, ich stehle nicht den sehr interessanten Thread und verzeihen Sie mir, Peter, wenn ich das tue, es wird keine Diskussion sein, sondern ich hoffe auf eine kurze Antwort für das theorethische Interesse - meinen Sie, dass Sie eine Art statische Klasse haben, die alle im System instanziierten Klassenobjekte kennt (behält den Überblick über alle Objektzeiger), und jedes Objekt hat Zugang, um sich für erforderliche Ereignisse auf dieser statischen Steuerklasse zu abonnieren, und diese statische Steuersingletonklasse liefert die Ereignisse einfach an alle Objekte? Wenn ja, sehen Sie das als korrekt im Sinne von OOP an oder ist es vielleicht akzeptable ereignisgesteuerte Programmierung? Da Sie darüber geschrieben haben, nehme ich an, dass Sie Fragen dazu annehmen möchten, und wenn ja, lassen Sie sie uns bitte so kurz wie möglich halten, um diesen Thread nicht zu entführen, obwohl er damit zusammenhängt.

Ja, genau das ist es.
Kurzbeschreibung:

Der Kern empfängt alle MetaTrader-Ereignisse und jedes Objekt kann den Kern abonnieren. Daher musste auch die CObject-Klasse neu entworfen/geändert werden, so dass jedes Objekt eine Funktion namens "public: virtual void OnEACycle(CCycleParams * cpm)" hat. Ein solcher Zyklus könnte dann ein Chart-Ereignis, init, deinit usw. sein. Jedes Objekt kann auch ein "public: virtual void OnEATick()" haben. Netter Nebeneffekt ist, dass man auf diese Weise ein zusätzliches Feature erhält, denn man kann sich auch für das Ende eines Zyklus anmelden, egal welcher es ist. Ziemlich nützlich, um eine Datei zu schließen oder irgendetwas anderes zu beenden, einfach am Ende eines Zyklus.

Außerdem kann jedes CObject-Objekt Childs und auch Subscribers haben. Das heißt, ein Objekt kann seine eigenen Ereignisse auslösen, z.B. wenn etwas angeklickt wurde oder ähnliches. Dann führt man einfach ein object.SubEvent(STH_CLICKED, params) aus. Auf diese Weise kümmert sich das Objekt selbst nicht darum, wer diese Informationen benötigt, sie werden einfach an die Abonnenten verteilt, die ein OnSubEvent(int msg, CSubEventParams * sep) erhalten und damit machen können, was sie wollen.

Alles in allem ist diese Art der Programmierung mehr an die Art der Programmierung angelehnt, die wir aus C# kennen, wo man auch einfach .Invoke() verwendet, um Ereignisse auszulösen und sich nicht darum kümmert, wer sie bekommt.

Es ist eigentlich nicht so super-kompliziert zu implementieren, aber natürlich sind die Details am Ende die Herausforderung, da es ein Kern/Basis für jeden einzelnen EA oder Indikator für die Zukunft ist, der in jedem Szenario funktionieren muss.

 
Um es etwas besser zu verstehen, ist dies die Basisklasse für jeden EA oder Indikator nach der Implementierung.

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)         {}
         
   };
Und ein fertiger EA sieht dann so aus:

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;
 
Natürlich sind Load/Unload/Activate usw. benutzerdefiniert, aber da Sie diesen Event-Kern haben, haben Sie viel mehr Flexibilität als ohne und viel mehr Kontrolle über absolut alles.
Wenn ich die Zeit hätte, würde ich einen Artikel schreiben und die Quellen angeben. Es ist kein Geheimnis, überhaupt keine Magie.
 
Doerk Hilger Kontrolle über absolut alles.
Ich habe mir die von Ihnen erstellte GUI angesehen. Sie gefällt mir sehr gut. Sagen Sie mir, haben Sie es selbst geschrieben oder haben Sie einige MQL-Bibliotheken verwendet?
 
Реter Konow #:
Ich habe mir die von Ihnen erstellte GUI angesehen. Sie gefällt mir sehr gut. Sagen Sie mir, haben Sie es selbst geschrieben oder haben Sie einige MQL-Bibliotheken verwendet?

Ja, danke.
Nein, keine Bibliotheken. Ich habe es von Grund auf selbst entwickelt. Eigentlich ist nur CCanvas von den ursprünglichen angepasst, nichts anderes.

 
Doerk Hilger #:

Ich danke Ihnen.
Nein, keine Bibliotheken. Ich habe es von Grund auf selbst entwickelt. Eigentlich ist nur CCanvas von den ursprünglichen angepasst, nichts anderes.

Es ist nicht einfach, so etwas zu entwickeln. )

Soweit ich weiß, gibt es in der Standard-CCanvas-Klasse keine Funktion zum Zeichnen eines Farbverlaufs, wie haben Sie das Problem mit dem Farbverlauf in Ihrer GUI gelöst?
 
Реter Konow #:
Es ist nicht einfach, so etwas zu machen. )

Soweit ich weiß, gibt es in der Standard-Canvas-Klasse keine Funktion zum Zeichnen eines Farbverlaufs. Wie haben Sie das Problem mit einem Farbverlauf in Ihrer GUI gelöst?

Du meinst die Lichteffekte? Naja, Licht hinzugefügt :D Wie beschrieben, ist CCanvas auch nur in seinen Grundlagen und seiner Struktur angepasst, nicht in seinen Details.

//+------------------------------------------------------------------+
//| 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);
            }
         }
      }   
  }