Обсуждение статьи "Сделайте торговые графики лучше с интерактивным графическим интерфейсом на основе MQL5 (Часть III): Простой перемещаемый торговый интерфейс"

 

Опубликована статья Сделайте торговые графики лучше с интерактивным графическим интерфейсом на основе MQL5 (Часть III): Простой перемещаемый торговый интерфейс:

В этой серии статей мы исследуем интеграцию интерактивных графических интерфейсов в перемещаемые торговые панели на MQL5. В третьей части мы используем наработки из предыдущих частей, чтобы превратить статические торговые панели в динамические.

Для начала давайте вспомним, что мы рассмотрели в предыдущих двух частях:

1. В первой части мы рассмотрели концепцию событий графика, а затем создали две простые перемещаемые панели на одном графике.

2. Во второй части мы пошли еще дальше. Мы использовали классы в файле .mqh, чтобы сделать наш код более эффективным и универсальным, готовым к интеграции с полномасштабными советниками/индикаторами.


В третьей части мы сосредоточимся на улучшении наших панелей путем интеграции в них графических интерфейсов. Без графического интерфейса панели не будут служить своему прямому назначению.

Автор: Kailash Bai Mina

 

Наглядный пример использования ООП ради ООП.

Получилось громоздко и не удобно (ИМХО). Но работает, а это уже хорошо :)


Нужно добавить OBJPROP_ZORDER иначе кнопки нажимаются через раз.

void Button::Create(string name, int xDis = 0, int yDis = 0, int xSize = 0, int ySize = 0)
  {
   ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xDis);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yDis);
   ObjectSetInteger(0, name, OBJPROP_XSIZE, xSize);
   ObjectSetInteger(0, name, OBJPROP_YSIZE, ySize);
   ObjectSetInteger(0, name, OBJPROP_ZORDER, 1);
   _name = name;
  }
//+------------------------------------------------------------------+
 
Alexander Slavskii #:
ut it works, which is good :)

Thanks for the suggestion.

 
Aleksandr Slavskii #:

Наглядный пример использования ООП ради ООП.

Получилось громоздко и не удобно (ИМХО). Но работает, а это уже хорошо :)


Нужно добавить OBJPROP_ZORDER иначе кнопки нажимаются через раз.

это вообще не ООП. Это повторно завёрнутые в классы методы терминала. 

если программист захочет сделать иной GUI (модный http, через WebSocket освещённый в прочих статьях), то ничего сделать не сможет. Просто выбросит вообще весь код из статьи и напишет иной.

чтобы коренным образом поменять визуальную часть, но на тех-же ObjectCreate(xx) - всё равно придётся переписывать просто всё.

или как отключить GUI, чтобы он не занимал процессор на VDS-ке

Где reusability ? Почему GUI перемежается с прочим кодом..Про стили, хотя-бы цвета, можно и не говорить

Используя библиотеки статьи, код типичного советника стал короче ? а вот хренушки, не для того писано :-)

 
Maxim Kuznetsov #:

это вообще не ООП. Это повторно завёрнутые в классы методы терминала. 

если программист захочет сделать иной GUI (модный http, через WebSocket освещённый в прочих статьях), то ничего сделать не сможет. Просто выбросит вообще весь код из статьи и напишет иной.

чтобы коренным образом поменять визуальную часть, но на тех-же ObjectCreate(xx) - всё равно придётся переписывать просто всё.

или как отключить GUI, чтобы он не занимал процессор на VDS-ке

Где reusability ? Почему GUI перемежается с прочим кодом..Про стили, хотя-бы цвета, можно и не говорить

Используя библиотеки статьи, код типичного советника стал короче ? а вот хренушки, не для того писано :-)

Ну обсуждать цвета, думаю здесь не совсем корректно.

А вот то что кнопки бай и селл расположены наоборот, это  может ввести пользователя в заблуждение.


Не понятно зачем отключать  GUI, если это панель для ручной торговли. Хотя, если это не торговая панель, а информационная, то да, лучше продумать отключение.

Мне понравилось как организованна функция RectangleLabel::OnEvent и RectangleLabel::Add, красиво, понятно, читаемо.

Я в своих панельках использовал такой же принцип, но у меня код был какой то корявый, что ли. В общем не красивый. Вот и решил использовать код из статьи для новой панельки.

