Ursprünglich gab es einfach keine solche Aufgabe, dass es notwendig war, Elemente zu verschieben, nachdem die GUI erstellt war. Alles basierte auf der Idee, dass jedes Element bereits das notwendige Verhalten implementiert hatte.
Gegenfragen: Warum müssen Sie Elemente verschieben? Was wollen Sie tun? Welches Verhalten bei der Interaktion mit der grafischen Benutzeroberfläche möchten Sie erreichen?
Um zu verstehen, ob etwas kaputt gehen wird, müssen Sie alle Elemente nach jeder Änderung der Basisklassen testen. Es ist schon schwer, das auf Anhieb zu sagen. Es ist schon eine Weile her, dass ich mich damit beschäftigt habe.
Erstellen Sie eine Test-GUI mit allen Elementen der Bibliothek und testen Sie diese nach Änderungen.
Zum Beispiel aufklappbare Listen. Wenn man klickt, werden einige der Elemente ausgeblendet, alles darunter wird nach oben gezogen. Und andersherum.
Test GUI ist eine gute Idee, ich werde versuchen, es zu machen :)
//--- Wenn die Bindung auf der rechten Seite istif(m_anchor_right_window_side)
{
//--- Speichern von Koordinaten in Elementfeldern
CElementBase::X(m_main.X2()-XGap());
//--- Speichern von Koordinaten in Objektfeldern
m_canvas.X(m_main.X2()-m_canvas.XGap());
}
else
{
CElementBase::X(m_main.X()+XGap());
m_canvas.X(m_main.X()+m_canvas.XGap());
}
//--- Wenn die Bindung von unten erfolgtif(m_anchor_bottom_window_side)
{
CElementBase::Y(m_main.Y2()-YGap());
m_canvas.Y(m_main.Y2()-m_canvas.YGap());
}
else
{
CElementBase::Y(m_main.Y()+YGap());
m_canvas.Y(m_main.Y()+m_canvas.YGap());
}
Wenn es eine Bindung gibt, bewegt sich das Element zusammen mit dem Canvas. Also sollte theoretisch nichts kaputt gehen :)
Alles funktioniert. Nachdem ich in der gefüllten Combobox einen Wert ausgewählt habe - zum Beispiel den dritten Wert - und auf die Schaltfläche geklickt habe, kommt es zu einer Reihe von Aktionen, die zum Überlauf der Combobox führen. Und ich fülle sie wieder mit einem Wert auf (z. B. waren ursprünglich 20 Elemente darin, nach dem Klicken auf die Schaltfläche ist nur noch ein Element übrig!)
Und hier kommt ein interessanter Fehler - nachdem alles überschrieben ist (mit der obigen Funktion) - versuche ich, die Combobox zu öffnen, aber ich kann es nicht tun, weil der Fehler Array out of range! Der Fehler tritt in der Methode: void CListView::RedrawItemsByMode(const bool is_selected_item=false).
In Zeile 1364. Wie ich durch Nachforschen herausgefunden habe, tritt es auf, weil: 1) bei der Auswahl des dritten Elements der Liste (vor dem Drücken der Schaltfläche) - die Variable m_prev_item_index_focus mit einem Index gleich 3 gefüllt wird.
Dann wird dieser Index über die Variable prev_item_index an das Array indexes
in Zeile 1357 übergeben. Das Ergebnis davon - in Zeile 1364 - ist die Auswahl eines Wertes aus dem Array m_items
bei Index #2 (der dem letzten ausgewählten Element entspricht), während das Array (m_items) nur einen Wert bei Index #0 hat.
Ich suche nun schon den zweiten Tag und konnte immer noch nicht die Stelle finden, an der der Wert der Variablen m_prev_item_index_focus auf Null zurückgesetzt wird.
Logischerweise sollte er in der Clear-Methode der CListView-Klasse gelöscht werden, die ich verwendet habe, um alle Elemente dort zu löschen, aber leider konnte ich dort keine solche Methode finden....
Im Zusammenhang mit all den obigen Fragen: 1) Ist es ein Fehler in der Bibliothek, oder aktualisiere ich die Werte falsch? 2) Wie umgeht man dieses Problem am besten?
Das Minimum an reproduzierbarem Code für meine Frage:
//+------------------------------------------------------------------+//|TestCombobox.mq5 |//| Copyright 2018, MetaQuotes Software Corp. | |//| https://www.mql5.com |//+------------------------------------------------------------------+#include <EasyAndFastGUI\WndEvents.mqh>
#include <Arrays/ArrayString.mqh>
//+------------------------------------------------------------------+//||//+------------------------------------------------------------------+class CWindowManager : public CWndEvents
{
public:
void OnDeinitEvent(constint reason){CWndEvents::Destroy();};
//--- Graph-Ereignishandlervirtualvoid OnEvent(constint id,constlong &lparam,constdouble &dparam,conststring &sparam);////--- Erzeugt die grafische Oberfläche des Programmsbool CreateGUI(void);
private:
CComboBox m_cb;
CButton m_btn;
void Btn_Click(int id,long lparam);
bool CreateComboBox(conststring comboBox_name,
conststring &items_text[],
constint x_gap,
constint y_gap,
constint x_size,
constint y_size,
CComboBox &comboBox_link,
int x_ButtonSize=0);
bool CreateButton(conststring text,
constint x_gap,
constint y_gap,
constint x_size,
constint y_size,
CButton &btn_link);
bool CreateWindow(conststring text);
void setCombobox(CComboBox *cb_ptr,CArrayString &arr);
//--- Hauptfenster
CWindow m_window;
//--- ID und Nummer des Diagrammfensterslong m_chart_id;
int m_subwin;
};
CWindowManager _window;
//+------------------------------------------------------------------+//| Experteninitialisierungsfunktion|//+------------------------------------------------------------------+intOnInit()
{
//---if(!_window.CreateGUI())
{
Print(__FUNCTION__," > Fehler bei der Erstellung einer GUI!");
return(INIT_FAILED);
}
//---return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+//| Experten-Deinitialisierungsfunktion|//+------------------------------------------------------------------+voidOnDeinit(constint reason)
{
//---
_window.OnDeinitEvent(reason);
}
//+------------------------------------------------------------------+//| Experten-Tick-Funktion|//+------------------------------------------------------------------+voidOnTick()
{
//---
}
//+------------------------------------------------------------------+//||//+------------------------------------------------------------------+voidOnChartEvent(constint id,
constlong &lparam,
constdouble &dparam,
conststring &sparam)
{
_window.ChartEvent(id,lparam,dparam,sparam);
}
//+------------------------------------------------------------------+//||//+------------------------------------------------------------------+void CWindowManager::setCombobox(CComboBox *cb_ptr,CArrayString &arr)
{
CListView *lv_ptr=cb_ptr.GetListViewPointer();
lv_ptr.Clear(true);
cb_ptr.ItemsTotal(arr.Total());
for(int i=0;i<arr.Total();i++)
cb_ptr.SetValue(i,arr[i]);
lv_ptr.SelectItem(0,true);
cb_ptr.SelectItem(0);
cb_ptr.Update(true);
cb_ptr.GetButtonPointer().Update(true);
}
//+------------------------------------------------------------------+//||//+------------------------------------------------------------------+bool CWindowManager::CreateWindow(conststring text)
{
//--- Hinzufügen des Fensterzeigers zum Fenster-Array
CWndContainer::AddWindow(m_window);
//--- Koordinatenint x=(m_window.X()>0) ? m_window.X() : 1;
int y=(m_window.Y()>0) ? m_window.Y() : 1;
//--- Eigenschaften
m_window.XSize(300);
m_window.YSize(300);
m_window.Alpha(200);
m_window.IconXGap(3);
m_window.IconYGap(2);
m_window.IsMovable(true);
m_window.ResizeMode(false);
m_window.CloseButtonIsUsed(true);
m_window.FullscreenButtonIsUsed(false);
m_window.CollapseButtonIsUsed(true);
m_window.TooltipsButtonIsUsed(false);
m_window.RollUpSubwindowMode(true,true);
m_window.TransparentOnlyCaption(true);
//--- Tooltips einstellen
m_window.GetCloseButtonPointer().Tooltip("Close");
m_window.GetCollapseButtonPointer().Tooltip("Collapse/Expand");
//--- Formularerstellungif(!m_window.CreateWindow(m_chart_id,m_subwin,text,x,y))
return(false);
//---return(true);
}
//+------------------------------------------------------------------+//||//+------------------------------------------------------------------+bool CWindowManager::CreateButton(conststring text,
constint x_gap,
constint y_gap,
constint x_size,
constint y_size,
CButton &btn_link)
{
//--- Speichern des Zeigers auf das Hauptelement
btn_link.MainPointer(m_window);
//--- Eigenschaften
btn_link.XSize(x_size);
btn_link.YSize(y_size);
btn_link.IconXGap(3);
btn_link.IconYGap(3);
btn_link.IsCenterText(true);
//--- Ein Steuerelement erstellenif(!btn_link.CreateButton(text,x_gap,y_gap))
return(false);
//--- Hinzufügen eines Zeigers auf das Element in der Basis
CWndContainer::AddToElementsArray(0,btn_link);
return(true);
}
//+------------------------------------------------------------------+//||//+------------------------------------------------------------------+bool CWindowManager::CreateComboBox(conststring comboBox_name,
conststring &items_text[],
constint x_gap,
constint y_gap,
constint x_size,
constint y_size,
CComboBox &comboBox_link,
int x_lableXSize)
{
//--- Speichern des Zeigers auf das Hauptelement
comboBox_link.MainPointer(m_window);
if(x_lableXSize==0)
x_lableXSize=x_size;
int items_total=ArraySize(items_text);
//--- Eigenschaften vor der Erstellung festlegen
comboBox_link.XSize(x_size);
comboBox_link.YSize(y_size);
comboBox_link.ItemsTotal(items_total);
comboBox_link.AnchorRightWindowSide(false);
comboBox_link.GetButtonPointer().YSize(y_size);
if(StringCompare(comboBox_name,"")==0)
{
comboBox_link.GetButtonPointer().XSize(x_size);
comboBox_link.GetButtonPointer().AnchorRightWindowSide(true);
}
else
{
comboBox_link.GetButtonPointer().XSize(x_lableXSize);
comboBox_link.GetButtonPointer().AnchorRightWindowSide(false);
}
//--- Speichern der Elementwerte in der Liste des Kombinationsfeldesfor(int i=0;i<items_total;i++)
comboBox_link.SetValue(i,items_text[i]);
//--- Abrufen des Listenzeigers
CListView *lv=comboBox_link.GetListViewPointer();
//--- Listeneigenschaften festlegen
lv.YSize((int)MathMin(items_total*y_size,150));
lv.LightsHover(true);
lv.SelectItem(lv.SelectedItemIndex()==WRONG_VALUE ? 0 : lv.SelectedItemIndex());
//--- Ein Steuerelement erstellenif(!comboBox_link.CreateComboBox(comboBox_name,x_gap,y_gap))
returnfalse;
CWndContainer::AddToElementsArray(0,comboBox_link);
returntrue;
}
//+------------------------------------------------------------------+//||//+------------------------------------------------------------------+bool CWindowManager::CreateGUI(void)
{
if(!CreateWindow("Combobox Bug ???? "))
return(false);
string cb_arr[20];
for(int i=0;i<20;i++)
cb_arr[i]=IntegerToString(i+1);
if(!CreateComboBox("",cb_arr,100,100,100,20,m_cb))
returnfalse;
if(!CreateButton("Action",100,130,50,20,m_btn))
returnfalse;
// Fenster anzeigen
CWndEvents::CompletedGUI();
returntrue;
}
//+------------------------------------------------------------------+//||//+------------------------------------------------------------------+void CWindowManager::Btn_Click(int id,long lparam)
{
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_btn.Id())
{
CArrayString s;
s.Add("new value");
setCombobox(&m_cb,s);
}
}
//+------------------------------------------------------------------+//||//+------------------------------------------------------------------+void CWindowManager::OnEvent(constint id,constlong &lparam,constdouble &dparam,conststring &sparam)
{
Btn_Click(id,lparam);
}
//+------------------------------------------------------------------+
Bis jetzt laufen alle Lösungen, die ich gefunden habe, darauf hinaus, den Bibliothekscode zu bearbeiten (3 neue Codezeilen hinzuzufügen) - aber ich mag die Idee nicht, den Code von jemand anderem zu verändern...
Andrey Azatskiy: Minimaler reproduzierbarer Code für meine Frage:
...
Bisher laufen alle Lösungen, die ich gefunden habe, darauf hinaus, den Bibliothekscode zu bearbeiten (3 neue Codezeilen hinzuzufügen) - aber ich mag die Idee nicht, den Code von jemand anderem zu verändern...
Danke für die Nachricht.
Versuchen Sie, eine kleine Ergänzung zur Methode der KlasseCListView vorzunehmen. Sie müssen die Hilfsfelder wie unten angegeben löschen:
//+------------------------------------------------------------------+//| Löscht die Liste (löscht alle Einträge).//+------------------------------------------------------------------+void CListView::Clear(constbool redraw=false)
{
//--- Hilfsfelder auf Null zurücksetzen m_item_index_focus =WRONG_VALUE;
m_prev_selected_item =WRONG_VALUE;
m_prev_item_index_focus =WRONG_VALUE;//--- Die Größe auf Null setzen
ListSize(0);
//--- Berechnen und Festlegen neuer Listengrößen
RecalculateAndResizeList(redraw);
}
Können Sie mir sagen, wie ich die Schaltfläche zum Schließen des Fensters richtig handhaben kann?
Das Problem ist folgendes: Ich platziere einen Expert Advisor (z.B. ExampleEAF.ex5) und meinen Indikator in einem separaten Fenster unter dem Chart (der Minimalcode zeigt nur ein leeres Fenster an). Wenn ich dann in einer dieser Anwendungen auf die Schaltfläche "Fenster schließen" klicke, werden beide geschlossen (aus dem Chart entfernt).
Dieses Verhalten ist nicht ganz korrekt. Gibt es eine Möglichkeit, Ereignisse für verschiedene Anwendungen, die gleichzeitig auf demselben Diagramm arbeiten, zu unterscheiden? Es besteht der Verdacht, dass sich auch andere Ereignisse überschneiden könnten.
Können Sie mir sagen, wie ich die Schaltfläche "Fenster schließen" richtig handhaben kann?
Das Problem ist folgendes: Ich platziere einen Expert Advisor (z.B. ExampleEAF.ex5) und meinen Indikator in einem separaten Fenster unter dem Chart (der Minimalcode zeigt nur ein leeres Fenster an). Wenn ich dann auf die Schaltfläche "Fenster schließen" in einer dieser Anwendungen klicke, werden beide geschlossen (aus dem Chart entfernt).
Dieses Verhalten ist nicht ganz korrekt. Gibt es eine Möglichkeit, Ereignisse für verschiedene Anwendungen, die gleichzeitig auf demselben Diagramm arbeiten, zu unterscheiden? Ich vermute, dass sich auch andere Ereignisse überschneiden können.
Ich werde es testen, wenn ich Zeit habe, und das Ergebnis hier mitteilen.
Как на счет репозитория на битбакете и принятия коммитов от активных пользователей библиотеки?
Вместе быстрее допилим ;)
Anatoli Kazharski:
...
Wenn Änderungen vorgenommen werden, ist es notwendig, Beispiele und Testergebnisse mit einer Erklärung, warum es besser wäre, zu geben.
Zumindest kurz. Zum Beispiel:
Korrekturen in der CListView-Klasse. In der Clear()-Methode müssen wir einige Hilfsfelder auf Null setzen, um zu verhindern, dass andere Methoden der Klasse außerhalb des Arrays gehen.
Ursprünglich gab es einfach keine solche Aufgabe, dass es notwendig war, Elemente zu verschieben, nachdem die GUI erstellt war. Alles basierte auf der Idee, dass jedes Element bereits das notwendige Verhalten implementiert hatte.
Gegenfragen: Warum müssen Sie Elemente verschieben? Was wollen Sie tun? Welches Verhalten bei der Interaktion mit der grafischen Benutzeroberfläche möchten Sie erreichen?
Um zu verstehen, ob etwas kaputt gehen wird, müssen Sie alle Elemente nach jeder Änderung der Basisklassen testen. Es ist schon schwer, das auf Anhieb zu sagen. Es ist schon eine Weile her, dass ich mich damit beschäftigt habe.
Erstellen Sie eine Test-GUI mit allen Elementen der Bibliothek und testen Sie diese nach Änderungen.
Zum Beispiel aufklappbare Listen. Wenn man klickt, werden einige der Elemente ausgeblendet, alles darunter wird nach oben gezogen. Und andersherum.
Test GUI ist eine gute Idee, ich werde versuchen, es zu machen :)
Übrigens, in der gleichen CElement::Moving.
Wenn es eine Bindung gibt, bewegt sich das Element zusammen mit dem Canvas. Also sollte theoretisch nichts kaputt gehen :)
Hat jemand versucht, eine Combobox mit dieser Bibliothek zu erstellen - um Elemente darin zu ändern ????? Share Wie macht man das?
Ich erstelle eine Combobox, alles funktioniert. Dann fülle ich sie mit Elementen, indem ich die folgende Funktion verwende:
Alles funktioniert. Nachdem ich in der gefüllten Combobox einen Wert ausgewählt habe - zum Beispiel den dritten Wert - und auf die Schaltfläche geklickt habe, kommt es zu einer Reihe von Aktionen, die zum Überlauf der Combobox führen. Und ich fülle sie wieder mit einem Wert auf (z. B. waren ursprünglich 20 Elemente darin, nach dem Klicken auf die Schaltfläche ist nur noch ein Element übrig!)
Und hier kommt ein interessanter Fehler - nachdem alles überschrieben ist (mit der obigen Funktion) - versuche ich, die Combobox zu öffnen, aber ich kann es nicht tun, weil der Fehler Array out of range!
Der Fehler tritt in der Methode:
void CListView::RedrawItemsByMode(const bool is_selected_item=false).
In Zeile 1364. Wie ich durch Nachforschen herausgefunden habe, tritt es auf, weil:
1) bei der Auswahl des dritten Elements der Liste (vor dem Drücken der Schaltfläche) - die Variable
m_prev_item_index_focus mit einem Index gleich 3 gefüllt wird.
Dann wird dieser Index über die Variable prev_item_index an das Array
indexes
in Zeile 1357 übergeben. Das Ergebnis davon - in Zeile 1364 - ist die Auswahl eines Wertes aus dem Array
m_items
bei Index #2 (der dem letzten ausgewählten Element entspricht), während das Array (m_items) nur einen Wert bei Index #0 hat.
Ich suche nun schon den zweiten Tag und konnte immer noch nicht die Stelle finden, an der der Wert der Variablen
m_prev_item_index_focus auf Null zurückgesetzt wird.
Logischerweise sollte er in der Clear-Methode der CListView-Klasse gelöscht werden, die ich verwendet habe, um alle Elemente dort zu löschen, aber leider konnte ich dort keine solche Methode finden....
Im Zusammenhang mit all den obigen Fragen:
1) Ist es ein Fehler in der Bibliothek, oder aktualisiere ich die Werte falsch?
2) Wie umgeht man dieses Problem am besten?
Bis jetzt laufen alle Lösungen, die ich gefunden habe, darauf hinaus, den Bibliothekscode zu bearbeiten (3 neue Codezeilen hinzuzufügen) - aber ich mag die Idee nicht, den Code von jemand anderem zu verändern...
Minimaler reproduzierbarer Code für meine Frage:
...
Bisher laufen alle Lösungen, die ich gefunden habe, darauf hinaus, den Bibliothekscode zu bearbeiten (3 neue Codezeilen hinzuzufügen) - aber ich mag die Idee nicht, den Code von jemand anderem zu verändern...
Danke für die Nachricht.
Versuchen Sie, eine kleine Ergänzung zur Methode der Klasse CListView vorzunehmen. Sie müssen die Hilfsfelder wie unten angegeben löschen:
Vielen Dank für diese Nachricht.
Versuchen Sie, eine kleine Ergänzung zur Methode der Klasse CListView vorzunehmen. Sie müssen die Hilfsfelder wie unten beschrieben löschen:
Vielen Dank für Ihre Antwort.
Wie wäre es mit einem Repository auf Bitbucket, das Commits von aktiven Bibliotheksbenutzern annimmt?
Wir werden es gemeinsam schneller fertigstellen ;)
Können Sie mir sagen, wie ich die Schaltfläche zum Schließen des Fensters richtig handhaben kann?
Das Problem ist folgendes: Ich platziere einen Expert Advisor (z.B. ExampleEAF.ex5) und meinen Indikator in einem separaten Fenster unter dem Chart (der Minimalcode zeigt nur ein leeres Fenster an). Wenn ich dann in einer dieser Anwendungen auf die Schaltfläche "Fenster schließen" klicke, werden beide geschlossen (aus dem Chart entfernt).
Dieses Verhalten ist nicht ganz korrekt. Gibt es eine Möglichkeit, Ereignisse für verschiedene Anwendungen, die gleichzeitig auf demselben Diagramm arbeiten, zu unterscheiden? Es besteht der Verdacht, dass sich auch andere Ereignisse überschneiden könnten.
Wie wäre es mit einem Repository auf Bitbucket, das Commits von aktiven Bibliotheksbenutzern annimmt?
Wir werden es gemeinsam schneller fertigstellen ;)
Ich habe bereits Zugang erhalten. Viele der Bearbeitungen sind für mich fragwürdig.
Es gibt keine Rechtfertigung für diese oder jene Änderungen. Es ist einfacher, sie hier im Forum zu diskutieren.
Wenn irgendwelche Änderungen vorgenommen werden, ist es notwendig, Beispiele und Testergebnisse zu nennen und zu erklären, warum es besser ist.
Können Sie mir sagen, wie ich die Schaltfläche "Fenster schließen" richtig handhaben kann?
Das Problem ist folgendes: Ich platziere einen Expert Advisor (z.B. ExampleEAF.ex5) und meinen Indikator in einem separaten Fenster unter dem Chart (der Minimalcode zeigt nur ein leeres Fenster an). Wenn ich dann auf die Schaltfläche "Fenster schließen" in einer dieser Anwendungen klicke, werden beide geschlossen (aus dem Chart entfernt).
Dieses Verhalten ist nicht ganz korrekt. Gibt es eine Möglichkeit, Ereignisse für verschiedene Anwendungen, die gleichzeitig auf demselben Diagramm arbeiten, zu unterscheiden? Ich vermute, dass sich auch andere Ereignisse überschneiden können.
Ich werde es testen, wenn ich Zeit habe, und das Ergebnis hier mitteilen.
Andrey Khatimlianskii:
Как на счет репозитория на битбакете и принятия коммитов от активных пользователей библиотеки?
Вместе быстрее допилим ;)
Anatoli Kazharski:
...
Wenn Änderungen vorgenommen werden, ist es notwendig, Beispiele und Testergebnisse mit einer Erklärung, warum es besser wäre, zu geben.
Zumindest kurz. Zum Beispiel:
Korrekturen in der CListView-Klasse. In der Clear()-Methode müssen wir einige Hilfsfelder auf Null setzen, um zu verhindern, dass andere Methoden der Klasse außerhalb des Arrays gehen.