Zenity - графический интерфейс для командной строки

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

Алексей Снастин, независимый разработчик ПО, начальник отдела

Алексей Снастин - независимый разработчик ПО, консультант и переводчик с английского языка технической и учебной литературы по ИТ. Принимал участие в разработке сетевых офисных приложений типа клиент/сервер на языке С в среде Linux.



30.08.2011

Введение

Многие пользователи Linux уже настолько привыкли к "интуитивному графическому интерфейсу", что предложение ввести какую-либо команду в консоли кажется им неуместным. Возможно, утилита zenity, рассматриваемая в этой статье, позволит подобным пользователям комфортно работать с "такими неудобными, громоздкими и длинными" текстовыми командами оболочки shell.

Обзор zenity

Утилита zenity – это средство создания диалоговых окон в режиме командной строки. Следует отметить, что на самом деле диалоговые окна создаются средствами Gtk+, поэтому в системе должны быть установлены соответствующие библиотеки. От аналогичных программ, таких как dialog и whiptail, zenity отличают более изощрённые средства реализации GUI-элементов.

Загрузить актуальную версию этой утилиты можно на Web-сайте разработчиков [http://library.gnome.org/users/zenity/]. Также эту программу можно найти в репозиториях некоторых дистрибутивов Linux.

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

Необходимо уточнить, что после закрытия диалогового окна, zenity возвращает числовой код завершения операции:

  • 0 - означает, что пользователь нажал в диалоговом окне кнопку "OK" или "Закрыть" (Сlose);
  • 1 - означает, что пользователь нажал кнопку "Отмена" (Cancel) или воспользовался функциями (кнопками) окна, чтобы закрыть его;
  • -1 - сообщает о том, что операция завершилась с ошибкой;
  • 5 - диалоговое окно было закрыто после истечения интервала таймаута.

Создание диалогового окна для вывода сообщений

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

В zenity определены четыре типа диалоговых окон для вывода сообщений:

  • ошибка (ключ --error);
  • информация (ключ --info);
  • вопрос (ключ --question);
  • предупреждение (ключ --warning).

Простое сообщение, изображенное на рисунке 1, определяется следующей командой:

zenity --info --title="Сообщение от Gmail" \
              --text="На Gmail получены новые почтовые сообщения"
Рисунок 1. Простое информационное сообщение
Рисунок 1. Простое информационное сообщение

Если требуется вывести текст сообщения в одну строку и без переносов, чтобы привлечь внимание к сообщению об ошибке, то можно воспользоваться ключом --no-wrap, как показано ниже:

zenity --error \
       --text="На сменном носителе не хватает места \
               для резервного копирования файлов" \
       --no-wrap
Рисунок 2. Сообщение об ошибке, выведенное без переносов строки
Рисунок 2. Сообщение об ошибке, выведенное без переносов строки

Создание диалогового окна для выбора варианта ответа

Создание диалогового окна, в котором от пользователя требуется ответить на предложенный вопрос ("OK" или "Отмена"), лучше продемонстрировать на небольшом примере, приведённом в листинге 1.

Листинг 1. Пример использования диалогового окна для выбора варианта ответа
#!/bin/sh
if [ -z "$*" ]
then
  zenity --error --text="Не задан список удаляемых файлов"
else
 zenity --question --title="Внимание: операция удаления" \
        --text="Вы действительно хотите удалить перечисленные файлы?" \
        --timeout=7
 if [ $? -eq "0" ]
 then
   rm $*
   zenity --info --title="Операция выполнена" \
          --text="Перечисленные файлы удалены"
 else
   zenity --warning --title="Операция отменена" \
          --text="Перечисленные файлы не были удалены"
 fi
fi

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

Рисунок 3. Диалоговое окно для выбора варианта ответа
Рисунок 3. Диалоговое окно для выбора варианта ответа

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

Приведённый в листинге 1 сценарий намеренно упрощён: в нём отсутствует проверка существования удаляемых файлов и не учитывается тот факт, что имена задаваемых файлов могут содержать пробелы. Основной целью данного сценария была демонстрация возможностей диалоговых окон, создаваемых с помощью zenity.


Создание диалогового окна для выбора файла

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

Листинг 2. Создание диалогового окна для выбора файла
#!/bin/sh
filename=`zenity --file-selection --title="Выбор файла для редактирования"`
case $? in
0)  vim "$filename" ;;
*)  zenity --info --text="Не выбрано имя файла" ;;
esac

Пользователь сможет выбрать файл для редактирования буквально парой щелчков кнопкой мыши:

Рисунок 4. Диалоговое окно для выбора файла
Рисунок 4. Диалоговое окно для выбора файла

