Делаем GUI

17 января 2023, 00:21
Maxim Kuznetsov
0
102

Сейчас по шагам, сделаем простой-простой  GUI  (для начала одну форму) для советника MT5

скрипт на tcl/tk

Будем делать следующую форму: внутри рамки с заголовком, подсказка и текстовое поле ввода, внизу формы две кнопки ok/cancel. Когда-нибудь в дальнейшем будем добавлять разные дополнительные поля, а пока ограничемся всего одним.

То есть эскиз будет выглядеть примерно так:

дальше знакомимся с документацией Tk http://www.tcl-lang.org/man/tcl8.6/TkCmd/contents.htm , обращая внимание на подходящие виджеты (ttk::labelframe ttk::label ttk::entry ttk::button) и grid

пишем скрипт, который отобразит форму:

# комментарии начинаются с # и идут до конца строки

# скрипт GUI, нужен пакет Tk
package require Tk

# создаём все элементы
# окно с внутренним именем .form
toplevel .win
# внутри него невидимый фрейм
ttk::frame .win.carea
# уже в котором наш фрейм с рамкой и заголовком
ttk::labelframe .win.carea.form -text "заголовок"
# и кнопки cancel,ok (хотя их тоже можно было в отдельный фрейм)
ttk::button .win.carea.cancel -text "cancel"
ttk::button .win.carea.ok -text "ok"
# внутри формы - подсказка к полю ввода и само поле ввода
ttk::label .win.carea.form.prompt -text "подсказка"
ttk::entry .win.carea.form.entry

# теперь каждый фрейм сверстаем как таблицы 
# внутри окна у нас только один фрейм на всю единственную ячейку таблицы
grid .win.carea -row 0 -column 0 -sticky "nsew"
# разрешим строке и колонке растягиваться
grid rowconfigure .win 0 -weight 1
grid columnconfigure .win 0 -weight 1

# теперь фрейм .win.carea
grid .win.carea.form -row 0 -column 0 -columnspan 3 -sticky "nsew"
grid .win.carea.cancel -row 1 -column 1 -sticky "nsew"
grid .win.carea.ok -row 1 -column 2 -sticky "nsew"
grid columnconfigure .win.carea 0 -uniform same -weight 1
grid columnconfigure .win.carea 1 -uniform same -weight 1
grid columnconfigure .win.carea 2 -uniform same -weight 1
grid rowconfigure .win.carea 0 -weight 1

# и собственно элементы формы
grid .win.carea.form.prompt -row 0 -column 0 -sticky "nsew"
grid .win.carea.form.entry -row 0 -column 1 -sticky "nsew"
grid columnconfigure .win.carea.form 0 -weight 1
grid columnconfigure .win.carea.form 1 -weight 2

периодически запускаем наш скрипт :  tclsh -encoding utf-8 form.tcl  (я предпочитаю кодировку utf-8 в исходниках, и вам советую)

обратите внимание: при запуске скрипта возникает ещё одно окно. Это основное окно для приложения, мы в него ничего не добавляли поэтому оно пустое. И тоже сразу заметим что нажатие на «крестик» закрывает нашу форму.

Добавим пару строчек, в которых скроем основное окно и предотвратим закрытие формы по крестику:

# скрываем основное окно
wm withdraw .
# запрещаем закрывать форму
# (вместо закрытий, просто свернём)
wm protocol .win WM_DELETE_WINDOW { wm iconify .win }

Любуемся полученным результатом:

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

И кстати у нас почти всё готово чтобы поместить форму в советник и запускать в MetaTrader`е. Надо только заставить кнопки работать и самому-с-собой договориться как передавать данные. Пока поступим самым простым способом: при нажатии кнопки Ok в глобальную переменную поместим список {1 значение_из_поля_ввода} . Единица это просто сами придумали такой код . А терминал будет периодично опрашивать переменную и как-то реагировать.

Назначаем действия для кнопок:

# действия для кнопки Ok
# создадим переменную
set BOX {}
.win.carea.ok configure -command {
        # получаем текст из поля ввода
        set text [ .win.carea.form.entry get ]
        # удалим лишние пробелы
        set text [ string trim $text ]
        # если не пусто - зададим значение глобальной переменной
        if { $text != {} } {
                global BOX 
                set BOX [ list 1 $text ]
        }
}
# и заодно уж cancel будет очищать поле ввода
.win.carea.cancel configure -command {
        .win.carea.form.entry delete 0 end
}

Мы закончили с  GUI , начальная форма рисуется, кнопки нажимаются. Дальше будем делать уже советник на MQL5. А скрипт можем пока передать дизайнеру - пусть наводит лоск, добавляет элементы.

советник MQL5

Так как это просто демонстрация, то советник будет элементарный - при запуске показывает форму, при получении данных из формы будет выкидывать Alert:

#resource "form.tcl" as string Form_tcl; // заберём скрипт в виде ресурса
 
#include <ATcl/ATcl.mqh>
ATcl *tcl=NULL;
 
int OnInit()
{
   // инициализуем библиотеку
   if (ATcl_OnInit()!=INIT_SUCCEEDED) {
      return INIT_FAILED;
   }
   // создаём интерпретатор 
   tcl=new ATcl();
   if (tcl==NULL || tcl.OnInit()!=INIT_SUCCEEDED) {
      return INIT_FAILED;
   }
   // исполняем скрипт из ресурса
   if (tcl.Eval(Form_tcl)!=TCL_OK) {
      PrintFormat("error in script:%s",tcl.StringResult());
      return INIT_FAILED;
   }
   // задаём таймер
   EventSetMillisecondTimer(50);
   return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
   if (tcl!=NULL) {
      tcl.OnDeinit(reason);
      delete tcl;
   }
   EventKillTimer();
}
void OnTick()
{
   // пока ничего
}
void OnTimer()
{
   tcl.Update();  
 
   Tcl_Obj box=tcl.Get("BOX"); // получаем значение переменной
   if (box!=0) {
      tcl.Ref(box);   // будем работать с объектом tcl - увеличим ему число ссылок
      if (tcl.Count(box)>0) {
         // не пустое значение - пользвоатель нажал кнопку
         // код у нас первым в списке
         long code=tcl.Long(box,0);
         // вторым - значение из поля ввода
         string value=tcl.String(box,1);
         if (code==1) {
            // как сам-с-собой договорился код 1 - нажата кнопка Ok
            Alert("Текст в форме:"+value);
         }
         // и очистим переменную (зададим пустое значение)
         tcl.Eval("set BOX {}");
      }
      tcl.Unref(box);   // закончили работать с объектом - уменьшили число ссылок
   }
}
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   tcl.Update();
}

и результат:



форма стартует из советника, при нажатии кнопки советник получает данные и выкидывает Alert. Цель достигнута, сделан советник с  GUI .

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

(приведённые исходники, приложены)

ИТОГ

В течении буквально часа, сделали простой советник с графической формой ввода.

И самое главное, мы разделили труд - дизайном  GUI  можно и нужно заниматься отдельно. Даже другой человек. Без доступа к основному коду и без сведений об алгоритме советника и даже не владея MQL5. Tcl/Tk всё-же более известен в мире чем mql и тем более его самодельные gui библиотеки - вам проще найти соисполнителя

Установить библиотеку ATcl можно через инсталлятор или следуя инструкциям в репозитарии проекта

PS/ несколько часов назад веб-мастера mql начали блокировать переход на инсталлятор.

Скачать можно по резервному адресу https://www.filefactory.com/file/6zj49q87vhkk/atclsetup.exe

ещё https://dfiles.eu/files/9muo987ad 

или через эскизный сайт проекта http://atcl.unaux.com/download/

приношу свои извинения


Файлы:
form.zip  3 kb