MetaTrader 5 herunterladen

Grafische Interfaces X: Erweitertes Management von Listen und Tabellen Code Optimierung (build 7)

13 Februar 2017, 09:35
Anatoli Kazharski
0
246

Inhalt

Einführung

Um ein besseres Verständnis von dem Zwecke dieser Bibliothek zu erhalten, lesen Sie bitte den ersten Artikel: Grafische Interfaces I: Vorbereitung der Bibliotheksstruktur (Kapitel 1). Sie finden eine Liste von Artikeln mit Verweisen am Ende jeden Kapitels. Dort können Sie auch die komplette, aktuelle Version der Bibliothek zum derzeitigen Entwicklungsstand herunterladen. Die Dateien müssen im gleichen Verzeichnis wie das Archiv platziert werden.

Der Code der Bibliothek konnte optimiert werden, damit er besser dem Standard folgt und so leichter lesbar und schneller zu verstehen. Weiters werden wir die als letztes entwickelten Kontrollelemente weiterentwickeln: Listen, Tabellen und Bildlaufleisten. Wir ergänzen Methoden, mit denen das Programm selbst die Eigenschaften der Kontrollelemente während der Laufzeit einer MQL-Anwendung regeln kann. 

Änderungen und Optimierungen des Codes der Bibliothek

Teilweise optimierter Code in allen Bibliotheksdateien mit Bezug zu den Kontrollelementen. Sich öfter wiederholender Code wurde in eigenen Methoden platziert und diese Methoden wurden in einer eigenen Klasse zusammengefasst.

Hier sieht man, wie vorgegangen wurde. Das CElement wurde umbenannt in CElementBase. Es ist die Basisklasse aller Kontrollelemente der Bibliothek. Die jetzt erste abgeleitete Klasse ist die neue Klasse CElement mit den Methoden der sich wiederholenden Codeteile aller Kontrollelemente. Diese beinhalten:

  • Methode zur Sicherung der Pointer, die dem Kontrollelement zugeordnet sind
  • Prüfung der Gültigkeit der Pointer
  • Prüfung der Kennungen aktivierter Kontrollelemente
  • Berechnung der absoluten Koordinaten
  • Berechnung der relativen Koordinaten ausgehend von den Kanten

Die Klassen CElementBase und CElement sind jetzt in verschiedenen Dateien, ElementBase.mqh bzw. Element.mqh. Daher wird jetzt die Datei ElementBase.mqh mit der Basisklasse von der Datei Element.mqh geladen. Da der Typ CWindows hier definiert werden muss, laden wir hier auch die Datei Window.mqh. Das Ganze schaut dann so aus:

//+------------------------------------------------------------------+
//|                                                      Element.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "ElementBase.mqh"
#include "Controls\Window.mqh"
//+------------------------------------------------------------------+
//| Klasse zur Abfrage der Mausparameter                             |
//+------------------------------------------------------------------+
class CElement : public CElementBase
  {
protected:
   //--- Pointer auf die zugeordnete Form
   CWindow          *m_wnd;
   //---
public:
                     CElement(void);
                    ~CElement(void);
   //--- Sichern des Pointers auf die Form
   void              WindowPointer(CWindow &object) { m_wnd=::GetPointer(object); }
   //---
protected:
   //--- Prüfung ob der Pointer auf die Form existiert
   bool              CheckWindowPointer(void);
   //--- Prüfung der Kennung des aktivierten Kontrollelementes
   bool              CheckIdActivatedElement(void);
  
   //--- Berechnung der absoluten Koordinaten
   int               CalculateX(const int x_gap);
   int               CalculateY(const int y_gap);
   //--- Berechnung der relativen Koordinaten von den Kanten der Form
   int               CalculateXGap(const int x);
   int               CalculateYGap(const int y);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CElement::CElement(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CElement::~CElement(void)
  {
  }

All diese Methoden mit ihrem jeweiligen Code fand sich wiederholt in allen Klassen der Kontrollelemente. Ihre Überführung in eigene Methoden macht den Code der Klassen leichter les- und verstehbar. Der Code all dieser Methoden ist sehr einfach und besteht eigentlich nur aus einer Zeile (siehe unten). Die Positionierung des Kontrollelementes relativ zu einer Seite der Form wird bei der Berechnung der Koordinaten berücksichtigt.

//+------------------------------------------------------------------+
//| Prüfung der Kennung des aktivierten Kontrollelementes            |
//+------------------------------------------------------------------+
bool CElement::CheckIdActivatedElement(void)
  {
   return(m_wnd.IdActivatedElement()==CElementBase::Id());
  }
//+------------------------------------------------------------------+
//| Berechnung der absoluten X-Koordinate                            |
//+------------------------------------------------------------------+
int CElement::CalculateX(const int x_gap)
  {
   return((CElementBase::AnchorRightWindowSide())? m_wnd.X2()-x_gap : m_wnd.X()+x_gap);
  }
//+------------------------------------------------------------------+
//| Berechnung der absoluten Y-Koordinate                            |
//+------------------------------------------------------------------+
int CElement::CalculateY(const int y_gap)
  {
   return((CElementBase::AnchorBottomWindowSide())? m_wnd.Y2()-y_gap : m_wnd.Y()+y_gap);
  }
//+------------------------------------------------------------------+
//| Berechnung der relativen X-Koordinate von der Kante der Form     |
//+------------------------------------------------------------------+
int CElement::CalculateXGap(const int x)
  {
   return((CElementBase::AnchorRightWindowSide())? m_wnd.X2()-x : x-m_wnd.X());
  }
//+------------------------------------------------------------------+
//| Berechnung der relativen Y-Koordinate von der Kante der Form    |
//+------------------------------------------------------------------+
int CElement::CalculateYGap(const int y)
  {
   return((CElementBase::AnchorBottomWindowSide())? m_wnd.Y2()-y : y-m_wnd.Y());
  }

Man könnte frage: "Warum wurden diese Methoden nicht in der ursprünglichen Klasse CElement platziert?" Das ist nicht möglich: wenn die Datei Window.mqh geladen wird und kompiliert werden soll, entsteht der Fehler Deklaration ohne Typ und viele andere Folgefehler:

 Fig. 1. Kompilermeldung über das Fehlen des Typs CElement

Fig. 1. Kompilermeldung über das Fehlen des Typs CElement

Versuche, das zu vermeiden, durch das Laden von Window.mqh nach dem Codeblock der Klasse CElement, in dem ein Objekt von CWindow bereits deklariert wurde, führt zu ähnlichen Kompilerfehlern, dass der angegebene Typ fehlt.

 Fig. 2. Kompilermeldung über das Fehlen des Typs CWindow

Fig. 2. Kompilermeldung über das Fehlen des Typs CWindow

Daher entschieden wir uns für eine eigene Zwischenklasse für den wiederholt verwendeten Code und den Methoden, um mit den der Form zugeordneten Pointern zu arbeiten. Teile des Schemas der Bibliothek bezüglich der Form und der Kontrollelemente schaut daher wie folgt aus:

 Fig. 3. Teile des Schemas der Bibliothek bezüglich der Form und der Kontrollelemente.

Fig. 3. Teile des Schemas der Bibliothek bezüglich der Form und der Kontrollelemente

Wien man im obigen Schema sieht, wird die Klasse CWindow direkt abgeleitet von der Klasse CElementBase, da die Zwischenklasse CElement jetzt überflüssig und ungeeignet für die Form ist. Alle anderen Klassen des Kontrollelementes leiten sich von der Zwischenklasse CElement ab. 

 

Die Kontrolle einer Bildlaufleiste durch das Programm

Die Notwendigkeit, die Bildlaufleiste vom Programm handhaben zu lassen, entsteht durch die Verwendung der Bibliothek. Dazu wurde die Methode MovingThumb() in den Klassen CScrollV und CScrollH implementiert, die die Bildlaufleiste auf die angegebene Position platziert. 

Der Code unten zeigt nur die senkrechte Bildlaufleiste, ist sie doch praktisch identisch mit der horizontalen. Die Methode hat nur ein Argument mit dem Standardwert WRONG_VALUE. Wird die Methode ohne Angabe einer Position (das wäre der Standard) aufgerufen, wird der Schieberegler auf das letzte Element der Liste gesetzt. Das erleichtert das Hinzufügen neuer Elemente zur Liste während das Programm läuft, und es erlaubt das automatische Verschieben der Liste.

//+------------------------------------------------------------------+
//| Klasse zur Handhabung der vertikalen Bildlaufleiste              |
//+------------------------------------------------------------------+
class CScrollV : public CScroll
  {
public:
   //--- Bewegt den Schieberegler auf die angegebene Position
   void              MovingThumb(const int pos=WRONG_VALUE);
  };
//+------------------------------------------------------------------+
//| Bewegt den Schieberegler auf die angegebene Position             |
//+------------------------------------------------------------------+
void CScrollV::MovingThumb(const int pos=WRONG_VALUE)
  {
//--- Verlassen, wenn die Bildlaufleiste nicht benötigt wird
   if(m_items_total<=m_visible_items_total)
      return;
// --- Prüfung der Position des Schiebereglers
   uint check_pos=0;
//--- Anpassen, falls die Breite verändert wurde
   if(pos<0 || pos>m_items_total-m_visible_items_total)
      check_pos=m_items_total-m_visible_items_total;
   else
      check_pos=pos;
//--- Sichern der Position des Schiebereglers
   CScroll::CurrentPos(check_pos);
//--- Berechne und setze die Y-Koordinate des Schiebereglers der Bildlaufleiste
   CalculateThumbY();
  }

 

Die Kontrolle von Listen durch das Programm

Eine Anzahl von public Methoden zur Handhabung von Listen wurde mit folgenden Möglichkeiten implementiert:

  • Neubildung der Liste
  • Hinzufügen eines Elements am Ende der Liste
  • Löschen der Liste (löschen aller Elemente)
  • Die Liste durchblättern

Zusätzlich wurden auch, als Teil der Codeoptimierung, private Methoden mit wiederholt verwendetem Code der Klasse der Listen hinzugefügt:

  • Berechnung der Y-Koordinate des Elements
  • Die Berechnung der Breite der Elemente
  • Berechnung der Länge der Liste auf der Y-Achse

Betrachten wir die Struktur der Klasse CListView genauer. Die private Methoden sind hauptsächlich Hilfsmethoden mit häufig verwendetem Code in unterschiedlichen Teilen der Klasse. Diese Methoden bestehen meist nur aus einer Zeile:

//+------------------------------------------------------------------+
//| Klasse zum Erstellen der Anzeige einer Liste                     |
//+------------------------------------------------------------------+
class CListView : public CElement
  {
private:
   //--- Berechnung der Y-Koordinate des Elements
   int               CalculationItemY(const int item_index=0);
   //--- Berechnung der Breite der Elemente
   int               CalculationItemsWidth(void);
   //--- Berechnung der Länge einer Liste auf der Y-Achse
   int               CalculationYSize(void);
//+------------------------------------------------------------------+
//| Berechnung der Y-Koordinate des Elements                         |
//+------------------------------------------------------------------+
int CListView::CalculationItemY(const int item_index=0)
  {
   return((item_index>0)? m_items[item_index-1].Y2()-1 : CElementBase::Y()+1);
  }
//+------------------------------------------------------------------+
//| Berechnung der Breite der Elemente                               |
//+------------------------------------------------------------------+
int CListView::CalculationItemsWidth(void)
  {
   return((m_items_total>m_visible_items_total) ? CElementBase::XSize()-m_scrollv.ScrollWidth()-1 : CElementBase::XSize()-2);
  }
//+------------------------------------------------------------------+
//| Berechnung der Länge einer Liste auf der Y-Achse                 |
//+------------------------------------------------------------------+
int CListView::CalculationYSize(void)
  {
   return(m_item_y_size*m_visible_items_total-(m_visible_items_total-1)+2);
  }

Das Löschen der Liste spricht für sich selbst: Entfernung aller Elemente der Liste. Dafür wird die Methode CListView::Clear() verwendet. Sie entfernt zuerst die grafischen Primitiven, dann wird der Array mit den Pointern zu diesen Objekten freigegeben und die Standardwerte werden für manche Felder der Klasse eingetragen. Danach wird die Länge der Liste auf Null gesetzt und die Parameter der Bildlaufleiste zurückgesetzt. Am Ende der Methode muss dann noch der Pointer zum Hintergrund der Liste in den Array der Pointer wieder eingetragen werden, da er vorher duch die Methode CElementBase::FreeObjectsArray() entfernt worden war.

//+------------------------------------------------------------------+
//| Klasse zum Erstellen der Anzeige einer Liste                     |
//+------------------------------------------------------------------+
class CListView : public CElement
  {
public:
   //--- Löschen der Liste (löschen aller Elemente)
   void              Clear(void);
  };
//+------------------------------------------------------------------+
//| Löschen der Liste (löschen aller Elemente)                       |
//+------------------------------------------------------------------+
void CListView::Clear(void)
  {
//--- Lösche die Objekte der Elemente
   for(int r=0; r<m_visible_items_total; r++)
      m_items[r].Delete();
//--- Lösch den Array mit den Pointern zu den Objekten
   CElementBase::FreeObjectsArray();
//--- Setzen der Standardwerte
   m_selected_item_text  ="";
   m_selected_item_index =0;
//--- Setze die Länge der Liste auf Null
   ListSize(0);
//--- Rücksetzen der Werte der Bildlaufleiste
   m_scrollv.Hide();
   m_scrollv.MovingThumb(0);
   m_scrollv.ChangeThumbSize(m_items_total,m_visible_items_total);
//--- Hinzufügen des Hintergrunds der Liste zum Array der Objekte des Kontrollelements
   CElementBase::AddToArray(m_area);
  }

Für die Neuerstellung der Liste, verwenden Sie die Methode CListView::Umbau(). Eine Neuerstellung wird dann ausgeführt, wenn die Liste komplett neu erstellt werden muss. Diese Methode kann verwendet werden, um die Gesamtzahl der Listenelemente oder die Zahl der sichtbaren Elemente zu ändern. Das heißt, die Länge der Liste ändert sich auch, wenn sich die Zahl sichtbarer Elemente ändert.

Die Liste wird zu Anfang der Methode CListView::Rebuilding() gelöscht. Dann werden die Werte der übergebenen Argumente verwendet, um die neue Länge und die Größe der Liste zu bestimmen, falls die Anzahl der sichtbaren Elemente sich geändert hat. Dann wird die Größe der Bildlaufleiste angepasst. Dann erst wird die Liste erstellt und, falls die Gesamtzahl der Elemente die Anzahl der sichtbaren Elemente übertrifft, wird eine Bildlaufleiste angezeigt. 

//+------------------------------------------------------------------+
//| Klasse zum Erstellen der Anzeige einer Liste                     |
//+------------------------------------------------------------------+
class CListView : public CElement
  {
public:
   //--- Neuerstellen der Liste
   void              Rebuilding(const int items_total,const int visible_items_total);
  };
//+------------------------------------------------------------------+
//| Neuerstellen der Liste                                           |
//+------------------------------------------------------------------+
void CListView::Rebuilding(const int items_total,const int visible_items_total)
  {
//--- Löschen der Liste
   Clear();
//--- Bestimme die Gesamtlänge und den sichtbaren Teil der Liste
   ListSize(items_total);
   VisibleListSize(visible_items_total);
//--- Anpassen der Listenlänge
   int y_size=CalculationYSize();
   if(y_size!=CElementBase::YSize())
     {
      m_area.YSize(y_size);
      m_area.Y_Size(y_size);
      CElementBase::YSize(y_size);
     }
//--- Anpassen der Größe der Bildlaufleiste
   m_scrollv.ChangeThumbSize(m_items_total,m_visible_items_total);
   m_scrollv.ChangeYSize(y_size);
//--- Erstellen der Liste
   CreateList();
//--- Anzeigen der Bildlaufleiste, wenn nötig
   if(m_items_total>m_visible_items_total)
     {
      if(CElementBase::IsVisible())
         m_scrollv.Show();
     }
  }

Eine eigene Methode CListView::CreateItem() wurde für das Erstellen eines einzelnen Elementes geschrieben, die verwendet wird, um mit CListView::AddItem() während der Laufzeit Elemente einer Liste hinzuzufügen, aber nicht nur beim Erstellen einer Liste durch die Methode CListView::CreateList(). 

CListView::AddItem() übernimmt nur ein Argument - den anzuzeigenden Text des Elementes. Standardmäßig ist das eine leere Zeichenkette. Text kann auch nach der Erstellung noch mit der Methode CListView::SetItemValue() übergeben werden. Zu Beginn der Methode CListView::AddItem() wird der Array der Elemente um ein Eines verlängert. Wenn jetzt die Anzahl der Elemente aktuell nicht größer ist als die Anzahl der sichtbaren Elemente, bedeutet das, dass ein Grafikobjekt erstellt werden muss. Wird aber die Anzahl der sichtbaren Elemente überschritten, muss die Bildlaufleiste und der Schieberegler wie auch die Breite der Elemente angepasst werden. 

//+------------------------------------------------------------------+
//| Klasse zum Erstellen der Anzeige einer Liste                     |
//+------------------------------------------------------------------+
class CListView : public CElement
  {
public:
   //--- Hinzufügen eines Elementes zur Liste
   void              AddItem(const string value="");
  };
//+------------------------------------------------------------------+
//| Hinzufügen eines Elementes zur Liste                             |
//+------------------------------------------------------------------+
void CListView::AddItem(const string value="")
  {
//--- Verlängere den Array um eins
   int array_size=ItemsTotal();
   m_items_total=array_size+1;
   ::ArrayResize(m_item_value,m_items_total);
   m_item_value[array_size]=value;
//--- Ist die Gesamtzahl der Elemente größer als die der sichtbaren
   if(m_items_total>m_visible_items_total)
     {
      //--- Anpassen der Bildlaufleiste und des Schiebereglers
      m_scrollv.ChangeThumbSize(m_items_total,m_visible_items_total);
      if(CElementBase::IsVisible())
         m_scrollv.Show();
      //--- Verlassen, wenn der Array weniger als ein Element hat
      if(m_visible_items_total<1)
         return;
      //--- Berechnung der Breite der Listenelemente
      int width=CElementBase::XSize()-m_scrollv.ScrollWidth()-1;
      if(width==m_items[0].XSize())
         return;
      //--- Bestimme die neue Größe der Listenelemente
      for(int i=0; i<m_items_total && i<m_visible_items_total; i++)
        {
         m_items[i].XSize(width);
         m_items[i].X_Size(width);
        }
      //---
      return;
     }
//--- Berechnung der Koordinaten
   int x=CElementBase::X()+1;
   int y=CalculationItemY(array_size);
//--- Berechnung der Breite der Listenelemente
   int width=CalculationItemsWidth();
//--- Erstellen des Objektes
   CreateItem(array_size,x,y,width);
//--- Hervorheben des ausgewählten Elementes
   HighlightSelectedItem();
//--- Sichern des Textes des ausgewählten Elementes
   if(array_size==1)
      m_selected_item_text=m_item_value[0];
  }

Die Methode CListView::Scrolling() dient dem automatischen Durchblättern der Liste. Die Positionsnummer ist ihr einziges Argument. Der Standardwert ist WRONG_VALUE, gleichbedeutend mit dem letzten Element der Liste. 

//+------------------------------------------------------------------+
//| Klasse zum Erstellen der Anzeige einer Liste                     |
//+------------------------------------------------------------------+
class CListView : public CElement
  {
public:
   //--- Durchblättern der Liste
   void              Scrolling(const int pos=WRONG_VALUE);
  };
//+------------------------------------------------------------------+
//| Durchblättern der Liste                                          |
//+------------------------------------------------------------------+
void CListView::Scrolling(const int pos=WRONG_VALUE)
  {
//--- Verlassen, wenn die Bildlaufleiste nicht benötigt wird
   if(m_items_total<=m_visible_items_total)
      return;
//--- Bestimme die Position des Schiebereglers
   int index=0;
//--- Index der letzten Position
   int last_pos_index=m_items_total-m_visible_items_total;
//--- Anpassen, falls die Breite überschritten wurde
   if(pos<0)
      index=last_pos_index;
   else
      index=(pos>last_pos_index)? last_pos_index : pos;
//--- Bewege den Schieberegler der Bildlaufleiste
   m_scrollv.MovingThumb(index);
//--- Verschiebe die Liste
   UpdateList(index);
  }

Ähnliche Methode wurden für Listen des Typs CCheckBoxList implementiert. 

 

Codeoptimierung für Tabellen vom Typ CTable

Der Code der Klasse CTable wurde ebenfalls optimiert. Er ist kompakter und leichter lesbar durch mehrere private Methoden mit öfter benötigten Codeteilen. Diese Methoden sind:

  • Größenanpassung der Arrays der Zeilen
  • Initialisierung der Zellen mit Standardwerten
  • Berechnung der Tabellengröße auf der X-Achse
  • Berechnung der Tabellengröße auf der Y-Achse
  • Berechnung der X-Koordinate der Zelle
  • Berechnung der Y-Koordinate der Zelle
  • Berechnung der Spaltenbreite
  • Veränderung der Spaltenbreite
  • Änderung der Tabellengröße auf der Y-Achse
//+------------------------------------------------------------------+
//| Klasse zum Erstellen einer Tabelle mit Bearbeitungsfelder        |
//+------------------------------------------------------------------+
class CTable : public CElement
  {
private:
   //--- Größenanpassung der Arrays der Zeilen
   void              RowResize(const uint column_index,const uint new_size);
   //--- Initialisierung der Zellen mit Standardwerten
   void              CellInitialize(const uint column_index,const int row_index=WRONG_VALUE);
   //--- Berechnung der Tabellengröße auf der X-Achse
   int               CalculationXSize(void);
   //--- Berechnung der Tabellengröße auf der Y-Achse
   int               CalculationYSize(void);
   //--- Berechnung der X-Koordinate der Zelle
   int               CalculationCellX(const int column_index=0);
   //--- Berechnung der Y-Koordinate der Zelle
   int               CalculationCellY(const int row_index=0);
   //--- Berechnung der Spaltenbreite
   int               CalculationColumnWidth(const bool is_last_column=false);
   //--- Veränderung der Spaltenbreite
   void              ColumnsXResize(void);
   //--- Änderung der Tabellengröße auf der Y-Achse
   void              YResize(void);
  };

Die Methode CTable::CalculationColumnWidth() berechnet die Breite der Spalten der Tabelle und erwartet nur ein Argument mit dem Wert false. Dieser Standardwert führt zur Gesamtbreite aller Spalten. Wird aber der Wert true übergeben, wird nur die Breite der letzten Spalte berechnet. In diesem Fall wird ein rekursiver Methodenaufruf verwendet. Die zweiteilige Berechnung von entweder allen oder nur der letzte Spalte ist dadurch bedingt, dass einen allgemeine Berechnung der letzten Spalte unter Umständen nicht zur rechten Kante der Tabelle passen könnte.

//+------------------------------------------------------------------+
//| Berechnung der Spaltenbreite                                  |
//+------------------------------------------------------------------+
int CTable::CalculationColumnWidth(const bool is_last_column=false)
  {
   int width=0;
//--- Prüfung der Existenz einer vertikalen Bildlaufleiste
   bool is_scrollv=m_rows_total>m_visible_rows_total;
//---
   if(!is_last_column)
     {
      if(m_visible_columns_total==1)
         width=(is_scrollv)? m_x_size-m_scrollv.ScrollWidth() : width=m_x_size-2;
      else
        {
         if(is_scrollv)
            width=(m_x_size-m_scrollv.ScrollWidth())/int(m_visible_columns_total);
         else
            width=m_x_size/(int)m_visible_columns_total+1;
        }
     }
   else
     {
      width=CalculationColumnWidth();
      int last_column=(int)m_visible_columns_total-1;
      int w=m_x_size-(width*last_column-last_column);
      width=(is_scrollv) ? w-m_scrollv.ScrollWidth()-1 : w-2;
     }
//---
   return(width);
  }

Die Methode CTable::ColumnsXResize() wird beim Erstellen einer Tabelle oder bei der Änderung der Tabellenbreite aufgerufen. Hier wird die Methode CTable::CalculationColumnWidth() zur Berechnung der Spaltenbreite aufgerufen, wie oben besprochen. Am Ende dieser Methode, wenn die Tabelle sortiert ist, ist es notwendig, auch die Position des Richtungspfeils der Sortierung anzupassen

//+------------------------------------------------------------------+
//| Ändern der Breite von Spalten                                    |
//+------------------------------------------------------------------+
void CTable::ColumnsXResize(void)
  {
//--- Berechnung der Spaltenbreite</s53><br54/>
   int width=CalculationColumnWidth();
//--- Spalten
   for(uint c=0; c<m_columns_total && c<m_visible_columns_total; c++)
     {
      //--- Berechnung der X-Koordinate
      int x=CalculationCellX(c);
      //--- Anpassen der Breite der letzten Spalte
      if(c+1>=m_visible_columns_total)
         width=CalculationColumnWidth(true);

      //--- Zeilen
      for(uint r=0; r<m_rows_total && r<m_visible_rows_total; r++)
        {
         //--- Koordinaten
         m_columns[c].m_rows[r].X(x);
         m_columns[c].m_rows[r].X_Distance(x);
         //--- Breite
         m_columns[c].m_rows[r].XSize(width);
         m_columns[c].m_rows[r].X_Size(width);
         //--- Ränder der Kanten
         m_columns[c].m_rows[r].XGap(CalculateXGap(x));
        }
     }
//--- Verlassen, wenn die Tabelle nicht sortiert ist
   if(m_is_sorted_column_index==WRONG_VALUE)
      return;
//--- Nächster Index, wenn der Kopfzeilenmodus fix ist
   int l=(m_fix_first_column) ? 1 : 0;
//--- Abfrage der Position des Schiebereglers der horizontalen und vertikalen Bildlaufleiste
   int h=m_scrollh.CurrentPos()+l;
//--- Innerhalb der Grenzen des Arrays
   if(m_is_sorted_column_index>=h && m_is_sorted_column_index<(int)m_visible_columns_total)
     {
      //--- Verschieben des Pfeils auf die Sortierspalte
      ShiftSortArrow(m_is_sorted_column_index);
     }
  }

Sie können den Code andere privater Methoden leicht studieren, die zu Beginn dieser Absatzes aufgelistet sind, da sie über keine komplexe Strukturen verfügen, die zu Fragen führen könnten.

Zusätzlich zu den oben erwähnten Methoden, als Teil der Optimierung, wurde eine private Methode CTable::CreateCell() implementiert, die Zellen einer Tabelle erstellt. Ein weitere sinnvolle Ergänzung zu den Tabellen des Typs CTable ist die automatische Formatierung im Zebrastil. Davor musste man, um gestreifte Tabelle für eine bessere Darstellung der Daten erzeugen zu können, die Methode CTable::CellColor() verwendet werden. Das bedeutete, man musste jeder Zelle einzeln ihre Farbe zuweisen. Das ist unbequem und Zeitverschwendung. Jetzt muss man nur noch die Methode CTable::IsZebraFormatRows() vor dem Erstellen des Kontrollelementes aufrufen und die zweite Farbe als einziges Argument übergeben, um eine gestreifte Tabelle zu erhalten. Der Wert, der durch die Methode CTable::CellColor() für alle Zellen der Tabelle bestimmt wurde (standardmäßig ist das Weiß), wird als erste Farbe verwendet. 

//+------------------------------------------------------------------+
//| Klasse zum Erstellen einer Tabelle mit Bearbeitungsfelder        |
//+------------------------------------------------------------------+
class CTable : public CElement
  {
private:
   //--- Modus einer im Zebrastil gestreifte Tabelle
   color             m_is_zebra_format_rows;
   //---
public:
   //--- Modus der Formatierung der Zeilen im Zebrastil
   void              IsZebraFormatRows(const color clr)                         { m_is_zebra_format_rows=clr;      }
  };

Wenn die zweite Farbe für das Formatieren im Zebrastil bestimmt ist, kann die private Methode CTable::ZebraFormatRows() aufgerufen werden, wenn immer es nötig ist. 

//+------------------------------------------------------------------+
//| Klasse zum Erstellen einer Tabelle mit Bearbeitungsfelder        |
//+------------------------------------------------------------------+
class CTable : public CElement
  {
private:
   //--- Formatieren der Tabelle im Zebrastil
   void              ZebraFormatRows(void);
  };
//+------------------------------------------------------------------+
//| Formatieren der Tabelle im Zebrastil                             |
//+------------------------------------------------------------------+
void CTable::ZebraFormatRows(void)
  {
//--- Verlassen, wenn dieser Modus deaktiviert ist
   if(m_is_zebra_format_rows==clrNONE)
      return;
//--- Die Standardfarbe
   color clr=m_cell_color;
//---
   for(uint c=0; c<m_columns_total; c++)
     {
      for(uint r=0; r<m_rows_total; r++)
        {
         if(m_fix_first_row)
           {
            if(r==0)
               continue;
            //---
            clr=(r%2==0)? m_is_zebra_format_rows : m_cell_color;
           }
         else
            clr=(r%2==0)? m_cell_color : m_is_zebra_format_rows;
         //--- Store the cell background color in the common array
         m_vcolumns[c].m_cell_color[r]=clr;
        }
     }
  }

 

Die Kontrolle einer Tabelle vom Typ CTable durch das Programm

In dieser Aktualisierung der Bibliothek erhalten nur die Tabellen vom Typ CTable eine programmgesteuerte Kontrolle. Mehrere public Methoden wurden implementiert, die Folgendes ausführen:

  • Neuerstellung einer Tabelle
  • Ergänzung einer Tabelle
  • Ergänzung einer Zeile
  • Löschen einer Tabelle (Löschen aller Spalten und Zeilen)
  • Horizontales und vertikales Blättern durch die Tabelle
//+------------------------------------------------------------------+
//| Klasse zum Erstellen einer Tabelle mit Bearbeitungsfelder        |
//+------------------------------------------------------------------+
class CTable : public CElement
  {
public:
   //--- Neuerstellung einer Tabelle
   void              Rebuilding(const int columns_total,const int visible_columns_total,const int rows_total,const int visible_rows_total);
   //--- Hinzufügen einer Spalte
   void              AddColumn(void);
   //--- Hinzufügen einer Zeile
   void              AddRow(void);
   //--- Löschen einer Tabelle (Löschen aller Spalten und Zeilen)
   void              Clear(void);
   //--- Durch die Tabelle blättern: (1) vertikal und (2) horizontal
   void              VerticalScrolling(const int pos=WRONG_VALUE);
   void              HorizontalScrolling(const int pos=WRONG_VALUE);
  };

Die Methode CTable::Clear() zum Löschen einer Tabelle wird nicht besprochen: sie ist praktisch identisch mit der für Listen, und die wurde im vorherigen Absatz behandelt.

Für eine Neuerstellung einer Tabelle muss die Methode CTable::Rebuilding() aufgerufen werden, der die Gesamtzahl der Spalten und Zeilen und die jew. Anzahl, die von denen sichtbar sind, als Argument übergeben werden. Hier wird, zu Beginn der Methode die ganze Tabelle gelöscht. Das heißt, alle Spalten und Zeilen werden gelöscht. Dann wird die neue Größe der Tabelle bestimmt und die Werte als Argumente übergeben. Die Bildlaufleisten werden gesetzt in Abhängigkeit der Gesamtzahl der Spalten und Zeilen und ihrer jew. Sichtbarkeit. Nach all dem werden die Zellen erstellt und, wenn nötig, die Bildlaufleisten gezeigt. 

//+------------------------------------------------------------------+
//| Neuerstellung einer Tabelle                                      |
//+------------------------------------------------------------------+
void CTable::Rebuilding(const int columns_total,const int visible_columns_total,const int rows_total,const int visible_rows_total)
  {
//--- Löschen der Tabelle
   Clear();
//--- Bestimmung der Tabellengröße und des sichtbaren Anteils
   TableSize(columns_total,rows_total);
   VisibleTableSize(visible_columns_total,visible_rows_total);
//--- Anpassen der Größe der Bildlaufleiste
   m_scrollv.ChangeThumbSize(rows_total,visible_rows_total);
   m_scrollh.ChangeThumbSize(columns_total,visible_columns_total);
//--- Prüfung der Existenz der vertikalen Bildlaufleiste
   bool is_scrollv=m_rows_total>m_visible_rows_total;
//--- Prüfung der Existenz der horizontalen Bildlaufleiste
   bool is_scrollh=m_columns_total>m_visible_columns_total;
//--- Berechnung der Tabellengröße entlang der Y-Achse
   int y_size=CalculationYSize();
//--- Anpassung der vertikalen Bildlaufleiste
   m_scrollv.ChangeYSize(y_size);
//--- Größenanpassung der Tabelle
   m_y_size=(is_scrollh)? y_size+m_scrollh.ScrollWidth()-1 : y_size;
   m_area.YSize(m_y_size);
   m_area.Y_Size(m_y_size);
//--- Anpassen der Position der horizontalen Bildlaufleiste entlang der Y-Achse
   m_scrollh.YDistance(CElementBase::Y2()-m_scrollh.ScrollWidth());
//--- Wenn eine horizontale Bildlaufleiste benötigt wird
   if(is_scrollh)
     {
      //--- Setze die Größe gemäß des Vorhandenseins einer vertikalen Bildlaufleiste
      if(!is_scrollv)
         m_scrollh.ChangeXSize(m_x_size);
      else
        {
         //--- Berechnen und Ändern der Breite der horizontalen Bildlaufleiste
         int x_size=m_area.XSize()-m_scrollh.ScrollWidth()+1;
         m_scrollh.ChangeXSize(x_size);
        }
     }
//--- Erzeugen einer Tabellenzelle
   CreateCells();
//--- Anzeige der Bildlaufleiste, wenn nötig
   if(rows_total>visible_rows_total)
     {
      if(CElementBase::IsVisible())
         m_scrollv.Show();
     }
   if(columns_total>visible_columns_total)
     {
      if(CElementBase::IsVisible())
         m_scrollh.Show();
     }
  }

Die Methoden des Hinzufügens von Spalten CTable::AddColumn() und Zeilen CTable::AddRow() sind fast gleich, wir werden hier daher nur eine besprechen. 

Am Anfang der Methode CTable::AddColumn() wird die Größe des Arrays der Spalten und Zeilen dieser Spalte bestimmt. Dann werden die Zellen der hinzugefügten Spalte mit dem Standardwert durch die Methode CTable::CellInitialize() initialisiert. Danach, wenn die Gesamtzahl der der Spalten nicht größer ist als die der sichtbaren: 

  1. Berechnung der Breite der Spalten
  2. Eine Anzahl von Grafikobjekten (Tabellenzellen) der hinzugefügten Spalte wird erstellt
  3. Wenn nötig wird die Tabelle im Zebrastil formatiert
  4. Am Ende der Methode wird die Tabelle aktualisiert

Ergibt es sich, dass, nach der Erhöhung der Arrays der Spalten und Zeilen, die Gesamtzahl der Spalten größer ist als die der sichtbaren, muss eine horizontale Bildlaufleiste gezeigt werden und die Höhe der Tabelle angepasst werden. Danach wird die Tabelle im Zebrastil formatiert und das Programm verlässt die Methode. 

//+------------------------------------------------------------------+
//| Ergänzen einer Spalte zur Tabelle                                |
//+------------------------------------------------------------------+
void CTable::AddColumn(void)
  {
//--- Erhöhen der Arraygröße um ein Element
   uint array_size=ColumnsTotal();
   m_columns_total=array_size+1;
   ::ArrayResize(m_vcolumns,m_columns_total);
//--- Setze die Größe des Arrays der Zeilen
   RowResize(array_size,m_rows_total);
//--- Initialisiere die Arrays mit den Standardwerten
   CellInitialize(array_size);
//--- Wenn die Gesamtzahl der Spalten größer ist als die der sichtbaren
   if(m_columns_total>m_visible_columns_total)
     {
      //--- Anpassen der Tabellengröße entlang der Y-Achse
      YResize();
      //--- Gibt es keine vertikale Bildlaufleiste, erstelle eine horizontale Bildlaufleiste über die gesamte Breite der Tabelle
      if(m_rows_total<=m_visible_rows_total)
         m_scrollh.ChangeXSize(m_x_size);
      //--- Anpassen des Schiebereglers und Anzeigen der Bildlaufleiste
      m_scrollh.ChangeThumbSize(m_columns_total,m_visible_columns_total);
      //--- Zeige die Bildlaufleiste
      if(CElementBase::IsVisible())
         m_scrollh.Show();
      //--- Formatieren im Zebrastil
      ZebraFormatRows();
      //--- Aktualisieren der Tabelle
      UpdateTable();
      return;
     }
//--- Berechnen der Spaltenbreite
   int width=CalculationColumnWidth();
//--- Anpassen der Breite der letzten Spalte
   if(m_columns_total>=m_visible_columns_total)
      width=CalculationColumnWidth(true);
//--- Berechnung der X-Koordinate
   int x=CalculationCellX(array_size);
//---
   for(uint r=0; r<m_rows_total && r<m_visible_rows_total; r++)
     {
      //--- Berechnung der Y-Koordinate
      int y=CalculationCellY(r);
      //--- Erstelle das Objekt
      CreateCell(array_size,r,x,y,width);
      //--- Setze die entsprechenden Farbe der Kopfzeile
      if(m_fix_first_row && r==0)
         m_columns[array_size].m_rows[r].BackColor(m_headers_color);
     }
//--- Formatieren der Zeilen im Zebrastil
   ZebraFormatRows();
//--- Aktualisieren der Tabelle
   UpdateTable();
  }

Die Methoden CTable::VerticalScrolling() und CTable::HorizontalScrolling() zum Blättern durch eine Tabelle praktisch identisch mit denen im Absatz über die Listen, sie werden daher hier nicht weiter besprochen. Sie finden sie in den beigefügten Dateien.

Jetzt erstellen wir ein MQL-Testprogramm, das die neuen Möglichkeiten der Listen und Tabellen vom Typ CTable demonstriert. 

 

Anwendung zum Testen der Kontrollelemente

Zum Zwecke des Testens erstellen wir eine MQL-Anwendung, die uns sofort die neuen Arbeitsweisen der Klassen der Listen und Tabellen vom Typ CTable zeigt. Wir erstellen zwei Karteireiter im der grafische Benutzeroberfläche dieser Anwendung. Unter dem ersten Karteireiter ist eine Tabelle vom Typ CTable und Kontrollelementen über der Tabelle für die Handhabung ihrer Eigenschaften. Es gibt zwei Tasten und vier Zahlenfelder:

  • Die Taste «CLEAR TABLE» zum Löschen der Tabelle (Löschen aller Spalten und Zeilen)
  • Die taste «REBUILD TABLE» zum Neuerstellen der Tabelle mit den Parametern der Zahlenfelder
  • Im Zahlenfeld «Rows total» wird die Gesamtzahl der Zeilen der Tabelle eingetragen
  • Im Zahlenfeld «Columns total» wird die Gesamtzahl der Spalten der Tabelle eingetragen
  • Im Zahlenfeld «Visible rows total» steht die Zahl der sichtbaren Zeilen
  • Im Zahlenfeld «Visible columns total» steht die Zahl der sichtbaren Spalten

Der Screenshot unten zeigt wie alles aussieht:

 Fig. 4. Gruppe von Kontrollelementen unter dem ersten Karteireiter.

Fig. 4. Gruppe von Kontrollelement unter dem ersten Karteireiter

Unter dem zweiten Karteireiter gibt es zwei Listen (Listenansicht und eine Liste mit Kontrollkästchen). Um die programmgesteuerte Verwaltung von Listen zu demonstrieren, gibt es folgende Steuerelemente:

  • Die Taste «CLEAR LISTS» zum Löschen der Liste (löschen aller Elemente)
  • Die Taste «REBUILD LISTS» zum Neuerstellen der Liste mit den in den Zahlenfeldern angegebenen Werten
  • Im Zahlenfeld «Items total» wird die Gesamtzahl der Elemente angegeben
  • Im Zahlenfeld «Visible items total» wird die Anzahl der sichtbaren Elemente angegeben

 Der Screenshot unten zeigt die Kontrollelemente des zweiten Karteireiters. Zwei weitere Kontrollelemente wurden ergänzt: Ein Drop-Down-Kalender und das Zeitelement. 

 Fig. 5. Gruppe der Kontrollelemente unter dem zweiten Karteireiter.

Fig. 5. Gruppe der Kontrollelemente unter dem zweiten Karteireiter

Bevor wir mit weiteren Beispielen zu den Eigenschaften von Listen und Tabellen fortfahren, erwähnen wir noch kurz eine weitere Ergänzung, die die Arbeit eines MQL-Entwicklers mit Zeitelementen in seiner MQL-Anwendung erleichtert. Das ist die Klasse CTimeCounter. Sie kann für eine regelmäßige Aktualisierung (Neuzeichnen) unterschiedlicher Gruppen grafische Benutzeroberflächen zu festgelegten Zeiten verwendet werden. Die Klasse CTimeCounter verfügt über drei Felder und zwei Methoden (siehe den Code unten).

//+------------------------------------------------------------------+
//|                                                  TimeCounter.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Zeitzähler                                                       |
//+------------------------------------------------------------------+
class CTimeCounter
  {
private:
   //--- Schritt des Zähler
   uint              m_step;
   //--- Zeitspanne
   uint              m_pause;
   //--- Zeitzähler
   uint              m_time_counter;
   //---
public:
                     CTimeCounter(void);
                    ~CTimeCounter(void);
   //--- Bestimmen von Schritt und Zeitspanne
   void              SetParameters(const uint step,const uint pause);
   //--- Prüfung, ob das angegebene Zeitintervall verstrichen ist
   bool              CheckTimeCounter(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTimeCounter::CTimeCounter(void) : m_step(16),
                                   m_pause(1000),
                                   m_time_counter(0)
                                  
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTimeCounter::~CTimeCounter(void)
  {
  }

Die Methode CTimeCounter::SetParameters() kann zum Setzen des Zählerinkrements und der Zeitspanne für die Dauer der Pause verwendet werden:

//+------------------------------------------------------------------+
//| Bestimmen von Schritt und Zeitspanne                             |
//+------------------------------------------------------------------+
void CTimeCounter::SetParameters(const uint step,const uint pause)
  {
   m_step  =step;
   m_pause =pause;
  }

Die Methode CTimeCounter::CheckTimeCounter() ist gedacht für die Prüfung, ob die in den Klassenparametern vereinbarte Zeitspanne verstrichen ist. Ist die Zeitspanne verstrichen, gibt die Methode true zurück.

//+------------------------------------------------------------------+
//| Prüfung, ob das angegebene Zeitintervall verstrichen ist         |
//+------------------------------------------------------------------+
bool CTimeCounter::CheckTimeCounter(void)
  {
//--- Erhöhe den Zähler, wenn die vereinbarte Zeitspanne noch nicht verstrichen ist
   if(m_time_counter<m_pause)
     {
      m_time_counter+=m_step;
      return(false);
     }
//--- Zähler auf Null setzen
   m_time_counter=0;
   return(true);
  }

Vor dem nächsten Schritt sollte erwähnt werden, dass der Ort, an dem die Dateien liegen sollten, sich auch geändert hat. Nur Dateien, die die Kassen der Kontrollelemente enthalten sollten jetzt im Verzeichnis «MetaTrader 5\MQL5\Include\EasyAndFastGUI\Controls» liegen. Alle anderen Dateien müssen in das Wurzelverzeichnis: «MetaTrader 5\MQL5\Include\EasyAndFastGUI» verschoben werden. Daher, um die Bibliotheken laden zu können, muss jetzt auch der Pfad angegeben werden, wie unten angegeben. Es wird auch gezeigt, wie eine Datei mit der Klasse CTimeCounter geladen wird (wird im Bespieltest verwendet). 

//+------------------------------------------------------------------+
//|                                                      Program.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <EasyAndFastGUI\WndEvents.mqh>
#include <EasyAndFastGUI\TimeCounter.mqh>

Die Parameter des Zeitzählers werden im Constructor gesetzt:

//+------------------------------------------------------------------+
//| Klasse der Erstellung einer Anwendung                            |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
protected:
   //--- Zeitzähler
   CTimeCounter      m_counter1; // for updating the status bar
   CTimeCounter      m_counter2; // for updating the lists and the table
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CProgram::CProgram(void)
  {
//--- Setzen der Parameter des Zeitzählers
   m_counter1.SetParameters(16,500);
   m_counter2.SetParameters(16,150);
  }

Beispiel über das Hinzufügen von Elementen in Listen und von Zeilen und Spalten in eine Tabelle implementiert in einem Timer. Nach der angegebenen Zeitspanne werden, falls die Anzahl der Elemente/Zeilen/Spalten kleiner ist als in den entsprechenden Eingabefeldern, diese in diesem Codeblock hinzugefügt (siehe der Code unten). Um die programmgesteuerte Handhabung der Bildlaufleiste zu demonstrieren, wird jedes Mal, wenn ein Element ergänzt wurde, der Schieberegler der Bildlaufleiste an das Ende der Liste gesetzt

//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void CProgram::OnTimerEvent(void)
  {
   CWndEvents::OnTimerEvent();
...
//--- Pause zwischen der Aktualisierung der Kontrollelemente
   if(m_counter2.CheckTimeCounter())
     {
      //--- Ergänzen einer neuen Zeile zur Tabelle, wenn die Gesamtzahl kleiner als angegeben ist
      if(m_table.RowsTotal()<m_spin_edit1.GetValue())
         m_table.AddRow();
      //--- Ergänzen einer neuen Spalte zur Tabelle, wenn die Gesamtzahl kleiner als angegeben ist
      if(m_table.ColumnsTotal()<m_spin_edit2.GetValue())
         m_table.AddColumn();
      //--- Ergänzen eines neuen Elementes zur Liste, wenn die Gesamtzahl kleiner als angegeben ist
      if(m_listview.ItemsTotal()<m_spin_edit5.GetValue())
        {
         m_listview.AddItem("SYMBOL "+string(m_listview.ItemsTotal()));
         //--- Setze den Schieberegler der Bildlaufleiste ans Ende der Liste
         m_listview.Scrolling();
        }
      //--- Ergänzen eines neuen Elementes zur Liste der Kontrollkästchen, wenn die Gesamtzahl kleiner als angegeben ist
      if(m_checkbox_list.ItemsTotal()<m_spin_edit5.GetValue())
        {
         m_checkbox_list.AddItem("Checkbox "+string(m_checkbox_list.ItemsTotal()));
         //--- Setz den Schieberegler der Bildlaufleiste ans Ende der Liste
         m_checkbox_list.Scrolling();
        }
      //--- Alles Neuzeichnen
      m_chart.Redraw();
     }
  }

Die Handhabung der Ereignisse durch das Drücken der Tasten für die Löschen oder Neubilden von Listen oder Tabellen funktioniert wie folgt: 

//+------------------------------------------------------------------+
//| Event Handler                                                    |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- Das Ereignis einer gedrückten Taste
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     {
      Print(__FUNCTION__," > id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam);
      //--- Das Ereignis der ersten Taste
      if(lparam==m_simple_button1.Id())
        {
         //--- Tabelle löschen
         m_table.Clear();
         return;
        }
      //--- Ereignis der zweiten Taste
      if(lparam==m_simple_button2.Id())
        {
         //--- Neubilden der Tabelle
         m_table.Rebuilding((int)m_spin_edit3.GetValue(),(int)m_spin_edit4.GetValue(),
                            (int)m_spin_edit1.GetValue(),(int)m_spin_edit2.GetValue());
         //--- Initialisierung der Tabelle
         InitializeTable();
         //--- Aktualisieren der Tabelle zur Anzeige der Änderungen
         m_table.UpdateTable();
         return;
        }
      //--- Ereignis der dritten Taste
      if(lparam==m_simple_button3.Id())
        {
         //--- Löschen der Liste
         m_listview.Clear();
         m_checkbox_list.Clear();
         return;
        }
      //--- Ereignis der zweiten Taste
      if(lparam==m_simple_button4.Id())
        {
         //--- Neubilden der Liste
         m_checkbox_list.Rebuilding((int)m_spin_edit5.GetValue(),(int)m_spin_edit6.GetValue());
         m_listview.Rebuilding((int)m_spin_edit5.GetValue(),(int)m_spin_edit6.GetValue());
         //--- Auswahl des achten Elementes in der Listenansicht
         m_listview.SelectItem(7);
         //--- Ausfüllen der Liste mit Daten
         int items_total=m_listview.ItemsTotal();
         for(int i=0; i<items_total; i++)
            m_listview.SetItemValue(i,"SYMBOL "+string(i));
         //--- Ausfüllen der Liste der Kontrollkästchen mit Daten, markieren Sie jedes zweite Kästchen
         items_total=m_checkbox_list.ItemsTotal();
         for(int i=0; i<items_total; i++)
           {
            m_checkbox_list.SetItemValue(i,"Checkbox "+string(i));
            m_checkbox_list.SetItemState(i,(i%2!=0)? true : false);
           }
         //---
         return;
        }
      //---
      return;
     }
  }

Die Testanwendung dieses Artikels kann mittel des Links unten heruntergeladen werden für ein weiteres Studieren. 

 

Schlussfolgerung

Zur Zeit schaut das Schema der Bibliothek zum Erstellen einer grafische Benutzeroberfläche wie folgt aus:

 Fig. 6. Struktur der Bibliothek im augenblicklichen Entwicklungszustand.

Fig. 6. Struktur der Bibliothek im augenblicklichen Entwicklungszustand.

In der nächsten Version dieser Bibliothek werden die bestehenden Kontrollelemente verbessert und mit neuen Möglichkeiten erweitert. Unten könne Sie die letzten Versionen der Bibliothek und der Dateien zum Testen herunterladen.

Bei Fragen zur Verwendung des bereitgestellten Materials, können Sie auf die detaillierten Beschreibungen im Lauf der Entwicklung der Bibliothek in den vorangegangenen Artikeln dieser Serie zurückgreifen oder sie stellen Ihre Fragen im Kommentarteil diese Artikels. 

Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/2943

Beigefügte Dateien |
Grafische Interfaces X: Elemente der Zeit, Listen von Kontrollkästchen und das Sortieren von Tabellen (build 6) Grafische Interfaces X: Elemente der Zeit, Listen von Kontrollkästchen und das Sortieren von Tabellen (build 6)

Weiterentwicklung der Bibliothek zum Erstellen grafischer Benutzeroberflächen. Zeit und Listen von Kontrollkästchen werden diesmal behandelt. Weiters verfügt die Klasse CTable jetzt über die Möglichkeit, Daten auf- oder absteigend zu sortieren.

3D-Modellierung in MQL5 3D-Modellierung in MQL5

Eine Zeitreihe stellt ein dynamisches System dar, in welches Werte einer zufälligen Größe einer nach dem anderen eintreffen: kontinuierlich oder in gewissen Zeitabständen. Der Übergang von einer flachen zur dreidimensionalen Analyse des Marktes ermöglicht es, komplexe Prozesse und Erscheinungen aus einer neuen Perspektive zu betrachten. In diesem Artikel werden Visualisierungsfunktionen für eine 3D-Darstellung zweidimensionaler Daten beschrieben.

Integrieren Sie das MetaTrader 4/5 Webterminal in Ihre Webseite - das ist kostenlos, und man kann damit Geld verdienen Integrieren Sie das MetaTrader 4/5 Webterminal in Ihre Webseite - das ist kostenlos, und man kann damit Geld verdienen

Trader sind mit dem Webterminal gut vertraut, in dem man auf Finanzmärkten direkt im Browser handeln kann. Wir schlagen Ihnen vor, das Webterminal auf Ihrer Webseite absolut kostenlos zu platzieren. Sie haben Besucher, Broker sind an neuen Leads interessiert, und wir bieten eine fertige Weblösung an. Damit alles funktioniert, brauchen Sir nur einen iframe in Ihre Webseite zu integrieren.

Grafische Interfaces X: mehrzeiliges Textfeld (build 8) Grafische Interfaces X: mehrzeiliges Textfeld (build 8)

Beschreibung eines mehrzeiligen Textfeldes. Anders als bei Grafikobjekten des Typs OBJ_EDIT ist die vorgestellte Version nicht durch eine Anzahl von Buchstaben beschränkt. Es gibt auch die Funktionen eines einfachen Editors, mit einem durch Maus oder Tasten bewegten Kursor.