Кроме того, можно сразу выделить предлагаемое имя файла с помощью ключа --filename=имя_файла, разрешить выбирать не один файл, а несколько (ключ --multiple), а также ограничить выбор пользователя только именами каталогов (ключ --directory). Есть ещё два специализированных ключа: ключ --save переводит диалоговое окно в режим сохранения заданного файла, а ключ --separator=разделитель позволяет определить строку символов, которая будет отделять имена файлов друг от друга в списке, возвращаемом из режима выбора нескольких файлов.


Создание шкалы значений с "бегунком"

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

zenity --scale --title="Уровень цвета СИНИЙ" \
       --text="Установите требуемый уровень синего цвета" \
       --min-value=0 --max-value=255 --value=100 --step=5

В результате выполнения этой команды выводится окно со шкалой, показанное на рисунке 5.

Рисунок 5. Шкала для выбора числовых значений
Рисунок 5. Шкала для выбора числовых значений

Первые пять ключей особых пояснений не требуют, так как их предназначение очевидно. Ключ --value=100 определяет начальное положение бегунка на шкале. Ключ --step=5 позволяет перемещаться по шкале с заданным шагом, если воспользоваться клавишами "стрелка влево" и "стрелка вправо". Особо следует отметить, что эта команда возвращает числовое значение, выбранное на шкале в момент выхода. В дополнение к этому можно задать режим фиксации промежуточных значений с помощью ключа --print-partial. В этом режиме для всех промежуточных положений бегунка в консоли будут выводиться соответствующие числовые значения.


Календарь

Календарь, имеющийся в zenity, обладает весьма скромной функциональностью. Он просто возвращает выбранную дату в формате, соответствующем текущей локали системы, или в формате, заданном ключом --date-format=формат_даты (задаваемый формат должен соответствовать требованиям функции strftime).

Следующая команда создаст календарь, изображенный на рисунке 6.

zenity --calendar --title="Выбор даты" \
       --text="Выберите дату для поиска более старых файлов" \
       --day=1 --month=7 --year=2011
Рисунок 6. Календарь для выбора даты
Рисунок 6. Календарь для выбора даты

Индикатор текущего состояния выполнения операции

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

Создать индикатор состояния немного сложнее, чем диалоговые окна, описанные ранее. Во время работы zenity может построчно принимать поток ввода и анализировать каждую строку. При получении строки, содержащей только число, zenity устанавливает текущий процент выполнения операции равным этому числу. Строки, начинающиеся со специального префикса '#', предназначены для вывода в диалоговом окне над шкалой индикатора. Все прочие строки игнорируются и могут служить в качестве комментариев. Простой пример создания индикатора состояния операции приведён в листинге 3.

Листинг 3. Использование индикатора состояния
#!/bin/sh
(
echo "10" ; sleep 1
echo "# Анализ изменённых параметров конфигурации" ; sleep 2
echo "25" ; sleep 3
echo "# Запись изменённых параметров конфигурации" ; sleep 5
echo "50" ; sleep 1
echo "Это комментарий - не выводится" ; sleep 1
echo "75" ; sleep 1
echo "# Перезапуск программы с изменённой конфигурацией" ; sleep 2
echo "100" ; sleep 1
) |
zenity --progress \
       --title="Конфигурирование" \
       --text="Инициализация..." \
       --percentage=0
if [ "$?" = -1 ]
then
  zenity --error --text="Изменение конфигурации отменено"
fi

На рисунке 7 изображена одна из стадий выполнения сценария из листинга 3.

Рисунок 7. Индикатор состояния выполнения операции
Рисунок 7. Индикатор состояния выполнения операции

Ключ --percentage=числовое_значение позволяет установить начальный процент выполнения задания. Кроме того, имеются дополнительные ключи:

  • --pulsate - вместо статического показа индикатор перемещается по шкале вправо-влево;
  • --auto-close - после того, как процент выполнения задачи станет равным 100, окно с индикатором прогресса автоматически закрывается;
  • --auto-kill - при нажатии кнопки "Отмена" ("Cancel") не только закрывается окно индикатора, но и посылается сигнал "kill" родительскому процессу.

Списки

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

Переключатели (ключ --checklist) и радио-кнопки (--radiolist) могут располагаться только в первом столбце, поэтому в строках для этих вариантов списка самым первым элементом обязательно должна быть строка "TRUE" или "FALSE".

По умолчанию возвращается первый столбец выбранной строки списка. Можно изменить выводимый столбец с помощью ключа --print-column=номер_столбца. Если задать ключ "ALL", то будут выведены все столбцы. Если пользователь выбрал несколько строк, то потребуется символ, разделяющий элементы этих строк при выводе. Для этого используется ключ --separator=строка-разделитель.

Листинг 4. Команда для создания диалогового окна со списком вариантов для выбора
zenity --list --title="Копирование файлов" \
       --text="Выберите необходимое средство копирования:" \
       --column="Средство" --column="Область действия" \
--column="Краткое описание" \
       cp "Локальный хост" "Копирование в файловой системе этого хоста" \
       nfs "Локальная сеть" "Копирование между хостами в локальной сети" \
       ftp "Без ограничений" "Копирование по протоколу ftp" \
       ssh "Без ограничений" "Защищённое копирование по протоколу ssh"

Команда из листинга 4 создаст диалоговое окно, изображенное на рисунке 8.

Рисунок 8. Диалоговое окно со списком вариантов для выбора
Рисунок 8. Диалоговое окно со списком вариантов для выбора
Листинг 5. Команда для создания диалогового окна со списком радио-кнопок
zenity --list --radiolist \
       --title="Сжатие архива файлов" \
       --text="Выберите способ сжатия архива файлов:" \
       --column="Отметка выбора" --column="Утилита сжатия" \
       FALSE zip TRUE gzip FALSE bzip2 FALSE 7zip

Команда из листинга 5 создаст диалоговое окно, изображенное на рисунке 9.

Рисунок 9. Диалоговое окно со списком радио-кнопок
Рисунок 9. Диалоговое окно со списком радио-кнопок

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

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

Листинг 6. Команда для создания диалогового окна со списком переключателей
zenity --list --checklist --multiple \
       --title="Подписка на новости" \
       --text="Отметьте необходимые источники новостей:" \
       --column="Пометить" --column="Источник новостей" --column="Обозначение" \
       --print-column="3" --separator=";" \
       TRUE "Организация GNU" "gnu-info" \
       FALSE "Linux Week News" "lwn" \
       FALSE "Open Source News" "OSNews" \
       FALSE "LinuxFormat" "LXF"
Рисунок 10. Диалоговое окно со списком переключателей
Рисунок 10. Диалоговое окно со списком переключателей

В данном случае zenity вернет только краткие обозначения источников новостей (третий столбец), разделённые точкой с запятой.

При необходимости строки в списке можно сделать редактируемыми с помощью ключа --editable, а также скрыть заданный столбец (ключ --hide-column=номер_столбца).


Ввод и редактирование текста

При взаимодействии с пользователем невозможно обойтись без средств ввода текстовой информации. Разумеется, zenity предоставляет и эти средства. В листинге 7 показано, как можно организовать ввод пароля.

Листинг 7. Пример ввода текста с помощью zenity
if zenity --entry --title="Проверка прав доступа" --text="Введите свой пароль:" \
          --entry-text="пароль" --hide-text
then
  echo $?
else
  zenity --error --text="Пароль не введён"
fi

В поле ввода содержится слово, определённое по умолчанию (ключ --entry-text), но скрытое из соображений безопасности (ключ --hide-text), как показано на рисунке 11.

Рисунок 11. Запрос и ввод пароля в диалоговом окне
Рисунок 11. Запрос и ввод пароля в диалоговом окне

Если объединить диалоговое окно для выбора файлов и диалоговое окно для вывода текстовой информации, то можно создать простой инструмент для просмотра содержимого файлов, как, например, в листинге 8.

Листинг 8. Утилита просмотра содержимого текстовых файлов
#!/bin/sh
file_name=`zenity --file-selection --title="Выберите файл для просмотра"`
case $? in
  0) zenity --text-info --title=$file_name \
            --filename=$file_name 2>/tmp/err.tmp ;;
  *) zenity --error --text="Файл не выбран" ;;
esac

Проверить работу этого сценария можно на любом текстовом файле.

Рисунок 12. Диалоговое окно для просмотра файлов
Рисунок 12. Диалоговое окно для просмотра файлов

С учётом того, что имеется возможность разрешить редактировать текст непосредственно в окне просмотра, то с помощью средств zenity можно создать "почти текстовый редактор". В сценарии из листинга 9 сначала выводится диалоговое окно для выбора файла, который будет выведен в окне просмотра. Но в этом окне включена возможность ввода нового текста и вставки ранее скопированного текста, а когда пользователь щёлкает по кнопке "Закрыть" (Close), то ещё раз выводится диалоговое окно для выбора файла, но уже в режиме сохранения (ключ --save).

Листинг 9. Простейший текстовый редактор
#!/bin/sh
open_path="$(zenity --file-selection)"
if [ "$open_path" != "" ]
then
  orig_text=$(cat "$open_path")
  edit_text=$(echo -n "$orig_text" | zenity --text-info --editable \
                                         --width=550 --height=500)
  save_path=$(echo -n "$(zenity --file-selection \
                      --filename="$open_path" --save --confirm-overwrite)")
  echo -n "$edit_text" > "$save_path"
fi

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

Рисунок 13. Окно для редактирования текстового файла
Рисунок 13. Окно для редактирования текстового файла

При попытке закрыть окно редактирования будет выведено окно сохранения файла, в котором можно сохранить изменённый текст в исходном файле или задать для него другой (новый) файл.


Заключение

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

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


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

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux, Open source
ArticleID=754863
ArticleTitle=Zenity - графический интерфейс для командной строки
publish-date=08302011