Обсуждение статьи "Графические интерфейсы III: Простые и многофункциональные кнопки (Глава 1)"

 

Опубликована статья Графические интерфейсы III: Простые и многофункциональные кнопки (Глава 1):

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

На этот раз рассмотрим такой элемент управления,  как кнопка.

Кнопка — самый простой элемент управления в графическом интерфейсе, с которым может взаимодействовать пользователь. Однако здесь можно предложить несколько различных вариантов реализации. В этой статье создадим три класса для создания кнопок разной сложности (см. перечисление ниже).

  • Обычная кнопка (simple button). Класс CSimpleButton.
  • Кнопка с картинкой (icon button). Класс CIconButton.
  • Сдвоенная кнопка с несколькими функциями (split button). Класс CSplitButton.

Кроме этого, реализуем ещё три класса, с помощью которых можно будет создавать группы взаимосвязанных между собой кнопок:

  • Группа из простых кнопок. Класс CButtonsGroup.
  • Группа из кнопок с картинками. Класс CIconButtonsGroup.
  • Группа радио-кнопок. Класс CRadioButtons.

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


После компиляции файлов и загрузки тестового эксперта на график вы увидите результат, как показано на скриншоте ниже:

Рис. 4. Тест элемента управления «Кнопка с картинкой».

Автор: Anatoli Kazharski

 
Исходя из личного опыта, могу сказать, что сделать окна "резиновыми" (то есть динамичными), совсем не простая задача. Если говорить о простой форме окна, лишенной каких либо объектов, то сделать ее растягиваемой определенно проще, но и здесь требуется целая концепция взаимодействия пользователя и окна. Стандартное виндоус окно имеет как минимум 8 ручек, ухват за которые позволяет удобно менять размеры окна в любую сторону. Возьмите к примеру окно "Alert". Реализовать подобное поведение окна совсем не просто. Теперь вернемся к обычному окну, содержащему большое количество различного рода объектов. Вы понимаете, что объекты находятся с друг другом в различного рода взаимосвязях. Это означает, что при изменении размеров окна их местоположение (или размеры) меняются по разному. Одни картинки например, перемещаются за ручкой, другие напротив остаются на месте. Некоторые поля ввода меняют свою длину,  другие наоборот сохраняют прежний размер. Поэтому говорить о том, что эта задача одна из самых простых в решении, считаю несколько опрометчиво.)
 
Реter Konow:
Исходя из личного опыта, могу сказать, что сделать окна "резиновыми" (то есть динамичными), совсем не простая задача. Если говорить о простой форме окна, лишенной каких либо объектов, то сделать ее растягиваемой определенно проще, но и здесь требуется целая концепция взаимодействия пользователя и окна. Стандартное виндоус окно имеет как минимум 8 ручек, ухват за которые позволяет удобно менять размеры окна в любую сторону. 

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

Возьмите к примеру окно "Alert". Реализовать подобное поведение окна совсем не просто.

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

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

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

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

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

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




Выскажу свое мнение:
 
 1. В интерфейсе стандартизированы формы окон, объектов, а также их поведение на различных событиях (реакции на действия пользователя).
    Существует стандартный метод связи графического объекта с своим параметром и с функцией, одна четкая классификация окон, объектов и событий. Данная          
    стандартизация совершенно отсутствует среди панелей.




 2. Интерфейс обладает неизмеримо большим набором возможностей взаимодействия пользователя с приложением. Он позволяет пользователю легко менять свой внешний вид,
    принимая требуемые от него размеры или цвет. Так сказать "приспосабливается" под требования пользователя.




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




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




Буду рад услышать возражения. :)
 

Реter Konow: 

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

2. Это даст Вам очень большие возможности, но еще раз повторяю, ООП не позволит Вам возможности эффективно это реализовать.

3. Придется написать слишком много кода.

4. Готов поспорить, что при сравнении моих результатов с Вашими, преимущество будет не на Вашей стороне.) 

1. Не понимаю, о какой Вашей реализации идёт речь? У Вас уже есть и будет ещё больше возможностей, по мере публикации остальных статей серии, произвести полноценное сравнение с Вашими разработками. А с чем мне сравнивать? ))

2. ООП как раз и даёт возможность всем этим эффективно управлять. Либо выразите свою мысль более подробно, почему Вы так думаете. Желательно, на каких-то конкретных примерах с кратким кодом, который показывает ту или иную проблему.

3. Меня не пугает сложность той или иной задачи и неважно, сколько для этого нужно написать кода. 

4. Не понимаю, о каком преимуществе Вы говорите? У меня не было в планах получить, какое либо преимущество перед Вами. ))

Реter Konow: 

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

Выскажу свое мнение:

... 

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

Что касается первого и второго шага, то подождите пока не будут опубликованы все статьи серии. На текущий момент опубликовано только 10 статей. Всего их будет >25.

Реter Konow:

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

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

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

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

 Однако, некоторые объекты могут быть привязаны сразу к нескольким другим объектам и ко всем по разному. Например, вы устали вычислять и прописывать координаты для каждого объекта отдельно. Вы хотите просто привязать его к другому, уже установленному объекту, сверху, снизу, слева или права. Вы создаете привязку одного объекта к другому, и если двигается первый объект, то второй будет двигаться за ним.

К сожалению куски кода показывать бессмысленно, так как комментарии к ним превысят размер этого кода в несколько раз. Просто Вы не знакомы с моим методом программирования и мой код Вам ничего не объяснит, а скорее наоборот приведет в тупик. 

Могу только сказать что все о чем я пишу у меня реализовано и прекрасно работает. Скоро выложу еще скриншоты и видео.
По поводу преимущества, то это просто в шутку. :D
 
Реter Konow:

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


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


Однако, некоторые объекты могут быть привязаны сразу к нескольким другим объектам и ко всем по разному. Например, вы устали вычислять и прописывать координаты для каждого объекта отдельно. Вы хотите просто привязать его к другому, уже установленному объекту, сверху, снизу, слева или права. Вы создаете привязку одного объекта к другому, и если двигается первый объект, то второй будет двигаться за ним.


Всё перечисленное достаточно простые задачи. Не вижу никаких проблем с этим. То есть можно будет добавить такие возможности на любой стадии развития проекта.

Реter Konow:

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

То есть примеров, объясняющих, почему ООП ограничивает Ваши возможности в программировании, не будет? Можно просто схему нарисовать, что невозможно для реализации подобного проекта используя ООП, но возможно используя Ваши методы. Этого будет достаточно.

И что нам делать с Вашими скриншотами и видео ? Возможности MQL позволяют реализовать графические интерфейсы любой сложности. Для примеров, каким может быть графический интерфейс, лучше тогда уж ориентироваться на графические интерфейсы операционных систем. То есть на то, что сделано достаточно качественно (ошибки и недочёты бывают и в Windows) и можно протестировать самому, а не просто увидеть на видео. 

Если же у Вас в планах было продавать свою библиотеку, то тогда выкладывайте в маркете хотя бы свои бесплатные DEMO-примеры, чтобы мы могли их протестировать и сделать выводы. А ещё напишите статью, в которой можно будет понять, как использовать Вашу библиотеку для создания графических интерфейсов в своих MQL-приложениях. Просто скриншотов и видео далеко недостаточно для оценки. ;)

 
Анатолий, Вы разработчик. Я тоже разработчик. Мы оба занимаемся разработкой интерфейса для программ на платформах MT4/MT5. Этот спор, по поводу подхода в программировании может вестись между людьми находящимися "глубоко" в теме. Мне не удастся объяснить людям не занимавшимся самостоятельной разработкой интерфейса, все нюансы и проблемы, или преимущества того или иного подхода.

 Я не отрицаю, что используя ООП Вы можете решить поставленные выше задачи, но это решение окажется слишком громоздким. Если Вы не согласны и продолжаете утверждать, что не видите с этим проблем и это все достаточно простые задачи, предлагаю Вам доказать это на практике.
 
Мои скриншоты и видео, просто доказательство моих слов о решении вышеупомянутой задачи. Предоставить их я собирался именно Вам.

Насчет схемы или иных доказательств эффективности, я отвечу просто, - вся моя программа с интерфейсом весит 250 килобайт, не включая ядра. Ядро не является программным кодом и загружается в программу на этапе инициализации. Этот факт и плюс видео демонстрирующее возможности моего интерфейса и будет доказательством эффективности моего подхода.

От Вас жду доказательств эффективности Вашего подхода тем же способом. Если конечно Вы в нем уверены.))

P.S. Не преследую иных целей, кроме установления истины.
 
Заметка:  Маленький размер программы я рассматриваю как преимущество.
 
Реter Konow:
...

P.S. Не преследую иных целей, кроме установления истины.

Истина заключается на текущий момент в том, что публикуются мои (а не Ваши) статьи с подробным описанием библиотеки, которая по сути предоставляется всему MQL-сообществу на безвозмездной основе. В отличие от Вас, это и есть доказательства на практике.

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

Впереди ещё, как минимум, 15 статей. Так что Вы слишком рано начали сравнивать.

Реter Konow:
Заметка:  Маленький размер программы я рассматриваю как преимущество.

Не смешно. Наверное и возможностей столько же, сколько и кода. Можно ещё удалить все комментарии или даже обфускацию сделать, будет ещё меньше.

 
Anatoli Kazharski:

Истина заключается на текущий момент в том, что публикуются мои (а не Ваши) статьи с подробным описанием библиотеки, которая по сути предоставляется всему MQL-сообществу на безвозмездной основе. В отличие от Вас, это и есть доказательства на практике.

Так не хотелось ничего писать, ... но

  • Анатолий, там про "истину" и "доказательства" как-то не очень скромно.
  • Помните диалог: "... как трудно читать ваши статьи..." ответ автора: "а вы знаете как трудно их писать?". Анатолий, спасибо конечно за труд, но у меня возникает вопрос: а для кого Вы публикуете "на безвозмездной основе" статьи? Для продвинутых не интересно, а для начинающих непонятно. Очень много кода, в котором ковыряться и систематизировать изложенное совершенно не хочется.
  • Анатолий, Ваш читатель задаёт вопросы по Вашей статье, и судя по всему Вас это не устраивает. И более того, его мнение Вас вообще не интересует и даже раздражает. Тогда что Вас заставляет писать статьи?
  • Критика авторам нужна для того, чтобы меняться в лучшую сторону.

При всём уважении к Вам, будьте ближе к своим читателям и не заводитесь с пол оборота на ровном месте.

Причина обращения: