Разработка простых интерфейсов с помощью dialog/Xdialog


dialog это утилита для построения консольных интерфейсов. Xdialog аналогичная программа для X. Обе программы более-менее совместимы и легко интегрируются в скрипты. Dialog входит в состав большинства дистрибутивов GNU/Linux. Если вы хотите собрать её из исходников, то архив можно найти тут. Программа Xdialog доступна на сайте.

Эти программы являются свободными и работают на большом количестве платформ *nix. Большинство приведённых примеров в данном руководстве являются адаптацией примеров, поставляемых с исходными кодами программ.

Вот первый скрипт, работу которого я проверил. Он просто выводит диалог с кнопками «Да» и «Нет».

01.#!/bin/bash
02.DIALOG=${DIALOG=dialog}
03. 
04.$DIALOG --title " Мой первый диалог" --clear \
05.--yesno "Привет! Перед вами пример программы,\nиспользующей (X)dialog" 10 40
06. 
07.case $? in
08.0)
09.echo "Выбрано 'Да'.";;
10.1)
11.echo "Выбрано 'Нет'.";;
12.255)
13.echo "Нажата клавиша ESC.";;
14.esac

Скопируйте приведённые строки в файл, например, yesno.sh и установите атрибут выполнения.

1.chmod +x ./yesno.sh

Теперь попробуйте запустить его

1../yesno.sh

Изменим строку

1.DIALOG=${DIALOG=dialog}

на

1.DIALOG=${DIALOG=Xdialog}

и запустим скрипт из xterm

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

1.DIALOG=${DIALOG=dialog}

Эта строка присваивает переменной DIALOG значение ‘dialog’. Сам же диалог формируется следующей строкой:

1.$DIALOG --title " Мой первый диалог" --clear \
2.--yesno "Привет! Перед вами пример программы,\nиспользующей (X)dialog" 10 40

Применяемые опции:
—title задаёт заголовок диалога
—clear очищает экран перед отображением диалога
—yesno задаёт тип диалога и текст для отображения.

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

Теперь программа ждёт пользовательского выбора. В зависимости от того, нажмёте кнопку «Да» или «Нет», или нажмёте клавишу Escape, переменная командного интерпретатора $? будет содержать код завершения программы, который можно так или иначе обработать.

Следующая программа ожидает ввода строку и затем отображает её на экране.

01.#!/bin/sh
02.DIALOG=${DIALOG=dialog}
03.tempfile=`tempfile 2>/dev/null` || tempfile=/tmp/test$$
04.trap "rm -f $tempfile" 0 1 2 5 15
05. 
06.$DIALOG --title "Ввод данных" --clear \
07.--inputbox "Привет! Перед вами пример ввода даных\nВведите своё имя:" 16 51 2> $tempfile
08. 
09.retval=$?
10. 
11.case $retval in
12.0)
13.echo "Вы ввели `cat $tempfile`"
14.;;
15.1)
16.echo "Отказ от ввода.";;
17.255)
18.if test -s $tempfile ; then
19.cat $tempfile
20.else
21.echo "Нажата клавиша ESC."
22.fi
23.;;
24.esac

Запустите программу в консоли и под X (после замены dialog на Xdialog)

Эта программа немного сложнее, чем предыдущая. Следующие строки определяют временный файл и его удаление при завершении программы:

1.tempfile=`mktemp 2>/dev/null` || tempfile=/tmp/test$$
2.trap "rm -f $tempfile" 0 1 2 5 15

В первой строке делается попытка создать временный файл с помощью утилиты mktemp. Если это не получается, он создается вручную, в каталоге /tmp. Вторая строка определяет обработчик сигналов. При завершении скрипта (вне зависимости, корректном или не корректном) обработчик удаляет временный файл. Числа — это номера обрабатываемых сигналов.

После этого вызывается программа dialog:

1.$DIALOG --title "Ввод данных" --clear \
2.--inputbox "Привет! Перед вами пример ввода даных\nВведите своё имя:" 16 51 2> $tempfile

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

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

01.#!/bin/sh
02.DIALOG=${DIALOG=dialog}
03.tempfile=`mktemp 2>/dev/null` || tempfile=/tmp/test$$
04.trap "rm -f $tempfile" 0 1 2 5 15
05. 
06.$DIALOG --clear --title "Мои любимые исполнители" \
07.--menu "Все любят песни хинди, поэтому выбирайте:" 20 51 4 \
08."Rafi"  "Mohammed Rafi" \
09."Mukesh" "Mukesh" \
10."Kishore" "Kishore Kumar" \
11."Saigal" "K L Saigal" \
12."Lata"  "Lata Mangeshkar" \
13."Yesudas"  "K J Yesudas" 2> $tempfile
14. 
15.retval=$?
16. 
17.choice=`cat $tempfile`
18. 
19.case $retval in
20.0)
21.echo "Да вы эстет! '$choice' -- это лучшее, что вы слышали в своей жизни!";;
22.1)
23.echo "Отказ от ввода.";;
24.255)
25.echo "Нажата клавиша ESC.";;
26.esac

Логика работы скрипта аналогична той, что реализована в скрипте inputbox.sh — результат выполнения скрипта перенаправляется во временный файл, откуда он может быть взят для дальнейшей обработки.

Формирование таких списков аналогично организации меню, описанного в предыдущем разделе.

01.#! /bin/sh
02.DIALOG=${DIALOG=dialog}
03.tempfile=`mktemp 2>/dev/null` || tempfile=/tmp/test$$
04.trap "rm -f $tempfile" 0 1 2 5 15
05. 
06.$DIALOG --backtitle "Не стесняйтесь, выберите любимого певца" \
07.--title "Выбор исполнителя" --clear \
08.--radiolist "Мой любимый певец, это... " 20 61 5 \
09."Rafi"  "Mohammed Rafi" off \
10."Lata"    "Lata Mangeshkar" ON \
11."Hemant" "Hemant Kumar" off \
12."Dey"    "MannaDey" off \
13."Kishore"    "Kishore Kumar" off \
14."Yesudas"   "K. J. Yesudas" off  2> $tempfile
15. 
16.retval=$?
17. 
18.choice=`cat $tempfile`
19.case $retval in
20.0)
21.echo "Ого! Кто бы мог подумать, но выбор пал на '$choice'";;
22.1)
23.echo "Отказ от ввода.";;
24.255)
25.echo "Нажата клавиша ESC.";;
26.esac


Для того, чтобы использовать список флажков, вместо радиокнопок, замените в скрипте опцию —radiolist на —checklist.

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

01.#!/bin/sh
02.DIALOG=${DIALOG=dialog}
03. 
04.COUNT=10
05.(
06.while test $COUNT != 110
07.do
08.echo $COUNT
09.echo "XXX"
10.echo "Новое сообщение ($COUNT процентов)"
11.echo "Строка 2"
12.echo "XXX"
13.COUNT=`expr $COUNT + 10`
14.sleep 1
15.done
16.) |
17.$DIALOG --title "Индикатор" --gauge "А вот пример простейшего индикатора" 20 70 0

Особенность реализации индикатора заключается в том, что программа dialog получает данные через конвейер от кода, который заключён внутри круглых скобок. Есть два момента, на которые необходимо обратить внимание. Первый — это обязательное использование переменной $COUNT. Именно из неё dialog/Xdialog считывает текущее значение индикатора. При этом желательно, чтобы значение переменной колебалось в диапазоне от 0 до 100. Второй — это использование строк вида «XXX» в качестве ограничителей сообщения, выводящегося на экран.

Вот пример простейшего диалога для выбора файла:

01.#!/bin/sh
02.DIALOG=${DIALOG=dialog}
03. 
04.FILE=`$DIALOG --stdout --title "Выберите файл" --fselect $HOME/ 10 60`
05. 
06.case $? in
07.0)
08.echo "Выбран \"$FILE\"";;
09.1)
10.echo "Отказ от ввода.";;
11.255)
12.echo "Нажата клавиша ESC.";;
13.esac

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

Диалоговое окно для выбора файла состоит из панелей. Вы можете перемещаться между ними при помощи клавиши «Tab». Кроме этого, у вас есть возможность вводить данные непосредственно в строке ввода, расположенной под панелями.

Календарь

Информация о годе, месяце и дне выводится на отдельных панелях. Если значение дня,месяца или года не указано, либо оно отрицательное, то используются системная дата. (Работает только в dialog. При частичном отсутствии начальных значений даты. Для изменения значений можно использовать стрелки управления курсором, либо воспользоваться горячими клавишами, используемыми в vi при навигации по тексту: h, j, k и l. Если год устанавливается равным 0, то по умолчанию используется значение текущего года. Результат выводится в формате день/месяц/год (см. рисунок 14, 15).

01.#!/bin/sh
02.DIALOG=${DIALOG=dialog}
03. 
04.USERDATE=`$DIALOG --stdout --title "Календарь" --calendar "Выберите дату..." 0 0 7 7 1981`
05. 
06.case $? in
07.0)
08.echo "Выбрано: $USERDATE.";;
09.1)
10.echo "Отказ от ввода.";;
11.255)
12.echo "Нажата клавиша ESC.";;
13.esac

Настройка часов

Этот диалог позволяет вам выбирать время.

01.#!/bin/sh
02. 
03.DIALOG=${DIALOG=Xdialog}
04.USERTIME=`$DIALOG --stdout --title "Настройка часов" --timebox "Укажите,пожалуйста, время..." 0 0 12 34 56`
05. 
06.case $? in
07.0)
08.echo "Указано время: $USERTIME.";;
09.1)
10.echo "Отказ от ввода.";;
11.255)
12.echo "Нажата клавиша ESC.";;
13.esac