Diskussion zum Artikel "Grafische Interfaces X: Elemente der Zeit, Listen von Kontrollkästchen und das Sortieren von Tabellen (build 6)" - Seite 2

 

Ich habe jedoch den Eindruck, dass die jüngsten Änderungen in Bezug auf die Angabe von Koordinaten durch einen Versatz vom Rand des Formulars für den Endbenutzer nicht sehr freundlich sind. Konnte der Benutzer früher problemlos zwei Optionen für die Angabe der Position eines Objekts im Fenster verwenden, so ist jetzt eine davon komplizierter geworden. Bei mir sind die Dinge auf dem ganzen Bildschirm so auseinandergefallen.

  1. Früher konnte der Benutzer die x,y-Koordinate des Objekts als Offset von einem beliebigen Rand des Fensterformulars angeben. Dazu genügte es, die Anfangskoordinate dieses Fensters plus/minus den Offset in Pixeln anzugeben. Jetzt ist er gezwungen, nur noch vom linken Rand des Formulars auszugehen - was die Möglichkeiten, die genaue Koordinate oder den Versatz der Koordinate in Pixeln von einem beliebigen Rand des Formulars oder Objekts anzugeben, einschränkt.
  2. Konnte der Benutzer früher, ohne die Größe des Objekts, von dem er den Versatz berechnet, in Frage zu stellen, in aller Ruhe ein neues Objekt mit einem Versatz der gewünschten Größe von einer beliebigen Kante des übergeordneten Objekts platzieren, so ist er jetzt gezwungen, die Koordinaten des neuen Objekts jedes Mal neu zu berechnen, wenn er die Größe des Objekts ändert, von dem das neue Objekt mit einem Versatz erstellt wird.
    Beispiel:
    Schaltfläche1 - ihre x-Koordinate ist 4 Pixel vom linken Rand des Formularfensters entfernt. Sie wird wie folgt festgelegt: x=m_window.X()+4; Die Größe der Schaltfläche1 ist 43 Pixel breit. Seine rechte Kante kann wie folgt ermittelt werden: m_butt1.X2();
    Button2 - seine Koordinate ist 2 Pixel von der rechten Kante von Button1 entfernt. Sie wird wie folgt festgelegt: x=m_butt1.X2()+2; Die Größe der Schaltfläche2 ist 24 Pixel breit. Seine rechte Kante kann wie folgt ermittelt werden: m_butt2.X2();
    Button3 - seine Koordinate ist 4 Pixel von der rechten Kante von Button2 entfernt. Sie wird wie folgt gesetzt: x=m_butt2.X2()+4; Die Größe der Schaltfläche3 ist 18 Pixel breit. Seine rechte Kante kann wie folgt ermittelt werden: m_butt3.X2();
    Der vertikale Trennstreifen ist 4 Pixel von der rechten Kante der Schaltfläche3 entfernt: x=m_butt3.X2()+4;
    Wir können also die Größe jeder der drei Schaltflächen leicht ändern, und alle werden sich an dem von uns festgelegten Versatz befinden, und der Trennstreifen wird ordentlich an dem Versatz stehen, den wir von Schaltfläche3 benötigen.
  3. Sehen wir uns nun an, was wir tun müssen, wenn wir die Schnittstelle nach den neuen Regeln aufbauen:
    Button1: x_gap1=4;
    Button2: x_gap2=4+m_butt1.XSize()+2;
    Button3: x_gap3=4+m_butt1.XSize()+2+m_butt2.XSize()+4;
    R-Strip: x_gap4=4+m_butt1.XSize()+2+m_butt2.XSize()+4+m_butt3.XSize()+4;
    Hier wird vorgeschlagen, die X2()-Koordinate anzugeben, anstatt die Objektgrößen zu spezifizieren, aber das ist nicht der Fall - alles fällt sofort auseinander (ich habe mir zum Beispiel den Kopf zerbrochen, als ich vermutete, dass Y2() nicht auf die richtige Y-Koordinatenposition zeigt).

Schauen wir mal: Ich habe die Menükoordinaten mit einem horizontalen Einzug von 1 Pixel und mit einem Einzug in der Größe des "Headers" des Hauptfensters festgelegt. Die Höhe des Menüs beträgt 18 Pixel.

//--- Erstellen des Hauptfenstermenüs
   x=m_window_main.X()+1;
   y=m_window_main.Y()+m_window_main.CaptionHeight();
   h=18;

Das Menü ist an seinem Platz:


Jetzt muss ich die Tabelle vom unteren Rand des Menüs versetzt anordnen. Wenn die CaptionHeight() des Formularfensters 18 Pixel und die Höhe des Menüs ebenfalls 18 Pixel beträgt, dann sollte der vertikale Versatz für die Tabelle 36 Pixel betragen. Es gibt zwei Möglichkeiten: Entweder wir setzen uns mit einem Taschenrechner hin und berechnen alle erforderlichen Offsets (und berechnen sie erneut, falls sich die Größe später ändert), oder wir versuchen, sie zu erhalten. Wir wählen natürlich die zweite Möglichkeit und versuchen es: für die Tabelle sollte y_gap gleich der Höhe des Hauptfensters plus der Höhe des Menüs sein: m_window_main.CaptionHeight()+m_menu_main.YSize();

   //--- Tabelle der Zeichenliste
   x=2;
   y=m_window_main.CaptionHeight()+m_menu_main.YSize()+1;
   w=140;

Kompilieren, holen:


Die Registerkarte ist an ihrem Platz. Aber. Sollte der Y2()-Wert des Menüs in diesem Fall nicht mit dem von uns berechneten Wert übereinstimmen? Schließlich ist es doch bequemer, nicht die Größen aller aufeinander folgenden Objekte zu sammeln, sondern nur ihre Koordinaten zu ermitteln, oder? Versuchen wir es - ändern Sie die Koordinatenberechnung zu ihrer Gewinnung:

   //--- Tabelle der Zeichenliste
   x=2;
   //y=m_window_main.CaptionHeight()+m_menu_main.YSize()+1;
   y=m_menu_main.Y2()+1;
   w=140;

Kompilieren, erhalten:


Sollte Y2() nicht dasselbe Y2 zurückgeben, das wir vorher berechnet haben? m_window_main.CaptionHeight()+m_menu_main.YSize()+1;

Das sollte es nicht - jetzt geben wir keine Koordinaten mit Versatz von irgendeinem Rand des Fensters an, sondern nur Versatz, und nur von oben oder links. Das ist gut. Entfernen Sie von der erhaltenen Y2()-Koordinate die Y()-Koordinate des oberen Randes des Formularfensters, um den Wert des Offsets vom oberen Rand des Formularfensters zu erhalten:

   //--- Tabelle der Zeichenliste
   x=2;
   //y=m_window_main.CaptionHeight()+m_menu_main.YSize()+1;
   y=m_menu_main.Y2()-m_window_main.Y()+1;
   w=140;

Kompilieren Sie und erhalten Sie, was wir wollen:


Bei zwanzig Objekten, die zwei Pixel voneinander entfernt sind, sollten wir also immer ihre Größen plus den Versatz zueinander addieren, um den richtigen Versatz für das letzte Objekt zu erhalten? Schließlich gibt uns Y2() des neunzehnten Objekts (aus dem man zuvor das zwanzigste Objekt nur durch Hinzufügen eines Offsets von zwei Punkten erstellen konnte) jetzt keinen Ausgangspunkt und liefert nicht das, was erwartet wird.... und wir müssen die Größen aller Objekte addieren, um den erforderlichen Versatz zu erhalten, oder wir müssen für jedes Objekt vor seiner Erstellung seinen Versatz auf der Grundlage seiner Y2()-Koordinate und der anfänglichen Y()-Koordinate des Formularfensters berechnen.

Ich verstehe das nicht. Anatoly, bitte gib mir eine Lösung. Was mache ich falsch? Warum ist es überhaupt so? Warum denken Sie, dass es jetzt freundlicher ist? Wenn man früher einfach den Abstand von einem beliebigen Rand des Formularfensters, von einem beliebigen Objekt in diesem Fenster oder sogar vom Rand des Diagramms im Allgemeinen angeben konnte, um das gewünschte Objekt zu erstellen, muss man jetzt einen Tamburintanz aufführen, um seine Koordinaten zu berechnen, bevor man es erstellt? Ist es besser und bequemer, mehr Code und andere Berechnungen zu schreiben?

Ich verstehe, dass Sie der Autor sind und es besser wissen. Aber trotzdem lassen Sie es andere benutzen. Ich denke (nur meine Meinung), dass sich diese Neuerung als die einzige schlechte Entscheidung herausstellte, sie als Update einzuführen - sie wurde schlechter. Es hatte nicht mehr die einfachen Möglichkeiten der Schnittstellenerstellung, die es vorher hatte.