Панелька в итоге получилась, но времени убил на это больше, чем если бы писал с нуля.

В общем вывод такой: статья интересная, полезная, но код в статье частично не продуман. 

 
Aleksandr Slavskii #:

Ну обсуждать цвета, думаю здесь не совсем корректно.

А вот то что кнопки бай и селл расположены наоборот, это  может ввести пользователя в заблуждение.


Не понятно зачем отключать  GUI, если это панель для ручной торговли. Хотя, если это не торговая панель, а информационная, то да, лучше продумать отключение.

Мне понравилось как организованна функция RectangleLabel::OnEvent и RectangleLabel::Add, красиво, понятно, читаемо.

Я в своих панельках использовал такой же принцип, но у меня код был какой то корявый, что ли. В общем не красивый. Вот и решил использовать код из статьи для новой панельки.

Панелька в итоге получилась, но времени убил на это больше, чем если бы писал с нуля.

В общем вывод такой: статья интересная, полезная, но код в статье частично не продуман. 

есть тьма проработанных методик с красивыми стрелочками "как реализовать UI чтобы не было мучительно больно" :-) MVC и подобные. Так там фронт (win,gtk,qt,web) подчас можно менять лёгким движением руки. 

ни одно не было реализовано в MQL. Тут всё прибивается наглухо гвоздями, хуже TurboVision - там хоть так-же классы от адама, но там есть модели  

отдельные лица годами(!!) пишут про "легко и просто" и "простой интерфейс", но ровно то-же самое что в этой статье. Масса кода не облегчающего ничего. Единственный эффект - бонус на счёт автора.

 
Maxim Kuznetsov #:

есть тьма проработанных методик с красивыми стрелочками "как реализовать UI чтобы не было мучительно больно" :-) MVC и подобные. Так там фронт (win,gtk,qt,web) подчас можно менять лёгким движением руки. 

ни одно не было реализовано в MQL. Тут всё прибивается наглухо гвоздями, хуже TurboVision - там хоть так-же классы от адама, но там есть модели  

отдельные лица годами(!!) пишут про "легко и просто" и "простой интерфейс", но ровно то-же самое что в этой статье. Масса кода не облегчающего ничего. Единственный эффект - бонус на счёт автора.

Ой, у меня одно только упоминание об  MVC вызывает ужас.

Это осталось с тех пор как я, жене сайт, интернет магазина делал на движке OcStore.

К тому времени как пришло хоть какое то понимание как это работает, я был наполовину седой)))


Давайте не будем судить строго, эта серия статей ориентирована на начинающих.

Статьи написаны понятно и доходчиво, а написать понятно это не такая уж простая задача.

Автор, справляется с этой задачей на отлично.

 
Aleksandr Slavskii #:

Ой, у меня одно только упоминание об  MVC вызывает ужас.

Это осталось с тех пор как я, жене сайт, интернет магазина делал на движке OcStore.

К тому времени как пришло хоть какое то понимание как это работает, я был наполовину седой)))


Давайте не будем судить строго, эта серия статей ориентирована на начинающих.

Статьи написаны понятно и доходчиво, а написать понятно это не такая уж простая задача.

Автор, справляется с этой задачей на отлично.

у меня вот воспоминание о том чтобы считать ширину/высоту и относительные и абс.координаты всратой кнопки повергают в уныние :-)

2024 год - но пр прежнему, пользователь библиотеки должен считать пиксели 

приведёный диалог, в виде : поле ввода объёмов и две кнополки buy/sell

как приведённый диалог решает проблемы с допустимостью объёмов и возможностью торговли ? да, лоты не могут быть менее минимума, инкременируются по шагам и не более максимума. Buy/Sell не всегда возможны.
Хоть намётки на решения есть ? нету

КАК ? в рукопашку-же...внутри советника вручную рулить всеми опциями конкретного GUI. Ничуть не лучше использольвания напрямую функций терминала.

между ObjectSetXXX(chart,objName,propertyName,propertyValue) и obj.SetInteger(value) - разница покрывается дефайнами, тут не нужно никакое ООП

---

это уже не в плане статьи, это вообще про "писателей". Лучше-бы читали

 
Maxim Kuznetsov # :

I have a memory of calculating the width/height and the relative and absolute coordinates of a button, which is depressing :-)

2024 - but still, the library user must count pixels 

the given dialogue, in the form: volume input field and two buy/sell buttons

How does the above dialogue solve problems with the admissibility of volumes and the possibility of trading? Yes, lots cannot be less than the minimum, they are incremented in steps and no more than the maximum. Buy/Sell is not always possible. Are there any hints of solutions? There is not

HOW? in hand-to-hand combat... inside the advisor, manually control all the options of a specific GUI. It's no better than using the terminal functions directly.

between ObjectSetXXX(chart,objName,propertyName,propertyValue) and obj.SetInteger(value) - the difference is covered by definitions, no OOP is needed here

---

This is no longer in terms of the article, it's generally about “writers”. It would be better if they read

Just one thing, I would like to point out is, this series was not written for this Buy/Sell GUI rather it was written for any GUI and this Buy/Sell GUI acts as an simple example.

Thanks for giving the series such thoughts, would appreciate suggestions.

Regards

 
Maxim Kuznetsov #:

у меня вот воспоминание о том чтобы считать ширину/высоту и относительные и абс.координаты всратой кнопки повергают в уныние :-)

2024 год - но пр прежнему, пользователь библиотеки должен считать пиксели 

приведёный диалог, в виде : поле ввода объёмов и две кнополки buy/sell

как приведённый диалог решает проблемы с допустимостью объёмов и возможностью торговли ? да, лоты не могут быть менее минимума, инкременируются по шагам и не более максимума. Buy/Sell не всегда возможны.
Хоть намётки на решения есть ? нету

КАК ? в рукопашку-же...внутри советника вручную рулить всеми опциями конкретного GUI. Ничуть не лучше использольвания напрямую функций терминала.

между ObjectSetXXX(chart,objName,propertyName,propertyValue) и obj.SetInteger(value) - разница покрывается дефайнами, тут не нужно никакое ООП

---

это уже не в плане статьи, это вообще про "писателей". Лучше-бы читали

Блин, у меня это всего третья панелька, первые две вспоминать не охота, если их увидит какой нибудь кодер, мне будет стыдно.

Хотелось бы сделать сейчас так, чтоб в следующий раз не пришлось столько с ней возится.

Сейчас в подключаемом файле оставил только класс с кодом для перетаскивания всех элементов панели и кучка гетов.

class CreateObject
  {
private:
   string            _name; // Name of the rectangle label
   int               previousMouseState, mlbDownX, mlbDownY, mlbDownXDistance, mlbDownYDistance; // Mouse state tracking variables
   bool              movingState; // State for whether the object is moving
   string            addedNames[]; // Array of added names
   long              addedXDisDiffrence[], addedYDisDiffrence[]; // Arrays to store added distance differences
   void              Destroy() {for(int i = 0; i < (int)addedNames.Size(); i++)ObjectDelete(0, addedNames[i]); ObjectDelete(0, _name);} // Destroy method for rectangle label
public:
                     CreateObject(void); // Constructor
                    ~CreateObject(void); // Destructor
   void              SetName(string name) {_name = name;}
   string            GetText(string name) {return ObjectGetString(0, name, OBJPROP_TEXT);} // Method to retrieve the text content
   long              GetType(string name) {return ObjectGetInteger(0, name, OBJPROP_TYPE);}
   double            GetPrice(string name) {return ObjectGetDouble(0, name, OBJPROP_PRICE);}
   void              OnEvent(int id, long lparam, double dparam, string sparam); // Event handler method
   void              Add(string name); // Method to add a name to the object
  };
//+------------------------------------------------------------------+
CreateObject::CreateObject(void) {}
//+------------------------------------------------------------------+
CreateObject::~CreateObject(void) {Destroy();}
//+------------------------------------------------------------------+
//| Event handling for mouse movements                               |
//+------------------------------------------------------------------+
void CreateObject::OnEvent(int id, long lparam, double dparam, string sparam)
  {
// Handle mouse movement events for dragging the rectangle label
   if(id == CHARTEVENT_MOUSE_MOVE && lparam > 20 && dparam > 20 &&
      lparam < ChartGetInteger(0, CHART_WIDTH_IN_PIXELS) - 20 && dparam < ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS) - 20)
     {
      int X = (int)lparam;
      int Y = (int)dparam;
      int MouseState = (int)sparam;

      string name = _name;
      int XDistance = (int)ObjectGetInteger(0, name, OBJPROP_XDISTANCE);
      int YDistance = (int)ObjectGetInteger(0, name, OBJPROP_YDISTANCE);
      int XSize = (int)ObjectGetInteger(0, name, OBJPROP_XSIZE);
      int YSize = (int)ObjectGetInteger(0, name, OBJPROP_YSIZE);

      if(previousMouseState == 0 && MouseState == 1)
        {
         mlbDownX = X;
         mlbDownY = Y;
         mlbDownXDistance = XDistance;
         mlbDownYDistance = YDistance;

         if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize)
           {
            movingState = true;
           }
        }

      if(movingState)
        {
         ChartSetInteger(0, CHART_MOUSE_SCROLL, false);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY);
         for(int i = 0; i < ArraySize(addedNames); i++)
           {
            ObjectSetInteger(0, addedNames[i], OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX - addedXDisDiffrence[i]);
            ObjectSetInteger(0, addedNames[i], OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY - addedYDisDiffrence[i]);
           }
         ChartRedraw(0);
        }

      if(MouseState == 0)
        {
         movingState = false;
         ChartSetInteger(0, CHART_MOUSE_SCROLL, true);
        }

      previousMouseState = MouseState;
     }
  }
//+------------------------------------------------------------------+
//| Method to add an object by name to the rectangle label           |
//+------------------------------------------------------------------+
void CreateObject::Add(string name)
  {
// Add a new object by name to the rectangle label and track distances
   ArrayResize(addedNames, ArraySize(addedNames) + 1);
   ArrayResize(addedXDisDiffrence, ArraySize(addedXDisDiffrence) + 1);
   ArrayResize(addedYDisDiffrence, ArraySize(addedYDisDiffrence) + 1);

   addedNames[ArraySize(addedNames) - 1] = name;
   addedXDisDiffrence[ArraySize(addedXDisDiffrence) - 1] = ObjectGetInteger(0, _name, OBJPROP_XDISTANCE) - ObjectGetInteger(0, name, OBJPROP_XDISTANCE);
   addedYDisDiffrence[ArraySize(addedYDisDiffrence) - 1] = ObjectGetInteger(0, _name, OBJPROP_YDISTANCE) - ObjectGetInteger(0, name, OBJPROP_YDISTANCE);
  }
//+------------------------------------------------------------------+

А ниже у меня просто функции для рисования объектов, скопипастил из справки, вроде так удобнее всё в одной кучке.

В итоге код в советнике был длинный, стал широкий, в общем поменял шило на мыло.

Ещё один подключаемый файл с часто используемыми торговыми функциями, типа посчитать все позиции, нормализовать цену, закрыть позиции, ну и т.д.

Но это всё равно как то громоздко и не универсально.

В следующей панельке всё равно по новой придётся высчитывать каждое поле и писать обработку для этих полей(кнопки/поле ввода).

И я что то ну никак не могу придумать схемку как сделать это всё более универсально.

Может, чего доброго подскажите по оформлению кода?

 
Aleksandr Slavskii #:

Но это всё равно как то громоздко и не универсально.

В следующей панельке всё равно по новой придётся высчитывать каждое поле и писать обработку для этих полей(кнопки/поле ввода).

И я что то ну никак не могу придумать схемку как сделать это всё более универсально.

Может, чего доброго подскажите по оформлению кода?

Наиболее практичный и универсальный вариант - дизайнить формы визуально, не заботясь о коде раскладки вообще - этим как раз должны заниматься классы. Одно из возможных решений было в статье.

Язык MQL как средство разметки графического интерфейса MQL-программ (Часть 3). Дизайнер форм
Язык MQL как средство разметки графического интерфейса MQL-программ (Часть 3). Дизайнер форм
  • www.mql5.com
В этой статье мы завершаем описание концепции построения оконного интерфейса MQL-программ с помощью конструкций языка MQL. Специальный графический редактор позволит интерактивно настраивать раскладку, состоящую из основных классов элементов GUI, и затем экспортировать её в MQL-описание для использования в вашем MQL-проекте. Представлено внутреннее устройство редактора и руководство пользователя. Исходные коды прилагаются.
Причина обращения: