Функция МЕНЮ(). Управление работой программ (+ вывод информации).

 

При работе программы (советника, индикатора, скрипта) часто возникает желание (необходимость) изменить какие-то параметры, управлять работой функций, запускать или отключать участки кода, выводить информацию о работе программы. Такое управление удобно осуществлять с помощью графических объектов на графике, и есть множество решений этого, например, от простого управления уровнями ордеров с помощью горизонтальных линий до целых программных комплексов.

Для себя я разработал достаточно универсальную функцию, с помощью которой можно легко создавать Меню с произвольным набором пунктов и встраивать его в любые программы. Меню выводится на график в виде Курсора (двойной стрелки), Заголовка и вертикального списка Пунктов меню; (а также - при желании - вертикального списка значений актуальных переменных программы).

Пункты меню - могут быть трех видов:
1. Run(Выполнить)(Кнопка без фиксации).
2. CheckBox(Включить/Отключить)(Кнопка с фиксацией).
3. RadioButton(Выбор одного из пунктов)(Переключатель).

Перечень возможных действий с Меню:
1. Выбор пункта меню - выделяем двойную стрелку (курсор Меню), перетаскиваем и бросаем её на нужный Пункт.
(1а.При этом произойдёт подтверждение выбора - выбранный пункт кратковременно изменит свой цвет).
2. Перемещение Меню - выделяем Заголовок меню и перетаскиваем его на требуемое место на графике.
(2а.Вслед за заголовком при его передвижении будет перемещаться всё Меню).
3. Свернуть/Развернуть Меню - выделяем двойную стрелку, перетаскиваем и бросаем её на Заголовок меню.
(3а.Таким образом можно скрыть все пункты Меню, сворачивая его до одного Заголовка).
4. Активность Меню - задается внутри функции, можно привязать к любому пункту, который отвечает за работу (активность) какой-либо функции или алгоритма.
(4а.Влияет на цвет Заголока (Активный или Неактивный). Наглядно отображает, работает или отключена эта функция/алгоритм, даже в случае свёрнутого Меню. Например, в демо-скрипте привязана к первому пункту Меню).
5. Восстановление исходного положения Меню (после перемещений) - выделяем двойную стрелку и удаляем её (кнопкой Delete или через контекстное меню).

Практически весь код, от инициализации пунктов Меню, логической обработки их, и до выдачи результата (номера выбранного пункта) помещён в одну функцию. Это очень упрощает встраивание Меню в любую программу. Остается лишь поместить функцию в программу, задать начальные параметры и список пунктов Меню. И затем в программе нужно просто опрашивать состояние пунктов Меню и управлять ее работой в зависимости от их состояния. Также легко можно встроить не одно, а несколько Меню, поместив нужное количество функций и настроив их; при желании можно создавать даже вложенные Меню. Для универсальности и корректной работы в индикаторах, все временные задержки формируются посредством GetTickCount(), а не Sleep().

В этом посте я выкладываю текущую версию функции Menu(v00) в составе демо-скрипта. Скрипт выводит на экран описание основных приёмов работы с Меню, с тем чтобы можно было освоить функцию, поработав с ней вживую. В следующих постах планирую написать инструкцию по встраиванию функции в программу, привести другие примеры использования функции, в том числе с выводом информации (значений переменных). По мере усовершенствования функции буду выкладывать новые версии. Например, можно сделать отсчет координат не от нулевого угла, а любого из четырех; можно добавить возможность ввода числовых значений; для индикаторов и скриптов можно подумать над возможностью выполнения всех действий функции за один тик...

П.С. Просьба писать лишь по существу, желательно конкретные вопросы и предложения. Ваши предложения и замечания постараюсь учитывать в новых версиях. Сорри за стиль кодирования, т.к. осваивал МТ4 и работаю сейчас на нетбуке с выводом 20 строк на экран, и привык уже к такому компактному стилю, мне так даже комфортнее.

Файлы:
 
 
n-i-k:

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

 

Есть еще вот такой вариант - перетаскиваем звездочки на нужную опцию и управляем ею.

 
Новое - это хорошо забытое старое https://www.mql5.com/ru/code/10344
 
khorosh:

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


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

Насчет отдельного окна и ДЛЛ. Думаю, новая версия функции во многом учитывает это пожелание, причем вполне обходится средствами МТ4. По аналогии с окнами, Меню теперь выводится на передний план на цветном фоне, закрывая под собой почти все другие объекты, может перемещаться по графику, может закрываться, точнее сворачиваться до Заголовка Меню. По умолчанию правильнее задавать такие настройки функции, чтобы Заголовок был прижат к верхнему (как вариант - к нижнему) краю графика, а Меню было свёрнуто - то есть максимально соответствовать привычному стандартному расположению меню (и даже в таком виде по цвету Заголовка мы будем знать, работает ли заданная функция (алгоритм или вся программа) или отключена). Если же Меню сворачивать нежелательно, то удобнее всего будет прижать его к левому краю графика.

 

Есть одна большая проблема в четверке (подходе к программированию) - все пытаются решить только свою проблему, и видят ситуацию со своей колокольни. Проблема в несовместимости подходов (кодов). будь в четверке модель ООП - таких бы проблем не было.

1) Вы уверены в том, что кто то другой сможет эфективно применить вашу разработку (хотя бы просто разобраться в коде) ?

2) Вы уверены в том, что ваша графика не будет мешать другой - даже вашей же, и ее не придется кардинально переделывать каждый раз ?

3) Вы уверены в том, что пользователь незнакомый с вашим меню сможет им пользоваться без предварительного обучения ?

4) Вы уверены в том, что это будет работать всегда и везде ?

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

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

 
khorosh:

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

Относительно ДЛЛ и винапи - проблема в том, что не все что исправно работает под ХР будет так же работать под 64битными системами. хотя для ХР уже все сделано разжеванно и выложено (некоторые вещи больше чем 2 года на форуме лежат)
 

В самом начале обещал написать инструкцию по подключению функции Меню. Тут обозначу основные моменты, чтобы было понятно, для чего и как её можно использовать. А пошаговые, конкретные, привязанные к данной, конкретной версии пояснения планирую сделать в ближайшем времени, в самОм тексте кода.

___ПОДКЛЮЧЕНИЕ ФУНКЦИИ МЕНЮ() В ПРОГРАММУ___
Функция Меню позволяет организовать удобное управление любой программой (советник, индикатор, скрипт), и использует три стандартных типа интерактивных управляющих элементов:
1. Run(Выполнить)(Кнопка без фиксации).
2. CheckBox(Включить/Отключить)(Кнопка с фиксацией).
3. RadioButton(Выбор одного из пунктов)(Переключатель).

Итак, сначала копируем функцию MenuAАА() в код нашей программы, работой которой нам нужно управлять. Затем начинаем настраивать функцию под свои требования. Те строки кода, которые требуют обязательной настройки, помечены в конце строки символами "<!!!>", а которые могут быть изменены при желании или необходимости - символами "(<!>)".

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

В теле самой функции прежде всего мы должны задать Заголовок и список Пунктов Меню, в виде строковых переменных, причем три первых символа строго и однозначно определяют тип пункта Меню:

1. " " (три пробела) - это Run(Выполнить)(Кнопка без фиксации).
2. "[ ]/[v]" - это CheckBox(Включить/Отключить)(Кнопка с фиксацией).
3. "( )/(о)" - это RadioButton(Выбор одного из пунктов)(Переключатель).

При этом 2й и 3й тип задают состояние этих пунктов (включен/отключен) по умолчанию.
В случае использования 3го типа, в разделе функции "ЛОГИКА ОБРАБОТКИ ПУНКТОВ МЕНЮ" мы также должны задать матрицу обработки пунктов этого типа.

___УПРАВЛЕНИЕ ПРОГРАММОЙ С ПОМОЩЬЮ ФУНКЦИИ МЕНЮ()___
Обращение к функции (её вызов) следует поместить один раз, где-нибудь в начале функции start(), до того, как мы будем обрабатывать результат ее работы. Далее, в любом месте нашей программы, в любой другой её функции, мы можем управлять работой программы, опрашивая значения переменных, формируемых функцией Меню:
a) Основной способ - использует массив флагов AAA[1]...AAA[N]; флаги отражают текущее состояние N пунктов Меню. Например, If(AAA[5])... сработает, если 5й пункт Меню был выбран/включен, If(!AAA[5])... - наоборот.
b) Вспомогательный способ - использует значение, возвращаемое функцией int Z=MenuAAA(); оно равно номеру выбранного пункта, его можно использовать как признак выбора одного (конкретного) или любого из пунктов, группы пунктов (например, группы пунктов RadioButton). А также для организации более сложной логики взаимодействия пунктов Меню между собой.
c) Вспомогательный способ - использует значение флага AAA[0]; этот флаг содержит признак работы пользователя с Меню. Флаг AAA[0] поднимается, если выполняются любые действия с Меню (выбор пункта, перемещение курсора Меню, сворачивание Меню).

В качестве примера прилагается простой демо-скрипт, включающий в себя и использующий функцию MenuAAA(). Скрипт поможет разобраться и понять принципы управления программами с помощью функции Меню. Вот вся функция start() в этом демо-скрипте - вызов функции Меню, опрос флагов AАА[N] - всё очень просто, если не сказать элементарно!

int start()
  {while (!IsStopped())
{//----

MenuAAA(); //<<<==============================ВЫЗОВ ФУНКЦИИ <MENU_AAA>

//_1.пункт Меню _                    //CheckBox// "Включить/Отключить"
if (AAA[1]) PrintManual();               //если [v] - вывести описание
if(!AAA[1]) DelObj(ObjAll+"Manual>");    //если [ ] - удалить описание

//_2.пункт Меню_                                  //Run//  "Выполнить"
if (AAA[2]) PlaySound("news.wav"); //>>>выполнить оператор PlaySound()

//_3/4/5.пункты Меню_   //RadioButton// "Bыбор одного из пунктов Меню"
//if(AAA[3])cMan=Pink;           B функции PrintManual()           ( )
//if(AAA[4])cMan=Lime;             выбор одного                    (о)
//if(AAA[5])cMan=Blue;             из трёх цветов                  ( )

//_6.пункт Меню_                                  //Run//  "Выполнить"
if (AAA[6]) break;                     // >>> удалить (закрыть) скрипт

Comment(AAA[0]+txCom); Sleep(200);
}//----
  return(0);  }

В данной версии в функцию добавлен код, который рисует фон под пунктами Меню, имитируя таким образом вывод Меню в отдельном окне. Отрисовка фона также поддерживает опцию Активность меню (подробнее см. первый пост) - так, если Меню не активно, тогда и Заголовок и фон Меню будет серого цвета; в демо-скрипте Активность Меню привязана к первому пункту Меню. Ещё в новой версии изменена идентификация (индексирование) имён функции и её переменных - не одной буквой (MenuA(), A[0]), а тремя (MenuAAA(), AAA[0]), для того чтобы можно было создавать клоны функции практически одним кликом (например, MenuВВВ(), ВВВ[0]) с помощью простой замены.

На следующем рисунке приведён пример использования в разрабатываемом советнике сразу четырёх Меню, каждое для своего алгоритма; на рисунке наглядно показаны различные состояния Меню, с привязкой Активности меню к первому пункту. Там же можно увидеть использование дополнительной сервисной функции MenuComment(), для вывода информации (актуальных параметров и переменных алгоритма) отдельно в каждом окошке Меню. При перемещении Заголовка вместе с ним будет перемещаться единым блоком и само Меню и выводимая информация (MenuComment).

Файлы: