Или независимые управляемые формы графического интерфейса.

Однажды я заинтересовался вопросом о том, каким образом можно было бы создавать пользовательский интерфейс программ и познакомился с Qt Designer — утилиты для разработки графических интерфейсов, которая входит в стандартный состав Qt.
Кроме всего прочего Qt Designer впечатлил своей способностью сохранять все формы в файлах формате XML, которые могут уже в последствие подключаться непосредственно в программу.
Мне это показалось очень удобным, так как я бы мог рисовать формочки с кнопочками не отходя от текстового редактора.
И тут мысль было уже не остановить: если весь интерфейс описан в стороннем файле, то программный код может вообще не содержать элементы работы непосредственно с формами, а только использовать какой-то программный интерфейс намертво изолирующий бизнес логику и представление.
Если так, то такая программа с пользовательским интерфейсом может быть написана не только на С++, о, священный GNU, она может быть вообще может без языка программирования.
Пока не отпустило, надо было срочно выдумывать как такое можно провернуть.
И так появился на свет концепт OpenForm — создание и управление формами с помощью командной строки.
Где основная идея базируется на том, что любое состояние интерфейса можно представить в формате XML.
Значит если я хочу отрисовать форму, мне нужно всего лишь какая-то утилита, которая возьмет на себя непосредственно задачу отображения форм, а вся логика будет на стороне.
Другими словами, требуется такой мини Qt Designer, который прочитает описание форм и виджетов, и это дело уже отобразит. А чтобы поменять состояние интерфейса, нужно просто как-то передать программе новое описание, например, в виде XML.
Вот и получается, что OpenForm сперва читает файл описания форм, отрисовывает их, и вешает на заданные события определенные триггеры, т. е. действия.
Если событие случается, например кто-то куда-то кликнул, то выполняется какое-то действие. А действие — это ничто иное как исполнение какой-то внешней программы, которая должна возвратить новое состояние пользовательского интерфейса.
А теперь по пунктам.
1. Qt Designer сохраняет дизайн в виде *.ui файлов формата XML.
2. OpenForm читает эти файлы и отображает.
3. На определенные события вешаются триггеры.
4. Если событие произошло, то выполняется сторонняя команда или программа, которая должна вернуть новое состояние интерфейса, т. е. вывести XML новой версии диза��на на стандартное устройство вывода.
OpenForm работает с *.ui файлами, которые создаются в среде Qt Designer.
И кроме дефолтных способностей просто отобразить форму, обладает еще и дополнительными плюшки.
Для тех, кто фигачит, комментарии штука очень нужная, если не сказать необходимая.
Полный набор для тех, кого не отпускает: знакомая директива для препроцессора #include.
Теперь можно интерфейс разделять на модули.
По традиции, если *.ui исполняемые файлы, то заголовочные должны быть как *.hui
file: geometry.hui:
file: widget.ui:
Самое важное, ради чего мы тут все собрались: возможность контролировать состояние пользовательского интерфейса с помощью сторонней программы через командную строку.
Это означает, что если пользователь нажмет на кнопку с именем btnSubmit, выполнится команда
cat update_widget.uui, выводящая содержимое файла с новым состоянием интерфейса.
action=return необходим, когда требуется спросить что-то у пользователя или узнать состояние интерфейса из внешней программы, которая вызывает OpenForm (смотри пример с диалоговым окном).
OpenForm обладает еще одним необычайной возможностью получения значения свойств виджетов. Т.е. если надо узнать, что там пользователь напечатал в поле ввода, то можно пользоваться конструкцией {WIDGET_NAME.PROPERTY_NAME}
Например
Где {lineEdit.text} — это означает, что из виджета lineEdit возвратить значение свойства с именем text. Если пользователь что-то введет, то это можно передать стороннему скрипту.
То же самое работает и для булевых свойств.
Возвратит true или false.
Если надо использовать { в командах, то можно просто написать так \{
Если триггер возвратит дизайн в виде
то форма заново перерисуется.
Но в случаях, когда не требуется заново пересоздавать форму, а нужно просто обновить состояние одного элемента, можно использовать :
Вот и подошли к вопросу, каким же таким способом можно управлять графическим интерфейсом с помощью утилиты echo.
Часто не хочется создавать новые файлы дизайна на каждое событие, поэтому можно сразу в триггерах указывать, что надо поменять и как.
По событию нажатия, выполнится команда echo, где [[ заменится на <, а ]] — на >. Результатом будет копирование текста из поля ввода lineEdit в объект label.
Ну, например, помощник при установки программного обеспечения:

Рис 1. Шаг лицензионного соглашения.

Рис 2. Пример анимации, прогресс бара.
Можно даже просто о чем-то спрашивать грозного пользователя с помощью графических форм.

Рис 3. Диалоговое окно с ожиданием действия от пользователя.
Работает следующим образом:
Ну или… а может, написать графический калькулятор на баше.

Рис 4. Графический калькулятор с обработкой выражений на баше.
Или даже так:

Рис 5. Графический калькулятор на PHP.

Предыстория
Однажды я заинтересовался вопросом о том, каким образом можно было бы создавать пользовательский интерфейс программ и познакомился с Qt Designer — утилиты для разработки графических интерфейсов, которая входит в стандартный состав Qt.
Кроме всего прочего Qt Designer впечатлил своей способностью сохранять все формы в файлах формате XML, которые могут уже в последствие подключаться непосредственно в программу.
Мне это показалось очень удобным, так как я бы мог рисовать формочки с кнопочками не отходя от текстового редактора.
И тут мысль было уже не остановить: если весь интерфейс описан в стороннем файле, то программный код может вообще не содержать элементы работы непосредственно с формами, а только использовать какой-то программный интерфейс намертво изолирующий бизнес логику и представление.
Если так, то такая программа с пользовательским интерфейсом может быть написана не только на С++, о, священный GNU, она может быть вообще может без языка программирования.
Пока не отпустило, надо было срочно выдумывать как такое можно провернуть.
OpenForm
И так появился на свет концепт OpenForm — создание и управление формами с помощью командной строки.
Где основная идея базируется на том, что любое состояние интерфейса можно представить в формате XML.
Значит если я хочу отрисовать форму, мне нужно всего лишь какая-то утилита, которая возьмет на себя непосредственно задачу отображения форм, а вся логика будет на стороне.
Другими словами, требуется такой мини Qt Designer, который прочитает описание форм и виджетов, и это дело уже отобразит. А чтобы поменять состояние интерфейса, нужно просто как-то передать программе новое описание, например, в виде XML.
Вот и получается, что OpenForm сперва читает файл описания форм, отрисовывает их, и вешает на заданные события определенные триггеры, т. е. действия.
Если событие случается, например кто-то куда-то кликнул, то выполняется какое-то действие. А действие — это ничто иное как исполнение какой-то внешней программы, которая должна возвратить новое состояние пользовательского интерфейса.
А теперь по пунктам.
1. Qt Designer сохраняет дизайн в виде *.ui файлов формата XML.
2. OpenForm читает эти файлы и отображает.
3. На определенные события вешаются триггеры.
4. Если событие произошло, то выполняется сторонняя команда или программа, которая должна вернуть новое состояние интерфейса, т. е. вывести XML новой версии диза��на на стандартное устройство вывода.
Мануал
OpenForm работает с *.ui файлами, которые создаются в среде Qt Designer.
<ui version="4.0" >
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="windowTitle">
<string>MainWindow</string>
</property>
</widget>
</ui>
И кроме дефолтных способностей просто отобразить форму, обладает еще и дополнительными плюшки.
Решетки комментируют
Для тех, кто фигачит, комментарии штука очень нужная, если не сказать необходимая.
<ui version="4.0" >
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
# This is a comment
<property name="windowTitle">
<string>MainWindow</string> # title of window
# <string>MainWindow changed</string> # unneeded title
</property>
</widget>
</ui>
Разделяй и подключай
Полный набор для тех, кого не отпускает: знакомая директива для препроцессора #include.
Теперь можно интерфейс разделять на модули.
По традиции, если *.ui исполняемые файлы, то заголовочные должны быть как *.hui
file: geometry.hui:
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
file: widget.ui:
<ui version="4.0" >
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="windowTitle">
<string>MainWindow</string>
</property>
#include "geometry.hui"
</widget>
</ui>
События, сигналы и триггера
Самое важное, ради чего мы тут все собрались: возможность контролировать состояние пользовательского интерфейса с помощью сторонней программы через командную строку.
<triggers>
<trigger object="btnSubmit">
<event signal="clicked">cat update_widget.uui</event>
</trigger>
</triggers>
Это означает, что если пользователь нажмет на кнопку с именем btnSubmit, выполнится команда
cat update_widget.uui, выводящая содержимое файла с новым состоянием интерфейса.
<triggers>
# Триггер для объекта с именем OBJECT_NAME
<trigger object="OBJECT_NAME">
# Список событий над текущим объектом.
# signal: стандартный Qt сигнал
# action: тип триггера
# "execute" - COMMAND должна быть выполнена, и возвратить новое состояние интерфейса в XML
# "return" - COMMAND должна быть выведена на стандартное устройство вывода
<event signal="SIGNAL" action="execute|return">COMMAND</event>
</trigger>
</triggers>
action=return необходим, когда требуется спросить что-то у пользователя или узнать состояние интерфейса из внешней программы, которая вызывает OpenForm (смотри пример с диалоговым окном).
Доставай и обрабатывай
OpenForm обладает еще одним необычайной возможностью получения значения свойств виджетов. Т.е. если надо узнать, что там пользователь напечатал в поле ввода, то можно пользоваться конструкцией {WIDGET_NAME.PROPERTY_NAME}
Например
<event signal="clicked">php script.php —user-input={lineEdit.text}</event>
Где {lineEdit.text} — это означает, что из виджета lineEdit возвратить значение свойства с именем text. Если пользователь что-то введет, то это можно передать стороннему скрипту.
То же самое работает и для булевых свойств.
<event signal="clicked">php script.php --checked={checkBox.checked}</event>
Возвратит true или false.
Экранирование
Если надо использовать { в командах, то можно просто написать так \{
Точечное обновление
Если триггер возвратит дизайн в виде
<ui version="4.0">
...
</ui>
то форма заново перерисуется.
Но в случаях, когда не требуется заново пересоздавать форму, а нужно просто обновить состояние одного элемента, можно использовать :
<update>
...
</update>
И, наконец, управление графическим интерфейсом с помощью echo
Вот и подошли к вопросу, каким же таким способом можно управлять графическим интерфейсом с помощью утилиты echo.
Часто не хочется создавать новые файлы дизайна на каждое событие, поэтому можно сразу в триггерах указывать, что надо поменять и как.
<event signal="clicked">echo "[[update]]
[[widget name='label']]
[[property name='text']]
[[string]]{lineEdit.text}[[/string]]
[[/property]]
[[/widget]]
[[/update]]"
</event>
По событию нажатия, выполнится команда echo, где [[ заменится на <, а ]] — на >. Результатом будет копирование текста из поля ввода lineEdit в объект label.
Ну и зачем все это надо?
Ну, например, помощник при установки программного обеспечения:

Рис 1. Шаг лицензионного соглашения.

Рис 2. Пример анимации, прогресс бара.
Можно даже просто о чем-то спрашивать грозного пользователя с помощью графических форм.

Рис 3. Диалоговое окно с ожиданием действия от пользователя.
Работает следующим образом:
#!/bin/bash
an=`./dialog.ui`
if [ $an = 'yes' ]; then
echo 'There should be real installation of something very cool'
else
echo 'Ok, we will do nothing...'
fi
Ну или… а может, написать графический калькулятор на баше.

Рис 4. Графический калькулятор с обработкой выражений на баше.
Или даже так:

Рис 5. Графический калькулятор на PHP.
