
Graphische Interfaces III: Gruppen von einfachen und multifunktionalen Buttons (Kapitel 2)
Inhalt
- Einleitung
- Entwicklung einer Klasse für die Erzeugung von Gruppen von einfachen Buttons
- Entwicklung einer Klasse für die Erzeugung einer Gruppe von Radiobuttons
- Erzeugen einer Klasse für die Erzeugung einer Gruppe von Icon-Buttons
- Schlussfolgerung
Einleitung
Der erste ArtikelGrafische Interfaces I: Vorbereitung der Bibliotheksstruktur(Kapitel 1) betrachtet im Detail den Sinn und Zweck der Bibliothek. Eine vollständige Liste der Links zu den Artikeln finden Sie am Ende von jedem Kapitel. Zudem finden Sie dort eine Möglichkeit das Projekt, entsprechend dem aktuellen Entwicklungszustand, herunterzuladen. Die Dateien müssen in den gleichen Verzeichnissen untergebracht werden, so, wie Sie auch in dem Archiv abgelegt sind.
In dem ersten Kapitel dieser Serie ging es um einfache und multifunktionelle Buttons. Der zweite Artikel handelt über Gruppen von interagierenden Buttons, mit denen der Programmierer Elemente erzeugen kann, bei der der Anwender ein Element aus der Gruppe auswählen kann.
Entwicklung einer Klasse für die Erzeugung von Gruppen von einfachen Buttons
Eine Gruppe von einfachen Buttons ist im Wesentlichen ein Array von grafischen Objekten des Typs OBJ_BUTTON. Die unterschiedliche Verhaltensweise solcher Controls besteht darin, dass immer nur ein Button dieser Gruppe gleichzeitig ausgewählt werden kann. In dem augenblicklichen Stadium, kann eine Klasse dieser Controls auf zwei Wege erzeugt werden:
- Durch das Erzeugen einer Gruppe von schon bereits implementierten Controls des Typs CSimpleButton;
- Durch das Erzeugen einer Gruppe von einfachen Objekten des Typs CButton.
Die zweite Option ist einfacher, da sie keine weitere Methode für die jedes Control des TypsCSimpleButton benötigt, um an die Basis der Pointer zu gelangen. Wie werden diese Option verwenden.
Erzeugen Sie die ButtonsGroup.mqh Datei mit der CButtonsGroup Klasse in dem Controls Verzeichnis, welches alle anderen Controls beinhaltet und beziehen Sie sie in derWndContainer.mqh Datei mit ein. Diese Klasse muss virtuelle Methoden besitzen und den Pointer der Form, so wie es auch schon in allen anderen zuvor entwickelten Controls der Fall war. Diese werden wir hier nicht weiter besprechen und gehen direkt zu der Beschreibung der Eigenschaften und Methoden für die Konstruktion der neuen Klasse über.
Es wird einige gemeinsame Eigenschaften für jeden Button innerhalb einer Gruppe geben, aber es wird auch ein paar spezielle Eigenschaften geben. Im Folgenden sehen Sie zwei Gruppen von Eigenschaften, bezogen auf ihr Erscheinungsbild / Funktion:
Gemeinsame Eigenschaften der Buttons:
- Höhe:
- Farbe der gesperrten Buttons;
- Rahmenfarbe der verfügbaren und gesperrten Modi;
- Die Textfarbe in den unterschiedlichen Zuständen;
- Priorität der linken Maustaste.
Gemeinsame Eigenschaften der Buttons:
- Status des Buttons (gedrückt/nicht gedrückt);
- Abstände vom Rand des Formulars;
- Text;
- Breite;
- Die Farbe der Buttons in den unterschiedlichen Zuständen;
- Die Gradienten für die Buttons.
Die Ränder der Buttons erlauben es, die Buttons in jeder gewünschten Art anzuordnen.
Abbildung 1. Ein Beispiel für die Anordnung von Buttons in einer Gruppe.
Deklarieren Sie dynamische Arrays für die Objekte des Typs CButton und ihre eindeutigen Eigenschaften, so wie es in dem nachfolgenden Programmcode gezeigt ist.
//+---------------------------------------------------------------- //| Klasse für die Erzeugung einer Gruppe von einfachen Buttons | //+---------------------------------------------------------------- class CButtonsGroup : public CElement { private: //--- Objekte für die Erzeugung eines Buttons CButton m_buttons[]; //--- Button Gradienten struct ButtonsGradients { color m_buttons_color_array[]; }; ButtonsGradients m_buttons_total[]; //--- Die Eigenschaften des Buttons: // Arrays Für spezielle Eigenschaften von Buttons bool m_buttons_state[]; int m_buttons_x_gap[]; int m_buttons_y_gap[]; string m_buttons_text[]; int m_buttons_width[]; color m_buttons_color[]; color m_buttons_color_hover[]; color m_buttons_color_pressed[]; //--- Höhe der Buttons int m_button_y_size; //--- Farbe der gesperrten Buttons color m_back_color_off; //--- Rahmenfarbe in dem aktiven und gesperrten Modus color m_border_color; color m_border_color_off; //--- Die Textfarbe color m_text_color; color m_text_color_off; color m_text_color_pressed; //--- Die Priorität der linken Maustaste int m_buttons_zorder; //--- public: //--- Anzahl der Buttons int ButtonsTotal(void) const { return(::ArraySize(m_buttons)); } //--- (1) Höhe der Buttons void ButtonYSize(const int y_size) { m_button_y_size=y_size; } //--- (1) Hintergrundfarben eines blockierten Buttons und Rahmens ((2) verfügbar/(3) gesperrt) void BackColorOff(const color clr) { m_back_color_off=clr; } void BorderColor(const color clr) { m_border_color=clr; } void BorderColorOff(const color clr) { m_border_color_off=clr; } //--- Die Textfarbe void TextColor(const color clr) { m_text_color=clr; } void TextColorOff(const color clr) { m_text_color_off=clr; } void TextColorPressed(const color clr) { m_text_color_pressed=clr; } };
Die Größe des dynamischen Arrays wird definiert, wenn die Gruppe von Buttons gebildet wird und bevor sie erzeugt werden (Hinzufügen zu dem Chart). Jedesmal, wenn die CButtonsGroup::AddButton() Methode aufgerufen wird, wird das Array vergrößert und mit den Elementen aufgefüllt, die mit der Methode übergeben wurden.
class CButtonsGroup : public CElement { public: //--- Fügt vor der Erzeugung einen Button mit den angegebenen Eigenschaften hinzu void AddButton(const int x_gap,const int y_gap,const string text,const int width, const color button_color,const color button_color_hover,const color button_color_pressed); }; //+---------------------------------------------------------------- //| Hinzufügen eines Buttons | //+---------------------------------------------------------------- void CButtonsGroup::AddButton(const int x_gap,const int y_gap,const string text,const int width, const color button_color,const color button_color_hover,const color pressed_button_color) { //--- Vergrößern des Arrays um ein Element int array_size=::ArraySize(m_buttons); ::ArrayResize(m_buttons,array_size+1); ::ArrayResize(m_buttons_total,array_size+1); ::ArrayResize(m_buttons_state,array_size+1); ::ArrayResize(m_buttons_x_gap,array_size+1); ::ArrayResize(m_buttons_y_gap,array_size+1); ::ArrayResize(m_buttons_text,array_size+1); ::ArrayResize(m_buttons_width,array_size+1); ::ArrayResize(m_buttons_color,array_size+1); ::ArrayResize(m_buttons_color_hover,array_size+1); ::ArrayResize(m_buttons_color_pressed,array_size+1); //--- Abspeichern der übergebenen Werte m_buttons_x_gap[array_size] =x_gap; m_buttons_y_gap[array_size] =y_gap; m_buttons_text[array_size] =text; m_buttons_width[array_size] =width; m_buttons_color[array_size] =button_color; m_buttons_color_hover[array_size] =button_color_hover; m_buttons_color_pressed[array_size] =pressed_button_color; m_buttons_state[array_size] =false; }
Wenn kein Button mit der CButtonsGroup::AddButton() Methode erzeugt worden ist, wird der Prozess für das Erzeugen eines grafischen Interfaces angehalten und eine entsprechende Nachricht wird in dem Journal angezeigt.. Die Buttons werden in einer Schleife, wie es in der hier verkürzten Methode CButtonsGroup::CreateButtons() dargestellt ist.
class CButtonsGroup : public CElement { public: //--- Methoden für die Erzeugung eines Buttons bool CreateButtonsGroup(const long chart_id,const int subwin,const int x,const int y); //--- private: bool CreateButtons(void); }; //+---------------------------------------------------------------- //| Erzeugte Buttons | //+---------------------------------------------------------------- bool CButtonsGroup::CreateButtons(void) { //--- Koordinaten int l_x =m_x; int l_y =m_y; //--- Anzahl der Buttons abfragen int buttons_total=ButtonsTotal(); //--- Falls es keinen Button in dieser Gruppe gibt, dann benachrichtigen if(buttons_total<1) { ::Print(__FUNCTION__," > This method is to be called " "if a group contains at least one button! Use the CButtonsGroup::AddButton() method"); return(false); } //--- Erzeugen der angegebenen Anzahl von Buttons for(int i=0; i<buttons_total; i++) { //--- Den Objektnamen bilden //--- Die Koordinaten berechnen //--- Einen Button einrichten //--- Festlegen seiner Eigenschaften //--- Abspeichern der Abstände, die Koordinaten und seine Größe //--- Initialisierung des Gradienten-Arrays //--- Abspeichern des Objekt-Pointers } //--- return(true); }
Lassen Sie uns für diesen Typ von Gruppen-Buttons zwei Modi erzeugen. Um dieses einzurichten, fügen wir in der Klasse einen Bereich ein, wie es in dem folgenden Code dargestellt ist: Der Standardwert ist false, was bedeutet, dass es erlaubt ist, dass alle Buttons in der Gruppe nicht gedrückt sind. Der Standardwert true bedeutet, dass immer ein Button gedrückt sein muss.
class CButtonsGroup : public CElement { public: //--- Der Radio-Button Modus bool m_radio_buttons_mode; //--- public: //--- Installieren des Radio-Button Modus void RadioButtonsMode(const bool flag) { m_radio_buttons_mode=flag; } };
Wie bei jedem anderen Control auch, muss diese Klasse ebenfalls eine Methode für das Blockieren des Controls enthalten. Für diesen Typ von Gruppen-Buttons, ist es wichtig sicherzustellen, dass wenn ein vorheriger gedrückter Button wieder entsperrt wird, er sein Erscheinungsbild auch wieder aktualisiert.
class CButtonsGroup : public CElement { private: //--- Verfügbar oder blockiert bool m_buttons_group_state; //--- public: //--- Genereller Status der Button-Gruppe (available/blocked) bool ButtonsGroupState(void) const { return(m_buttons_group_state); } void ButtonsGroupState(const bool state); }; //+---------------------------------------------------------------- //| Ändern des Status des Buttons | //+---------------------------------------------------------------- void CButtonsGroup::ButtonsGroupState(const bool state) { m_buttons_group_state=state; //--- int buttons_total=ButtonsTotal(); for(int i=0; i<buttons_total; i++) { m_buttons[i].State(false); m_buttons[i].Color((state)? m_text_color : m_text_color_off); m_buttons[i].BackColor((state)? m_buttons_color[i]: m_back_color_off); m_buttons[i].BorderColor((state)? m_border_color : m_border_color_off); } //--- Den Button drücken falls er vor dem Blockieren gedrückt war if(m_buttons_group_state) { if(m_selected_button_index!=WRONG_VALUE) { m_buttons_state[m_selected_button_index]=true; m_buttons[m_selected_button_index].Color(m_text_color_pressed); m_buttons[m_selected_button_index].BackColor(m_buttons_color_pressed[m_selected_button_index]); } } }
Wir brauchen eine Methode um den Status des Buttonshin und her zu schalten, wenn er gedrückt wird.. Wir benötigen zudem Felder und Methoden für das Abspeichern und Abfragen des Textes und des Indexes des hervorgehobenen Buttons..
Am Anfang der Methode, die für das hin- und herschalten des Status des Buttons zuständig ist, ist eine Überprüfung der Anzahl der Buttons innerhalb einer Gruppe. Wenn sich herausstellt, dass es keine Buttons gibt, dann wird eine entsprechende Nachricht herausgegeben. Das Programm wird die Methode aber nicht verlassen. Das Programm wird fortführen und an einem bestimmten Punkt eine Fehlermeldung über das Überschreiten der Größe des m_buttons_state[] Arrays melden. Das bedeutet, dass ein Entwickler eine Applikation mindestens einen Button zu der Gruppe hinzufügen muss, damit ein solcher Fehler nicht auftritt. Nach der Überprüfung, wenn es mindestens einen Button gibt, wird das Programm den mitgegebenen Index anpassen, falls die Größe des Arrays überschritten wird. Anschließend wird der Status des Buttons, der dem angegebenen Index entspricht, geändert. Anschließend bekommen in einer Schleife alle anderen Buttons den Zustand "nicht gedrückt"(Die entsprechende Farbe wird gesetzt) unter Berücksichtigung des Gruppenmodus. Mit anderen Worten, falls der Radio-Button Modus aktiv ist und es mindestens einen gedrückten Button geben muss, dann wird während der Iteration eine Überprüfung der Übereinstimmung des aktuellen Indexes mit dem übergebenen Index durchgeführt. Wenn der Modus, dass alle Buttons nicht gedrückt sein können aktiviert ist, dann wird zusätzlich zu der Überprüfung des Index auch noch der aktuelle Status des Buttons überprüft. Wenn die Bedingung erfüllt ist, dann wird das Flag für den gedrückten Button gesetzt, unabhängig von dem aktuellen Modus. Am Ende der Methode, in der Klasse wo der Text und der Index des hervorgehobenen Buttons gespeichert wird, werden die Felder mit den entsprechenden Werten unter Berücksichtigung des Flags gefüllt. Wenn es keinen gedrückten Button gibt, werden leere Werte gesetzt("" und WRONG_VALUE).
class CButtonsGroup : public CElement { private: //--- (1) Text und (2) Index des hervorgehobenen Buttons string m_selected_button_text; int m_selected_button_index; //--- public: //--- Gibt (1) den Text und (2) den Index des hervorgehobenen Buttons zurück string SelectedButtonText(void) const { return(m_selected_button_text); } int SelectedButtonIndex(void) const { return(m_selected_button_index); } //--- Wechselt den Status des Buttons mit dem angegebenen Index void SelectionButton(const int index); }; //+---------------------------------------------------------------- //| Wechselt den Status des Buttons mit dem angegebenen Index | //+---------------------------------------------------------------- void CButtonsGroup::SelectionButton(const int index) { //--- Für die Überprüfung ob ein Button innerhalb einer Gruppe gedrückt ist bool check_pressed_button=false; //--- Anzahl der Buttons abfragen int buttons_total=ButtonsTotal(); //--- Falls es keinen Button in dieser Gruppe gibt, dann benachrichtigen if(buttons_total<1) { ::Print(__FUNCTION__," > This method is to be called " "if a group contains at least one button! Use the CButtonsGroup::AddButton() method"); } //--- Anpassen des Indexwertes, falls die Größe des Arrays überschritten wird int correct_index=(index>=buttons_total)? buttons_total-1 : (index<0)? 0 : index; //--- Wechseln des Status aller entgegengesetzten Buttons m_buttons_state[correct_index]=(m_buttons_state[correct_index])? false : true; //--- Iteration über eine Gruppe von Buttons for(int i=0; i<buttons_total; i++) { //--- Wird ein relevanter check in Abhängigkeit des Modus durchgeführt bool condition=(m_radio_buttons_mode)? (i==correct_index) : (i==correct_index && m_buttons_state[i]); //--- Falls die Bedingungen zutreffen, bekommt der Button den gedrückten Status if(condition) { if(m_radio_buttons_mode) m_buttons_state[i]=true; //--- Es gibt einen gedrückten Button check_pressed_button=true; //--- Festlegen der Farbe m_buttons[i].Color(m_text_color_pressed); m_buttons[i].BackColor(m_buttons_color_pressed[i]); CElement::InitColorArray(m_buttons_color_pressed[i],m_buttons_color_pressed[i],m_buttons_total[i].m_buttons_color_array); } //--- Falls die Bedingungen nicht zutreffen, wird der Button in den nicht gedrückten Zustand versetzt else { //--- Setzen des deaktivierte Status und der Farbe m_buttons_state[i]=false; m_buttons[i].Color(m_text_color); m_buttons[i].BackColor(m_buttons_color[i]); CElement::InitColorArray(m_buttons_color[i],m_buttons_color_hover[i],m_buttons_total[i].m_buttons_color_array); } //--- Zurücksetzen des normalen Status des Buttons m_buttons[i].State(false); } //--- Wenn es einen gedrückten Button gibt, abspeichern des Textes und des Indexes m_selected_button_text =(check_pressed_button) ? m_buttons[correct_index].Description() : ""; m_selected_button_index =(check_pressed_button) ? correct_index : WRONG_VALUE; }
Um einen Klick auf einen gut wachsen behandeln zu können, erzeugen wir die CButtonsGroup::OnClickButton() Methode. Entsprechend zu einigen anderen gleichartigen Methoden, die Wir vorher schon besprochen haben, werden die folgenden Überprüfungen durchgeführt:
- Überprüfung des Namens;
- Der Identifizierer, bzw. Bezeichner. Um den Bezeichner von den Objektnamen zu extrahieren, verwenden wir die CButtonsGroup::IdFromObjectName() Methode. Der Code dieser Methode ist ähnlich wie in schon vorherigen besprochenen gleichartigen Methoden aus anderen Klassen. Wir werden diesen hier daher nicht weiter besprechen;
- Für den aktuellen Status(verfügbar/gesperrt).
Wenn alle Überprüfungen erfolgreich abgeschlossen worden sind und das Programm die Methode nicht verlassen hat, wird der Wechsel von den Zuständen der Buttons durch dieCButtonsGroup::SelectionButton() Methode ausgeführt. Am Ende dieser Methode, wird über die Events eine Nachricht mit den Daten über den gedrückten Button versendet. Diese Nachricht kann in dem Eventhandler der benutzerdefinierten Klasse empfangen werden.
class CButtonsGroup : public CElement { private: //--- Verarbeiten eines Klicks auf einen Button bool OnClickButton(const string clicked_object); //--- Den Bezeichner aus dem Namen des Buttons entnehmen int IdFromObjectName(const string object_name); }; //+---------------------------------------------------------------- //| Chart Eventhandler | //+---------------------------------------------------------------- void CButtonsGroup::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Verarbeiten eines Klicks mit der linken Maustaste auf ein Objekt if(id==CHARTEVENT_OBJECT_CLICK) { if(OnClickButton(sparam)) return; } } //+---------------------------------------------------------------- //| Drücken eines Buttons innerhalb einer Gruppe | //+---------------------------------------------------------------- bool CButtonsGroup::OnClickButton(const string pressed_object) { //--- Abbrechen, falls der Klick nicht auf diesem Menüpunkt stattgefunden hat if(::StringFind(pressed_object,CElement::ProgramName()+"_buttons_",0)<0) return(false); //--- Den Bezeichner aus dem Objektnamen entnehmen int id=IdFromObjectName(pressed_object); //--- Abbrechen, falls der Bezeichner nicht passt if(id!=CElement::Id()) return(false); //--- Für die Überprüfung des Index int check_index=WRONG_VALUE; //--- Überprüfen ob der Klick auf einen der Buttons dieser Gruppe ausgeführt wurde int buttons_total=ButtonsTotal(); //--- Abbrechen wenn die Buttons gesperrt sind if(!m_buttons_group_state) { for(int i=0; i<buttons_total; i++) m_buttons[i].State(false); //--- return(false); } //--- Falls ein Krieg stattgefunden hat, Abspeichern des Index for(int i=0; i<buttons_total; i++) { if(m_buttons[i].Name()==pressed_object) { check_index=i; break; } } //--- Abbrechen, falls kein Button dieser Gruppe gedrückt wurde if(check_index==WRONG_VALUE) return(false); //--- Wechsel des Status des Buttons SelectionButton(check_index); //--- Eine Nachricht darüber senden ::EventChartCustom(m_chart_id,ON_CLICK_BUTTON,CElement::Id(),m_selected_button_index,m_selected_button_text); return(true); }
Jetzt richten wir noch die Reaktion der Gruppe bei einer Bewegung des Mauszeigers über die Buttons hinweg ein, sowie den Klick mit der linken Maustaste. Dafür schreiben wir die CButtonsGroup::CheckPressedOverButton() Methode, welche in dem Eventhandler während der Verarbeitung des CHARTEVENT_MOUSE_MOVE Events aufgerufen wird. Bevor die Methode aufgerufen wird, werden folgende Überprüfungen vorgenommen: (1) ob das Konto sichtbar ist, (2) ob es verfügbar ist, (3) ob die Form verfügbar ist und(4) ob die linke Maustaste gedrückt worden ist.
class CButtonsGroup : public CElement { private: //--- Überprüfen, ob die linke Maustaste über den Group Buttons gedrückt wurde void CheckPressedOverButton(void); }; //+---------------------------------------------------------------- //| Chart Eventhandler | //+---------------------------------------------------------------- void CButtonsGroup::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Verarbeiten der Events über die Bewegung des Mauszeigers if(id==CHARTEVENT_MOUSE_MOVE) { //--- Abbrechen, falls das Control versteckt ist if(!CElement::IsVisible()) return; //--- Abbrechen wenn die Buttons gesperrt sind if(!m_buttons_group_state) return; //--- Den Fokus definieren int x=(int)lparam; int y=(int)dparam; int buttons_total=ButtonsTotal(); for(int i=0; i<buttons_total; i++) { m_buttons[i].MouseFocus(x>m_buttons[i].X() && x<m_buttons[i].X2() && y>m_buttons[i].Y() && y<m_buttons[i].Y2()); } //--- Abbrechen, falls die Forum blockiert ist if(m_wnd.IsLocked()) return; //--- Abbrechen, falls die Maustaste nicht gedrückt ist if(sparam!="1") return; //--- Überprüfen, ob die linke Maustaste über den Group Buttons gedrückt wurde CheckPressedOverButton(); return; } } //+---------------------------------------------------------------- //| Überprüfung der gedrückten linken Maustaste über den Group Buttons| //+---------------------------------------------------------------- void CButtonsGroup::CheckPressedOverButton(void) { int buttons_total=ButtonsTotal(); //--- Die Farbe, entsprechend dem Ort wo die linke Maustaste gedrückt wurde, setzen for(int i=0; i<buttons_total; i++) { //--- Wenn es einen Fokus gibt dann die Farbe des gedrückten Buttons if(m_buttons[i].MouseFocus()) m_buttons[i].BackColor(m_buttons_color_pressed[i]); //--- Falls es keinen Fokus gibt, dann... else { //--- ...Falls kein Group-Button gedrückt ist, Zuweisen der Hintergrundfarbe if(!m_buttons_state[i]) m_buttons[i].BackColor(m_buttons_color[i]); } } }
Nun ist alles für einen ersten Test der einfachen Group-Buttons in unserer Test Anwendung bereit. Erzeugen Sie eine Kopie des EAs, welchen wir zuvor getestet haben Entfernen Sie alle Controls mit Ausnahme des Hauptmenüs und seinen Kontextmenüs. Wir werden dieses Programm für den Test von verschiedenen Button-Groups in diesem Artikel verwenden.
Erzeugen sie eine Instanz der CButtonsGroup Klasse der Button-Groups in der benutzerdefinierten Klasse. Deklarieren Sie die CProgram::CreateButtonsGroup1() Methode für ihre Erzeugung und die Ränder von den Seiten der Form.
class CProgram : public CWndEvents { private: //--- Gruppe mit einfachen Buttons CButtonsGroup m_buttons_group1; //--- private: //--- Gruppe mit einfachen Buttons #define BUTTONS_GROUP1_GAP_X (7) #define BUTTONS_GROUP1_GAP_Y (50) bool CreateButtonsGroup1(void); };
Erzeugen sie eine Gruppe mit 4 Buttons. Platzieren Sie diese horizontal. In diesem Beispiel werden wir zwei Buttons rot machen und zwei blau. Die Implementation der CProgram::CreateButtonsGroup1() Methode wird in den nachfolgenden Code gezeigt. Wenn Sie direkt nach dem Start einen Button hervorheben möchten, dann verwenden Sie die CButtonsGroup::SelectionButton() public Methode.
//+---------------------------------------------------------------- //| Erzeugt eine Gruppe von einfachen Buttons | //+---------------------------------------------------------------- bool CProgram::CreateButtonsGroup1(void) { //--- Abspeichern des Fenster-Pointers m_buttons_group1.WindowPointer(m_window); //--- Koordinaten int x =m_window.X()+BUTTONS_GROUP1_GAP_X; int y =m_window.Y()+BUTTONS_GROUP1_GAP_Y; //--- Eigenschaften int buttons_x_gap[] ={0,72,144,216}; string buttons_text[] ={"BUTTON 1","BUTTON 2","BUTTON 3","BUTTON 4"}; int buttons_width[] ={70,70,70,70}; color buttons_color[] ={C'195,0,0',C'195,0,0',clrRoyalBlue,clrRoyalBlue}; color buttons_color_hover[] ={C'255,51,51',C'255,51,51',C'85,170,255',C'85,170,255'}; color buttons_color_pressed[] ={C'135,0,0',C'135,0,0',C'50,100,135',C'50,100,135'}; //--- Festlegen der Eigenschaften m_buttons_group1.TextColor(clrWhite); m_buttons_group1.TextColorPressed(clrGold); //--- Vier Buttons einer Gruppe hinzufügen for(int i=0; i<4; i++) m_buttons_group1.AddButton(buttons_x_gap[i],0,buttons_text[i],buttons_width[i], buttons_color[i],buttons_color_hover[i],buttons_color_pressed[i]); //--- Eine Gruppe von Buttons erzeugen if(!m_buttons_group1.CreateButtonsGroup(m_chart_id,m_subwin,x,y)) return(false); //--- Hervorheben des zweiten Buttons in der Gruppe m_buttons_group1.SelectionButton(1); //--- Ein Objekt dem gemeinsamen Array von Objektgruppen hinzufügen CWndContainer::AddToElementsArray(0,m_buttons_group1); return(true); }
Nachdem sie den Programmcode kompiliert haben und den Test EA dem Chart hinzugefügt haben, sollten Sie das folgende Ergebnis sehen:
Abbildung 2. Der Test einer Gruppe mit einfachen Buttons.
Wir haben nun mit der ersten Gruppe von Buttons abgeschlossen. Die vollständige Version in der CButtonsGroup Klasse kann am Ende des Artikels heruntergeladen werden. Bei dem nächsten control handelt es sich um eine Gruppe von Radiobuttons.
Entwicklung einer Klasse für die Erzeugung einer Gruppe von Radiobuttons
Erzeugen Sie die RadioButtons.mqh Datei mit der CRadioButtons Klasse, welche Standard virtuelle Methoden und Klassen für das Abspeichern und Abfragen des Formular-Pointers besitzen muss. Sie können sich die Beispiele in den Klassen der anderen Controls ansehen, die wir oben gezeigt haben. Beziehen Sie die RadioButtons.mqh Datei in der Bibliothek (WndContainer.mqh) mit ein.
Jeder Radio-Button besteht aus drei einfachen Objekten:
- Hintergrund;
- Icon;
- Text-Label.
Abbildung 3. Komponenten des Radio-Buttons
Anders als die Gruppe der einfachen Buttons, hat die Gruppe der Radio-Buttons nur einen Modus. Das liegt daran, dass in diesem Control nicht alle Buttons gleichzeitig ungedrückt sein können. In dieser Gruppe ist immer ein Button gedrückt. Die Hintergrundfarbe der Gruppe ist normalerweise gleich der Hintergrundfarbe des Formulars, zu welchem die Gruppe hinzugefügt worden ist. Im Wesentlichen dient sie dazu, den Fokus zu identifizieren und den Klick auf einen Radiobutton nachzuverfolgen (höhere Priorität) In dieser Version werden wir nur einen Farbwechsel des Textlabels durchführen, sobald der Mauszeiger sich über dem Hintergrund des Buttons befindet, oder ihn verlässt. Die Liste der speziellen und gemeinsamen Eigenschaften von einer Radiobutton-Group sind unterschiedlich zu der Liste und Eigenschaften einer Gruppe von einfachen Buttons, wie es wie folgt dargestellt wird:
Gemeinsame Eigenschaften:
- Farbe des Hintergrundes und des Rahmens.
- Textfarbe.
- Höhe.
- Icons der Buttons für (1) aktiv, (2) deaktiviert und (3) gesperrten Status.
- Priorität eines Klicks mit der linken Maustaste.
Spezielle Eigenschaften:
- Text.
- Breite.
- Status. Nur ein Button in der Gruppe kann gedrückt sein.
- Ränder. Ebenso wie die einfachen Buttons können auch die Radiobuttons in jeder beliebigen Reihenfolge angeordnet werden. (Mosaic, horizontal, vertikal...)
- Gradienten für das Text-Label.
Nachfolgend können Sie den Programmcode der CRadioButtons Klasse sehen. Die Größenanpassung der Arrays für die speziellen Eigenschaften und das Auffüllen der Werte, werden in der CRadioButtons::AddButton() public Methode vor der Erzeugung der Controls in der benutzerdefinierten Klasse durchgeführt. Wenn keine Buttons hinzugefügt worden sind, dann wird die Erzeugung des grafischen Interfaces abgebrochen. Dieses haben wir bereits während der Entwicklung der Klasse für die einfachen Gruppen-Buttons besprochen und werden daher hier nicht näher darauf eingehen.
//+---------------------------------------------------------------- //| Klasse für die Erzeugung einer Gruppe mit Radiobuttons | //+---------------------------------------------------------------- class CRadioButtons : public CElement { private: //--- Gradienten für das Text-Label. struct LabelsGradients { color m_labels_color_array[]; }; LabelsGradients m_labels_total[]; //--- Die Eigenschaften des Buttons: // (1) Color and (2) priority of the background of the left mouse click color m_area_color; int m_area_zorder; //--- Arrays für die speziellen Eigenschaften von Buttons bool m_buttons_state[]; int m_buttons_x_gap[]; int m_buttons_y_gap[]; int m_buttons_width[]; string m_buttons_text[]; //--- Höhe der Buttons int m_button_y_size; //--- Die Icons für die Buttons in dem aktiven, inaktiven und gesperrten Zustand string m_icon_file_on; string m_icon_file_off; string m_icon_file_on_locked; string m_icon_file_off_locked; //--- Die Textfarbe color m_text_color; color m_text_color_off; color m_text_color_hover; //--- Die Priorität der linken Maustaste int m_buttons_zorder; //--- public: //--- Festlegung der Icons des Buttons in dem aktiven, inaktiven und gesperrten Status void IconFileOn(const string file_path) { m_icon_file_on=file_path; } void IconFileOff(const string file_path) { m_icon_file_off=file_path; } void IconFileOnLocked(const string file_path) { m_icon_file_on_locked=file_path; } void IconFileOffLocked(const string file_path) { m_icon_file_off_locked=file_path; } //--- (1) Hintergrundfarbe, (2) Textfarbe void AreaColor(const color clr) { m_area_color=clr; } void TextColor(const color clr) { m_text_color=clr; } void TextColorOff(const color clr) { m_text_color_off=clr; } void TextColorHover(const color clr) { m_text_color_hover=clr; } //--- Fügt vor der Erzeugung einen Button mit den angegebenen Eigenschaften hinzu void AddButton(const int x_gap,const int y_gap,const string text,const int width); };
Jetzt müssen wir die Arrays für die Instanzen von primitiven Objektklassen und Methoden für deren Erzeugung erschaffen. Ähnlich wie bei der Gruppe der einfachen Buttons, werden die Radiobuttons in einer Schleife erzeugt. Aber hier Befindet sich die Schleife in der Hauptmethode und der Index, welcher zur Erzeugung des Namens von jedem Objekt beiträgt, wird der Methode für die Erzeugung dieser Objekte übergeben.
class CRadioButtons : public CElement { private: //--- Objekte für die Erzeugung eines Buttons CRectLabel m_area[]; CBmpLabel m_icon[]; CLabel m_label[]; //--- public: //--- Methoden für die Erzeugung eines Buttons bool CreateRadioButtons(const long chart_id,const int window,const int x,const int y); //--- private: bool CreateArea(const int index); bool CreateRadio(const int index); bool CreateLabel(const int index); //--- public: //--- Anzahl der Buttons int RadioButtonsTotal(void) const { return(::ArraySize(m_icon)); } }; //+---------------------------------------------------------------- //| Erzeugt eine Gruppe von Button Objekten | //+---------------------------------------------------------------- bool CRadioButtons::CreateRadioButtons(const long chart_id,const int window,const int x,const int y) { //--- Verlassen, wenn es keinen Pointer zu einer Form gibt if(::CheckPointer(m_wnd)==POINTER_INVALID) { ::Print(__FUNCTION__," > Before creating a group of radio buttons, the class must be passed " "the form pointer: CButtonsGroup::WindowPointer(CWindow &object)"); return(false); } //--- Initialisierung der Variablen m_id =m_wnd.LastId()+1; m_chart_id =chart_id; m_subwin =window; m_x =x; m_y =y; //--- Abfrage der Anzahl der Buttons in der Gruppe int radio_buttons_total=RadioButtonsTotal(); //--- Falls es keinen Button in dieser Gruppe gibt, dann benachrichtigen if(radio_buttons_total<1) { ::Print(__FUNCTION__," > This method is to be called " "if a group contains at least one button! Use the CRadioButtons::AddButton() method"); return(false); } //--- Einrichten einer Gruppe von Buttons for(int i=0; i<radio_buttons_total; i++) { CreateArea(i); CreateRadio(i); CreateLabel(i); //--- Zurücksetzen des Fokus m_area[i].MouseFocus(false); } //--- Verstecken des Elementes, falls es sich um ein Dialogfenster handelt, oder falls es minimiert ist if(m_wnd.WindowType()==W_DIALOG || m_wnd.IsMinimized()) Hide(); //--- return(true); }
Diese Klasse benötigt zu den Methoden für die Änderung des Zustandes eines Controls (verfügbar/gesperrt) und das Wechseln des Zustands über den angegebenen Index. In diesem Falle sind die Methoden ein wenig einfacher als in der CButtonsGroup Klasse, da eine Gruppe von Radiobutton es nur einen Modus besitzt. Diese Methoden finden Sie in den beigefügten Dateien zu diesem Artikel. Zusätzlich benötigen wir noch Methoden für die Abfrage des Textes und des Indexes von einem hervorgehobenen Button, so wie es auch in der Klasse für die einfachen Buttons der Fall ist.
class CButtonsGroup : public CElement { private: //--- (1) Text und (2) Index des hervorgehobenen Buttons string m_selected_button_text; int m_selected_button_index; //--- Verfügbar oder blockiert bool m_buttons_group_state; //--- public: //--- Genereller Status der Button-Gruppe (available/blocked) bool ButtonsGroupState(void) const { return(m_buttons_group_state); } void ButtonsGroupState(const bool state); //--- Gibt (1) den Text und (2) den Index des hervorgehobenen Buttons zurück string SelectedButtonText(void) const { return(m_selected_button_text); } int SelectedButtonIndex(void) const { return(m_selected_button_index); } //--- Wechselt den Status des Buttons mit dem angegebenen Index void SelectionButton(const int index); };
Für das Senden einer Nachricht über das Anklicken eines Controls, welches wie ein Text-Label auf dem Formular aussieht, verwenden wir den neuen Bezeichner ON_CLICK_LABEL Fügen Sie folgendes der Defines.mqh Datei hinzu:
#define ON_CLICK_LABEL (10) // Pressing of the text label
Nachfolgend wird die Implementation der Methoden für die Verarbeitung eines Klicks auf die Group-Buttons dargestellt. Nach dem erfolgreichen Abschluss der folgenden Überprüfungen (1) Die Zugehörigkeit zu dem Control Typ, (2) der Bezeichner und (3) die Verfügbarkeit, Wird der Index des angeklickten Buttons über den exakten Namen in der Schleife identifiziert. Falls ein Button dieser Gruppe gedrückt wurde und dieser Button im Augenblick nicht hervorgehoben ist, dann wird ein Wechsel des Zustandes durchgeführt und es wird eine NAchricht gesendet, welche in der benutzerdefinierten Klasse empfangen werden kann.
class CButtonsGroup : public CElement { private: //--- Verarbeiten eines Klicks auf einen Button bool OnClickButton(const string pressed_object); //--- Abfrage des Bezeichners über den Namen des radio buttons int IdFromObjectName(const string object_name); }; //+---------------------------------------------------------------- //| Chart Eventhandler | //+---------------------------------------------------------------- void CRadioButtons::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Verarbeiten eines Klicks mit der linken Maustaste auf ein Objekt if(id==CHARTEVENT_OBJECT_CLICK) { //--- Wechsel des Status des Buttons if(OnClickButton(sparam)) return; } } //+---------------------------------------------------------------- //| Klick auf einen Radiobutton | //+---------------------------------------------------------------- bool CRadioButtons::OnClickButton(const string pressed_object) { //--- Abbrechen, falls der Klick nicht auf diesem Menüpunkt stattgefunden hat if(::StringFind(pressed_object,CElement::ProgramName()+"_radio_area_",0)<0) return(false); //--- Abfragen des Bezeichners und des Indexes über den Objektnamen int id=IdFromObjectName(pressed_object); //--- Abbrechen, falls es nicht ein Klick auf ein Item war, zu welchem dieses Kontextmenü hinzugefügt wurde if(id!=CElement::Id()) return(false); //--- Für die Überprüfung des Index int check_index=WRONG_VALUE; //--- Abbrechen wenn die Buttons gesperrt sind if(!m_radio_buttons_state) return(false); //--- Falls ein Krieg stattgefunden hat, Abspeichern des Index int radio_buttons_total=RadioButtonsTotal(); for(int i=0; i<radio_buttons_total; i++) { if(m_area[i].Name()==pressed_object) { check_index=i; break; } } //--- Abbrechen, falls es keinen Klick auf einen Button dieser Gruppe gab, oder // Falls dieser Radiobutton schon hervorgehoben ist if(check_index==WRONG_VALUE || check_index==m_selected_button_index) return(false); //--- Wechsel des Status des Buttons SelectionRadioButton(check_index); //--- Eine Nachricht darüber senden ::EventChartCustom(m_chart_id,ON_CLICK_LABEL,CElement::Id(),check_index,m_selected_button_text); return(true); }
Nun ist alles bereit für einen Test. Fügen Sie dem EA vier Gruppen mit je 4 Radiobuttons hinzu(CRadioButtons) und eine Gruppe mit einfachen Buttons (CButtonsGroup).
class CProgram : public CWndEvents { private: //--- Gruppe mit Radiobuttons 1 CRadioButtons m_radio_buttons1; //--- Gruppe mit einfachen Buttons 2 CButtonsGroup m_buttons_group2; //--- Gruppe mit Radiobuttons 2,3,4 CRadioButtons m_radio_buttons2; CRadioButtons m_radio_buttons3; CRadioButtons m_radio_buttons4; //--- private: //--- Gruppe mit Radiobuttons 1 #define RADIO_BUTTONS1_GAP_X (7) #define RADIO_BUTTONS1_GAP_Y (75) bool CreateRadioButtons1(); //--- Gruppe mit einfachen Buttons 2 #define BUTTONS_GROUP2_GAP_X (7) #define BUTTONS_GROUP2_GAP_Y (100) bool CreateButtonsGroup2(void); //--- Gruppe mit Radiobuttons 2,3,4 #define RADIO_BUTTONS2_GAP_X (7) #define RADIO_BUTTONS2_GAP_Y (125) bool CreateRadioButtons2(); #define RADIO_BUTTONS3_GAP_X (105) #define RADIO_BUTTONS3_GAP_Y (125) bool CreateRadioButtons3(); #define RADIO_BUTTONS4_GAP_X (203) #define RADIO_BUTTONS4_GAP_Y (125) bool CreateRadioButtons4(); }; //+---------------------------------------------------------------- //| Erzeugung des Trading-Panels | //+---------------------------------------------------------------- bool CProgram::CreateTradePanel(void) { //--- Erzeugung einer Form für Controls //---Erzeugung der Controls: // Hauptmenü //--- Kontextmenüs //--- Gruppe mit einfachen Buttons 1 //--- Gruppe mit Radiobuttons 1 if(!CreateRadioButtons1()) return(false); //--- Gruppe mit einfachen Buttons 2 if(!CreateButtonsGroup2()) return(false); //--- Gruppe mit Radiobuttons 2,3,4 if(!CreateRadioButtons2()) return(false); if(!CreateRadioButtons3()) return(false); if(!CreateRadioButtons4()) return(false); //--- Neuzeichnen auf dem Chart m_chart.Redraw(); return(true); }
Beispielhaft zeigen wir hier die Implementation einer der Methoden für diese Gruppen. Der Rest unterscheidet sich nur durch Parameterwerte.
//+---------------------------------------------------------------- //| Erzeugte Gruppe mit Radiobuttons 1 | //+---------------------------------------------------------------- bool CProgram::CreateRadioButtons1(void) { //--- Übergabe des Panel Objektes m_radio_buttons1.WindowPointer(m_window); //--- Koordinaten int x =m_window.X()+RADIO_BUTTONS1_GAP_X; int y =m_window.Y()+RADIO_BUTTONS1_GAP_Y; //--- Eigenschaften int buttons_x_offset[] ={0,98,196}; int buttons_y_offset[] ={0,0,0}; string buttons_text[] ={"Radio Button 1","Radio Button 2","Radio Button 3"}; int buttons_width[] ={92,92,92}; //--- for(int i=0; i<3; i++) m_radio_buttons1.AddButton(buttons_x_offset[i],buttons_y_offset[i],buttons_text[i],buttons_width[i]); //--- Eine Gruppe von Buttons erzeugen if(!m_radio_buttons1.CreateRadioButtons(m_chart_id,m_subwin,x,y)) return(false); //--- Hervorheben des zweiten Buttons in der Gruppe m_radio_buttons1.SelectedRadioButton(1); //--- Sperren der Radiobuttons m_radio_buttons1.RadioButtonsState(false); //--- Ein Objekt dem gemeinsamen Array von Objektgruppen hinzufügen CWndContainer::AddToElementsArray(0,m_radio_buttons1); return(true); }
Lassen Sie uns zwei Buttons in der zusätzlichen (zweiten) Gruppe von Buttons des Typs CButtonsGroup erzeugen. Lassen Sie uns diese für Illustrationszwecke wie folgt arrangieren: Der zweite Button dieser Gruppe blockiert die erste Gruppe mit einfachen Radiobuttons und der Erste macht sie wieder verfügbar.
//+---------------------------------------------------------------- //| Event handler | //+---------------------------------------------------------------- void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Der Button event if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON) { ::Print("id: ",id,"; lparam: ",lparam,"; dparam: ",dparam,"; sparam: ",sparam); //--- Falls der Bezeichner der zweiten Gruppe oder der einfachen Buttons und // der Text des hervorgehobenen Buttons in dieser Gruppe mit dem String-Parameter der Nachricht uebereinstimmt if(lparam==m_buttons_group2.Id() && sparam==m_buttons_group2.SelectedButtonText()) { //--- Falls es sich um den Index des ersten Buttons handelt, entsperrung der angegebenen Controls if((int)dparam==0) { m_buttons_group1.ButtonsGroupState(true); m_radio_buttons1.RadioButtonsState(true); } //--- Falls es sich um den Index des zweiten Buttons handelt, sperren der angegebenen Controls else { m_buttons_group1.ButtonsGroupState(false); m_radio_buttons1.RadioButtonsState(false); } } return; } }
Kompilieren Sie die Projektdateien und laden Sie das Programm auf einem Chart. In diesem Stadium der Entwicklung, sollten Sie ein Ergebnis erhalten, wie es in der nachfolgenden Abbildung gezeigt ist:
Abbildung 4. Test des Radiobutton Controls.
Wir haben hiermit die Entwicklung einer Klasse für die Erzeugung einer Gruppe mit Radiobuttons abgeschlossen. Sie können eine vollständige Version am Ende dieses Artikels herunterladen.
Erzeugen einer Klasse für die Erzeugung einer Gruppe von Icon-Buttons
Wir haben zuvor schon die CIconButton Klasse für die Erzeugung eines Icon Button Controls erzeugt Nun werden wir ein Control implementieren, welches uns die Möglichkeit gibt, eine Gruppe von diesen Buttons zu erzeugen. Erzeugen Sie die IconButtonsGroup.mqh Datei mit der CIconButtonsGroup Klasse in dem Controls Verzeichnis, in welcher Sie die Standard virtuellen Methoden implementieren. Beziehen Sie diese Datei in der WndContainer.mqh Datei mit ein.
Wir beschreiben dieses nicht im Detail, da die CIconButtonsGroup Klasse im wesentlichen eine Zusammenstellung von Methoden ist, die wir bereits in der CButtonsGroup und CRadioButtons Klasse besprochen haben. Ähnlich wie bei der CRadioButtons Klasse mit Radiobuttons, werden die Objekte der Button Gruppe mit den privaten Methoden in einer Schleife der Hauptmethode für das Erzeugen des Controls erzeugt. Der einzige Parameter dieser Methode ist der Index, der für die Bildung des Namens des grafischen Objektes benötigt wird. Wir gestalten es so, dass die Buttons dieser Gruppe ihre Hintergrundfarbe und den Text ändern, wenn sich der Mauszeiger über ihnen befindet.
Die Methoden für die Verarbeitung von Events haben wir in diesem Artikel bereits besprochen. Sie sind bei dieser Art von Gruppen-Buttons identisch, und daher zeigen wir hier nur den Inhalt derCIconButtonsGroup Klasse. Die Implementation der Methoden, die sich außerhalb des Körpers der Klasse befinden, können in den an diesen Artikel angefügten Dateien nachgesehen werden.
//+---------------------------------------------------------------- //| Klasse für die Erzeugung einer Gruppe mit Icon-Buttons | //+---------------------------------------------------------------- class CIconButtonsGroup : public CElement { private: //--- Pointer zu dem Formular, zu welchem das Control hinzugefügt wurde CWindow *m_wnd; //--- Objekte für die Erzeugung eines Buttons CButton m_buttons[]; CBmpLabel m_icons[]; CLabel m_labels[]; //--- Gradienten für das Text-Label. struct IconButtonsGradients { color m_back_color_array[]; color m_label_color_array[]; }; IconButtonsGradients m_icon_buttons_total[]; //--- Die Eigenschaften des Buttons: // Arrays Für spezielle Eigenschaften von Buttons bool m_buttons_state[]; int m_buttons_x_gap[]; int m_buttons_y_gap[]; string m_buttons_text[]; int m_buttons_width[]; string m_icon_file_on[]; string m_icon_file_off[]; //--- Höhe der Buttons int m_buttons_y_size; //--- Die Hintergrundfarbe in den unterschiedlichen Modi color m_back_color; color m_back_color_off; color m_back_color_hover; color m_back_color_pressed; //--- Die Farbe des Rahmens color m_border_color; color m_border_color_off; //--- Icon Ränder int m_icon_x_gap; int m_icon_y_gap; //--- Text und Text Label Abstände int m_label_x_gap; int m_label_y_gap; //--- Text Label Farbe in den unterschiedlichen Modi color m_label_color; color m_label_color_off; color m_label_color_hover; color m_label_color_pressed; //--- (1) Text und (2) Index des hervorgehobenen Buttons string m_selected_button_text; int m_selected_button_index; //--- Generelle Priorität nicht anklickbarer Objekte int m_zorder; //--- Die Priorität der linken Maustaste int m_buttons_zorder; //--- Verfügbar oder blockiert bool m_icon_buttons_state; //--- public: CIconButtonsGroup(void); ~CIconButtonsGroup(void); //--- Methoden für die Erzeugung eines Buttons bool CreateIconButtonsGroup(const long chart_id,const int window,const int x,const int y); //--- private: bool CreateButton(const int index); bool CreateIcon(const int index); bool CreateLabel(const int index); //--- public: //--- (1) Speichert den Pointer des Formulars, (2) Button-Höhe, (3) Anzahl von Buttons, // (4) Genereller Status des Buttons (verfügbar/gesperrt) void WindowPointer(CWindow &object) { m_wnd=::GetPointer(object); } void ButtonsYSize(const int y_size) { m_buttons_y_size=y_size; } int IconButtonsTotal(void) const { return(::ArraySize(m_icons)); } bool IconButtonsState(void) const { return(m_icon_buttons_state); } void IconButtonsState(const bool state); //--- Hintergrundfarben der Buttons void BackColor(const color clr) { m_back_color=clr; } void BackColorOff(const color clr) { m_back_color_off=clr; } void BackColorHover(const color clr) { m_back_color_hover=clr; } void BackColorPressed(const color clr) { m_back_color_pressed=clr; } //--- Icon Ränder void IconXGap(const int x_gap) { m_icon_x_gap=x_gap; } void IconYGap(const int y_gap) { m_icon_y_gap=y_gap; } //--- Die Ränder des Text Labels void LabelXGap(const int x_gap) { m_label_x_gap=x_gap; } void LabelYGap(const int y_gap) { m_label_y_gap=y_gap; } //--- Gibt (1) den Text und (2) den Index des hervorgehobenen Buttons zurück string SelectedButtonText(void) const { return(m_selected_button_text); } int SelectedButtonIndex(void) const { return(m_selected_button_index); } //--- Wechselt den Status eines Radiobuttons über den angegebenen Index void SelectedRadioButton(const int index); //--- Fügt vor der Erzeugung einen Button mit den angegebenen Eigenschaften hinzu void AddButton(const int x_gap,const int y_gap,const string text, const int width,const string icon_file_on,const string icon_file_off); //--- Wechsel der Farbe void ChangeObjectsColor(void); //--- public: //--- Chart Eventhandler virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- Timer virtual void OnEventTimer(void); //--- Verschieben eines Controls virtual void Moving(const int x,const int y); //--- (1) Anzeigen, (2) verstecken, (3) zurücksetzen, (4) löschen virtual void Show(void); virtual void Hide(void); virtual void Reset(void); virtual void Delete(void); //--- (1) Setzen, (2) Zurücksetzen der Prioritäten des Klicks mit der linken Maustaste virtual void SetZorders(void); virtual void ResetZorders(void); //--- private: //--- Verarbeiten eines Klicks auf einen Button bool OnClickButton(const string pressed_object); //--- Überprüfen, ob die linke Maustaste über den Group Buttons gedrückt wurde void CheckPressedOverButton(void); //--- Abfrage des Bezeichners über den Namen des radio buttons int IdFromObjectName(const string object_name); };
Lassen Sie uns dieses Control nun testen. Als Beispiel erzeugen sie eine Gruppe von Icon-Buttons auf dem Formular desselben EAs, welchen wir zuvor für den Test der Group-Buttons des Typs CButtonsGroup und CRadioButtons verwendet haben. Dazu fügen Sie den nachfolgenden Programmcode der benutzerdefinierten Klasse hinzu.
class CProgram : public CWndEvents { private: //--- Gruppe von Icon Buttons 1 CIconButtonsGroup m_icon_buttons_group1; //--- private: //--- Gruppe von Icon Buttons 1 #define IBUTTONS_GROUP1_GAP_X (7) #define IBUTTONS_GROUP1_GAP_Y (190) bool CreateIconButtonsGroup1(void); }; //+---------------------------------------------------------------- //| Erzeugung des Trading-Panels | //+---------------------------------------------------------------- bool CProgram::CreateTradePanel(void) { //--- Erzeugung einer Form für Controls //---Erzeugung der Controls: // Hauptmenü //--- Kontextmenüs //--- Gruppe mit einfachen Buttons 1 //--- Gruppe mit Radiobuttons 1 //--- Gruppe mit einfachen Buttons 2 //--- Gruppe mit Radiobuttons 2,3,4 //--- Gruppe von Icon Buttons 1 if(!CreateIconButtonsGroup1()) return(false); //--- Neuzeichnen auf dem Chart m_chart.Redraw(); return(true); }
Kompilieren Sie die Projektdateien und laden Sie das Programm auf einem Chart. Das Ergebnis sollte so aussehen, wie es in dem nachfolgenden Screenshot gezeigt wird.
Abbildung 5. Test einer Gruppe mit Icon-Buttons
Die Entwicklung einer Klasse für die Erzeugung einer Gruppe mit Icon-Buttons ist nun abgeschlossen. Sie können eine vollständige Version am Ende dieses Artikels herunterladen.
Schlussfolgerung
Dieses ist das Ende des dritten Teils der Serie über die Entwicklung einer Bibliothek für die Erzeugung von grafischen Interfaces in den MetaTrader Trading Terminals. Im Augenblick sieht die Struktur der Bibliothek wie folgt aus:
Abbildung 6. Die Struktur der Bibliothek zum aktuellen Stand der Entwicklung.
In dem nächsten (vierten) Teil dieser Serie, werden wir die Entwicklung der Bibliothek fortsetzen. Wir werden die folgenden Punkte betrachten:
- Multi-Window Modus.
- Ein System für die Verwaltung von Prioritäten eines Klicks mit der linken Maustaste auf grafische Objekte.
- Informationselemente wie die Statusbar und Tooltips.
Die nachfolgend angehängten Archive mit den Programmdateien und Bildern entsprechend dem aktuellen Entwicklungsstatus, können für Tests in den MetaTrader Terminals heruntergeladen werden. Wenn Sie fragen zur Verwendung dieses Materials haben, dann können Sie zunächst auf die detaillierte Beschreibung in dem Artikel zu dieser Bibliothek zurückgreifen oder Sie stellen Ihre Frage(n) in den Kommentaren zu diesem Artikel.
Liste der Artikel(Kapitel) des dritten Teils:
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/2298





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.