Ich entschuldige mich, wenn ich Sie beleidigt habe (früher wurden Boten mit schlechten Nachrichten geköpft).

 
Artyom Trishkin:

...

Es tut mir leid, wenn ich Sie beleidigt habe.

Ich werde Ihnen etwas später antworten, aber vorher möchte ich gerne klären, was Sie mit diesem Satz in Bezug auf mich meinen. Was ist eine "schlechte Nachricht" und wer ist in diesem Zusammenhang ein "Bote"? :)

 
Anatoli Kazharski:

Ich werde etwas später antworten, aber vorher möchte ich klären, was Sie mit diesem Satz über mich sagen wollten. Was ist eine "schlechte Nachricht" und wer ist in diesem Zusammenhang ein "Bote"? :)

:)

Die schlechte Nachricht nannte ich meine Einstellung zu der Neuerung, dass man nicht mehr jede beliebige Koordinate als Objektkoordinatenbezugspunkt nehmen kann, sondern nur noch den linken und oberen Rand des Formulars (ich habe eine Neuberechnung der Koordinaten in lokalen - unnötigen - Berechnungen hinzugefügt).... Und der Überbringer bin natürlich ich, da es mir nicht gefallen hat und ich es gesagt habe :)

 
Artyom Trishkin:

:)

Die schlechte Nachricht nannte ich meine Einstellung zu der Neuerung, dass man nun nicht mehr jede beliebige Koordinate als Koordinatenbezugspunkt des Objekts nehmen kann, sondern nur noch den linken und oberen Rand der Form (ich habe eine Neuberechnung der Koordinaten in lokalen - unnötigen Berechnungen - hinzugefügt).... Nun, der Bote bin natürlich ich, denn ich mochte es nicht und habe es gesagt :)

So, da habt ihr es. Gut so. Ich dachte nämlich, ich hätte es falsch verstanden. )

Hier ist meine Antwort:

Artyom Trishkin:

Ich denke jedoch, dass die jüngsten Änderungen in Bezug auf die Angabe von Koordinaten durch Versatz vom Formularrand nicht sehr benutzerfreundlich sind. Konnte der Benutzer früher zwei Optionen zur Angabe der Position des Objekts im Fenster verwenden, so ist jetzt eine davon komplizierter geworden. Ich habe schon erlebt, dass Dinge auseinandergefallen sind - und sich so über den ganzen Bildschirm verteilt haben.

...

Schauen wir uns nun an, was wir tun müssen, wenn wir die Schnittstelle nach den neuen Regeln aufbauen:

Button1: x_gap1=4;
Button2: x_gap2=4+m_butt1.XSize()+2;
Button3: x_gap3=4+m_butt1.XSize()+2+m_butt2.XSize()+4;
R Strip: x_gap4=4+m_butt1.XSize()+2+m_butt2.XSize()+4+m_butt3.XSize()+4;

...

Anstatt die Größen der Objekte anzugeben, könnte man versucht sein, ihre X2()-Koordinate anzugeben, aber das ist nicht der Fall - alles fällt sofort auseinander (ich habe mir zum Beispiel den Kopf zerbrochen, bis ich merkte, dass Y2() nicht auf die richtige Stelle der Y-Koordinate zeigt).

Es ist ganz einfach. Früher musste man den Methoden zur Erstellung von Elementen absolute Koordinaten übergeben. Sie mussten relativ zum äußersten linken Punkt des Formulars, an dem das Element befestigt ist, berechnet werden.

Hier ist ein Beispiel dafür, was wir früher tun mussten:

//+------------------------------------------------------------------+
//|| Erzeugt eine Schaltfläche|
//+------------------------------------------------------------------+
bool CProgram::CreateSimpleButton(const int x_gap,const int y_gap,const string button_text)
  {
//--- Speichern des Zeigers auf das Formular
   m_simple_button.WindowPointer(m_window);
//--- Koordinaten
   int x=m_window.X()+x_gap;
   int y=m_window.Y()+y_gap;

//--- Eigenschaften vor der Erstellung festlegen
   m_simple_button.ButtonXSize(100);
//--- Erstellen einer Schaltfläche
   if(!m_simple_button.CreateSimpleButton(m_chart_id,m_subwin,button_text,x,y))
      return(false);
//--- Hinzufügen eines Zeigers auf das Element in der Basis
   CWndContainer::AddToElementsArray(0,m_simple_button);
   return(true);
  }

//---

Jetzt brauchen Sie nichts mehr zu berechnen, da es ausreicht, relative Koordinaten zu übergeben.

Ein Beispiel für das, was jetzt getan werden muss:

//+------------------------------------------------------------------+
//|| Erzeugt eine Schaltfläche|
//+------------------------------------------------------------------+
bool CProgram::CreateSimpleButton(const int x_gap,const int y_gap,const string button_text)
  {
//--- Übergabe des Panel-Objekts
   m_simple_button.WindowPointer(m_window);
//--- Eigenschaften vor der Erstellung festlegen
   m_simple_button.ButtonXSize(100);
//--- Erstellen einer Schaltfläche
   if(!m_simple_button.CreateSimpleButton(m_chart_id,m_subwin,button_text,x_gap,y_gap))
      return(false);
//--- Hinzufügen eines Zeigers auf das Element in der Basis
   CWndContainer::AddToElementsArray(0,m_simple_button);
   return(true);
  }

//---

In deinen obigen Beispielen berechnest du absolute Koordinaten. Dumme Entscheidung, gefolgt von falschen Schlussfolgerungen, die vorschnell veröffentlicht wurden.

Die Methoden CElement ::X(), CElement ::X2(), CElement ::Y() und CElement::Y2() geben absolute Koordinaten der Elementgrenzen zurück. Und es war einfach zu verstehen, indem man diese Werte in das Terminalprotokoll ausgibt, falls es irgendwelche Zweifel gibt.

Nachfolgend ein Beispiel für die Berechnung der Einrückung(relative Koordinate) relativ zu einem Element. Es gibt zwei Schaltflächen. Die X-Koordinate (relativ) für die zweite Schaltfläche wird in Bezug auf den rechten Rand der ersten Schaltfläche berechnet.

//+------------------------------------------------------------------+
//|| Erzeugt die Benutzeroberfläche des Programms.
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
  {
//--- Erstellen eines Panels
   if(!CreateWindow("EXPERT PANEL"))
      return(false);
   if(!CreateSimpleButton1(7,25,"BUTTON 1"))
      return(false);
   if(!CreateSimpleButton2(m_simple_button1.X2()-m_window.X()+5,25,"BUTTON 2"))
      return(false);
//---
   return(true);
  }

//---

Als Ergebnis wird die zweite Schaltfläche mit einem Einzug von 5 Pixel vom rechten Rand der ersten Schaltfläche gesetzt:

//---

Wenn Sie die Breite oder die X-Koordinate der ersten Schaltfläche ändern, wird die Position der zweiten Schaltfläche automatisch angepasst.

Unnötige Berechnungen gibt es also nur in Ihrem oben zitierten Beispiel.

 
Anatoli Kazharski:

//+------------------------------------------------------------------+
//|| Erzeugt die grafische Benutzeroberfläche des Programms.
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
  {
//--- Erstellen eines Panels
   if(!CreateWindow("EXPERT PANEL"))
      return(false);
   if(!CreateSimpleButton1(7,25,"BUTTON 1"))
      return(false);
   if(!CreateSimpleButton2(m_simple_button1.X2()-m_window.X()+5,25,"BUTTON 2"))
      return(false);
//---
   return(true);
  }

//---

Dadurch wird die zweite Schaltfläche mit einem Einzug von 5 Pixeln vom rechten Rand der ersten Schaltfläche gesetzt:

//---

Wenn Sie die Breite oder die X-Koordinate der ersten Schaltfläche ändern, wird die Position der zweiten Schaltfläche automatisch angepasst.

Die zusätzlichen Berechnungen sind also nur in Ihrem oben zitierten Beispiel enthalten.

Hier... Es ist nur nicht ganz klar geworden:

if(!CreateSimpleButton2(m_simple_button1.X2()-m_window.X()+5,25,"BUTTON 2"))

Ich muss diese Neuberechnung in meine Funktionen einbauen, um bei der Angabe der Koordinaten eines neu erstellten Objekts nicht überall diese Neuberechnung zu schreiben, sondern so weiter zu schreiben wie bisher - es ist übersichtlicher, die Beziehung eines Objekts zu einem anderen zu sehen. Das ist natürlich Geschmackssache und Vorlieben eines jeden...

Übrigens fällt der Dateinavigator auch dann auseinander, wenn man Koordinaten angibt, wie Sie sagen. Aber vielleicht liegt es nur an mir. Ich werde nach der Ursache suchen.

Screenshots von der MetaTrader-Handelsplattform

EURUSD, D1, 2016.12.12

MetaQuotes Software Corp., MetaTrader 5, Demo

EURUSD, D1, 2016.12.12, MetaQuotes Software Corp., MetaTrader 5, Demo


 

Anatoly, es sieht so aus, als hätten Sie vergessen, die Datei FileNavigator.mqh in der Datei

//+------------------------------------------------------------------+
//| Erstellt eine Baumliste|
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\folder_w10.bmp"
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\text_file_w10.bmp"
//---
bool CFileNavigator::CreateTreeView(void)
  {
//--- Speichern des Fensterzeigers
   m_treeview.WindowPointer(m_wnd);
//--- Eigenschaften einstellen
   m_treeview.Id(CElement::Id());
   m_treeview.ResizeListAreaMode(true);
   m_treeview.TreeViewAreaWidth(m_treeview_area_width);
   m_treeview.ContentAreaWidth(m_content_area_width);
   m_treeview.AutoXResizeMode(CElement::AutoXResizeMode());
   m_treeview.AutoXResizeRightOffset(CElement::AutoXResizeRightOffset());
   m_treeview.AnchorRightWindowSide(m_anchor_right_window_side);
   m_treeview.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Arrays der Baumliste bilden
   int items_total=::ArraySize(m_g_item_text);
   for(int i=0; i<items_total; i++)
     {
      //--- Definieren Sie das Bild für das Element (Ordner/Datei)
      string icon_path=(m_g_is_folder[i])? m_folder_icon : m_file_icon;
      //--- Wenn es sich um einen Ordner handelt, löschen Sie das letzte Zeichen ('\') in der Zeichenfolge
      if(m_g_is_folder[i])
         m_g_item_text[i]=::StringSubstr(m_g_item_text[i],0,::StringLen(m_g_item_text[i])-1);
      //--- Hinzufügen eines Elements zur Baumliste
      m_treeview.AddItem(i,m_g_prev_node_list_index[i],m_g_item_text[i],icon_path,m_g_item_index[i],
                         m_g_node_level[i],m_g_prev_node_item_index[i],m_g_items_total[i],m_g_folders_total[i],false,m_g_is_folder[i]);
     }
//--- Erstellen einer Baumliste
   if(!m_treeview.CreateTreeView(m_chart_id,m_subwin,m_x-1,m_y+m_address_bar_y_size-1))
      return(false);
//--- Speichern der Abmessungen des Navigators
   CElement::XSize(m_treeview.XSize());
   CElement::YSize(m_treeview.YSize()+m_address_bar_y_size);
   return(true);
  }
//+------------------------------------------------------------------+

Hier müssen Sie sie hinzufügen:

//--- Erstellen einer Baumliste
   if(!m_treeview.CreateTreeView(m_chart_id,m_subwin,m_x-m_wnd.X()-1,m_y-m_wnd.Y()+m_address_bar_y_size-1))
      return(false);
 
Artyom Trishkin:

...

Übrigens stürzt der Dateinavigator auch dann ab, wenn man Koordinaten angibt, wie Sie sagen. Aber vielleicht liegt es nur an mir. Ich habe nach der Ursache gesucht.

Ich habe es selbst nicht reproduzieren können:

 
Anatoli Kazharski:

Ich habe es selbst nicht reproduziert:

Prüfen Sie FileNavigator.mqh im neuesten Update.
 
Artyom Trishkin:
Prüfen Sie FileNavigator.mqh im letzten Update.
Das ist die neueste Version.
 
Anatoli Kazharski:
Das ist die neueste Version.

Ich meine auf der Website in dem Artikel - vielleicht gibt es eine alte zu den Updates genagelt. Ich nehme die Datei aus dem letzten Update, heruntergeladen von der Website vom Ende des Artikels aus dem Zip.

Hier habe ich die Korrekturen vorgenommen, wie ich oben geschrieben habe:

MetaTrader Handelsplattform Bildschirmfotos

EURUSD, W1, 2016.12.12

MetaQuotes Software Corp, MetaTrader 5, Demo

EURUSD, W1, 2016.12.12, MetaQuotes Software Corp, MetaTrader 5, Demo