Программирование проклятий Python

Python

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

Оригинальная ссылка:docs.Python.org/3.6/how to/… От…
Автор оригинала: А. М. Кухлинг, Эрик С. Рэймонд
Версия: Release-2.04

Что такое проклятия?

curses — это библиотека, обеспечивающая отрисовку интерфейса и ответ на ввод с клавиатуры для текстовых терминалов. Эти терминалы включают VT100, терминалы Linux и эмулированные терминалы, предоставляемые различными программами. Терминал поддерживает использование различных управляющих кодов для выполнения одних и тех же операций, таких как перемещение курсора, прокрутка экрана и стирание области экрана. Коды управления различных терминалов в основном различаются и имеют свои особые привычки и навыки работы.

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

Curses предоставляет базовую функциональность, предоставляя программистам неповторяющееся текстовое окно. Содержимое окна можно изменить разными способами — добавив текст, удалив текст, изменив внешний вид и т. д. curses маскирует разницу в низкоуровневых командах терминала и выясняет, какую команду нужно выполнить. curses не предоставляет пользовательский интерфейс, такой как кнопки, флажки или диалоговые окна. Если вам нужны эти элементы, вы можете использовать что-то вродеUrwidбиблиотека пользовательского интерфейса.

Первоначально Curses был написан для BSD Unix; более поздние версии Unix System V от AT&T расширили исходную функциональность и добавили много новых функций. BSD curses больше не поддерживается и заменен ncurses. ncurses — это реализация интерфейса AT&T с открытым исходным кодом. Если вы используете Unix с открытым исходным кодом, например Linux или FreeBSD, ваша система уже должна включать ncurses. Поскольку сегодня большинство коммерческих версий Unix основаны на коде System V, теоретически описанная здесь функциональность также должна существовать. Тем не менее, некоторые старые версии Проклятия Unix могут не иметь очень хорошей поддержки.

Версия Python для Windows не включает модуль curses. аналогичная альтернативная версияUniCurses. Вы также можете попробовать это от Фредрика Лундаthe Console module, хотя API, используемый curses, отличается, он также может обеспечивать вывод на основе курсора и обеспечивать полную поддержку мыши и клавиатуры.

Модуль проклятий Python

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

Этот учебник представляет собой введение в написание текстовых программ с использованием curses и Python и не пытается быть сложным руководством по API curses. Таким образом, просмотрев руководство Python curses и руководство C ncurses, вы получите более подробное представление об API.

Начало и конец программы curses

Перед запуском проклятия должны быть инициализированы. позвонивinitscr()реализовать. Эта функция определит тип терминала и отправит терминалу некоторые команды для запуска, а также создаст внутреннюю структуру данных. Если выполнение прошло успешно,initscr()Возвращает класс окна, представляющий весь экран; обычно он называется в соответствии с именами переменных, связанных с языком C.stdscr.

import Curses
stdscr = curses.initscr()

Часто проклятия эхом отражаются на экране, поэтому ввод с клавиатуры читается и отображается только при определенных условиях. Это требует вызоваnoecho()метод.

curses.noecho()

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

curses.cbreak()

Терминалы обычно возвращают специальные клавиши в виде многобайтовых escape-последовательностей, таких как клавиши курсора, клавиша Home, Page Up и т. д. Curses позволяет вашей программе выполнять соответствующий код в соответствии с escape-последовательностью. Чтобы проклятия реагировали на эти специальные значения, необходимо включить режим клавиатуры.

stdscr.keypad(True)

Закрыть приложение curses гораздо проще, чем запустить его. Просто выполните следующий метод:

curses.nocbreak()
stdscr.keypad(False)
curses.echo()

Чтобы восстановить настройки терминала curses. Вызовите метод endwin() для сброса в исходный режим работы.

curses.endwin()

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

В Python вы можете использоватьcurses.wrapper()Чтобы избежать этой проблемы и облегчить отладку.

from curses import wrapper
def main(stdscr):
  # Clear screen
  stdscr.clear()
  # This raises ZeroDivisionError when i == 10.
  for i in range(0, 11):
      v = i-10
      stdscr.addstr(i, 0, '10 divided by {} is {}'.format(v, 10/v))
  stdscr.refresh()
  stdscr.getkey()
wrapper(main)

wrapper()Функция получает вызываемый объект и выполняет описанный выше процесс инициализации. Если цветовая конфигурация поддерживается, цветовая конфигурация инициализируется одновременно. Затем ваш код будет запущен. Как только код вернется,wrapper()сбросит начальное состояние терминала, а код будет помещен вtry
exceptВыполняется в , если перехватывается исключение, он сбрасывает терминал в исходное состояние и выдает исключение. Таким образом, когда возникает исключение, ваш терминал не будет в нелепом состоянии и сможет определить проблему на основе информации об исключении.

Окно и площадка

Окно — самый основной элемент в curses. Окно представляет собой прямоугольную область экрана, которая поддерживает отображение текста, удаление текста, пользовательский ввод и многое другое.

initscr()возвращается функциейstdscrОбъект — это объект-окно, покрывающий весь экран. Для многих программ достаточно одного окна, но иногда необходимо разделить экран на разные окна, чтобы их можно было перерисовывать и очищать по отдельности.newwin()Функция создает новое окно заданного размера и возвращает этот класс окна.

begin_x = 20; begin_y = 7
height = 5; width = 40
win = curses.newwin(height, width, begin_y, begin_x)

Обратите внимание, что система координат curses необычная. Координаты обычно имеют формат y,x, а начало координат находится в верхнем левом углу окна. Это отличается от обычного способа работы с координатами, начинающимися с x в программе. Это немного неудобно, но именно так были созданы проклятия, когда они родились, и уже слишком поздно что-то менять.

ты можешь пройтиcurses.LINESа такжеcurses.COLSнастроить размер экрана. от(0,0)прибыть(curses.LINES - 1, curses.COLS - 1)все доступные координаты.

Когда вы вызываете функцию для отображения или удаления текста, эффект не сразу отображается на экране. Вы должны вызвать экземпляр окнаrefresh()способ обновления экрана.

Это связано с тем, что терминальные соединения curses медленные, и становится необходимым сократить время перерисовки экрана. Поэтому Проклятия накапливают модификации при вызовеrefresh()метод, чтобы перерисовать окно наиболее эффективным способом. Например: если вы добавите текст в окно, а затем очистите содержимое окна, операция добавления текста станет ненужной, потому что добавленного текста вы не увидите.

На самом деле явное указание curses обновить окно не сильно усложняет программирование. Большинство программ ждут действий пользователя после выполнения ряда действий, и им нужно только вызвать перед ожиданием ввода пользователя.stdscr.refresh()илиrefresh()метод.

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

pad = curses.newpad(100, 100)
# These loops fill the pad with letters; addch() is
# explained in the next section
for y in range(0, 99):
    for x in range(0, 99):
        pad.addch(y,x, ord('a') + (x*x+y*y) % 26)
# Displays a section of the pad in the middle of the screen.
# (0,0) : coordinate of upper-left corner of pad area to display.
# (5,5) : coordinate of upper-left corner of window area to be filled
#         with pad content.
# (20, 75) : coordinate of lower-right corner of window area to be
#          : filled with pad content.
pad.refresh( 0,0, 5,5, 20,75)

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

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

  • вызов для каждого окнаnoutrefresh()Метод обновляет базовую структуру данных экрана и не обновляет экран.
  • перечислитьdoupdate()метод физического обновления вышеуказанной структуры данных на экране.

Итак, вы можете позвонить в некоторые окнаnoutrefresh()метод для обновления структуры данных, затем вызовитеdoupdate()метод обновления экрана.

отображать текст

Программисты на C могут найти методы курсоров похожими на лабиринт хитросплетений с тонкими различиями между методами. Например:addstr()будет в настоящее времяstdscrтекст отображается в месте курсора окна, иmvaddstr()Это для отображения текста в указанных координатах.waddstr()функция иaddstr()Аналогично, но позволяет указать окно вместо окна по умолчаниюstdscr,mvwaddstrПозволяет указать и окно, и координаты одновременно.

К счастью, интерфейс Python скрывает эти детали.stdscrэто оконный класс, такой же, как и любой другой, похожий наaddstr()Методы могут получать различные типы параметров.
Обычно содержит следующие четыре типа параметров.

Тип параметра описывать
ул или ч Показать str или ch в текущей позиции
улица или ch, attr Используйте атрибут attr для отображения str или ch в текущей позиции
у, х стр или ч отображать str или ch с координатами y,x
y,x str или ch, attr Используйте атрибут attr для отображения str или ch с координатами y,x.

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

addstr()Функция отображает строку или строку байтов на терминале. Строка байтов отправляется непосредственно на терминал, а строка кодируется как байты через атрибут окна и отправляется на терминал.Системная кодировка по умолчанию может быть передана черезlocale.getpreferredcoding()получать.

addch()Функция принимает символ, который может быть строкой длины 1, строкой байтов длины 1 или целым числом.

Для расширенных символов предусмотрены некоторые константы, все из которых больше 255. Например:ACS_PLMINUSпредставлять+/-символ,ACS_ULCORNERПредставляет верхний левый угол блока (обрабатывает границы рисования). Вы также можете использовать другие подходящие символы Unicode.

Окно автоматически запомнит положение курсора после последней операции, если вы не используете координаты, все операции начнутся там, где закончилась последняя операция. Вы также можете пройтиmove(y,x)Переместите курсор. Поскольку некоторые курсоры терминала по умолчанию мигают, необходимо переместить курсор в какое-нибудь менее раздражающее положение.

Если вашему приложению не нужен мигающий курсор, вы можете вызватьcurs_set(False)Сделать курсор невидимым. Для совместимости со старыми версиями curses,leaveok(bool)а такжеcurs_setимеют ту же функцию. Когда bool равно true, курсор становится невидимым, и вам не нужно беспокоиться о том, что курсор мерцает в каких-то странных местах.

атрибуты и цвета

Персонажи могут отображаться по-разному. Текстовые приложения часто используют негативную пленку для отображения состояния. Текстовым редакторам часто требуется выделять определенные слова. curses поддерживает посимвольную настройку через атрибуты для поддержки описаний выше.

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

Атрибуты описывать
A_BLINK символ мигает
A_BOLD Выделить или выделить жирным шрифтом символы
A_DIM полувыделенные символы
A_REVERSE Негативный фильм с изображением персонажей
A_UNDERLINE подчеркивание символов

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

stdscr.addstr(0, 0, "Current mode: Typing mode", curses.A_REVERSE)
stdscr.refresh()

curses также поддерживает добавление цвета к тексту терминала, который поддерживает цветное отображение.

Если вы хотите использовать функцию цвета, вы должныinitscr()выполнить послеstart_color()функция(curses.wrapper()будет выполняться автоматически) для инициализации управления цветом, а если терминал поддерживает маскирование цвета, то вызватьhas_colors()Функция возвращает ИСТИНА.

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

Пример использования комбинации цветов 1 для отображения текста:

stdscr.addstr("Pretty text", curses.color_pair(1))
stdscr.refresh()

Как упоминалось выше, каждый цветовой режим делится на цвет переднего плана и цвет фона.init_pair(n, f, b)Метод изменяет цвет переднего плана цветового режима n на f и цвет фона на b. Цветовой режим 0 означает белый текст на черном фоне и не может быть изменен.

Цвета пронумерованы,start_color()Метод инициализирует восемь основных цветов, а именно: 0: черный, 1: красный, 2: зеленый, 3: желтый, 4: синий, 5: пурпурный, 6: голубой, 7: белый. curses также устанавливает постоянные значения для этих цветов, curses.COLOR_BLACK, curses.COLOR_RED, curses.COLOR_GREEN и т.д.

Позвольте мне применить это на практике и изменить цветовой режим № 1 на красный текст на белом фоне:

curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)

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

stdscr.addstr(0, 0, "RED ALERT!", curs_set.color_pair(1))

Многие терминалы поддерживают изменение цветов по заданным значениям RGB. Это изменяет цветовой режим на все, что вы хотите. К сожалению, стандартный терминал Linux не поддерживает его, поэтому я не могу продемонстрировать или привести пример. Вы можете сделать это, позвонивcan_change_color()функцию, чтобы определить, поддерживает ли ваш терминал эту функцию. Если ваш терминал возвращает True, указывая на поддержку, вы можете обратиться к справочной странице для получения дополнительной информации.

пользовательский ввод

C curses предоставляет очень простой метод ввода. Curses Python добавляет некоторые базовые приемы ввода (другие библиотеки, подобные Urwid, предлагают более широкий набор приемов ввода).

Существует два способа ввода данных в окно:

  • getch()обновите экран и подождите, пока пользователь введет ключ, еслиecho()Вызывается перед этим, введенные нажатия клавиш будут отображаться на экране синхронно. Вы можете указать координаты для управления положением отображения.
  • getkey()Делает то же самое, что и функция выше, за исключением того, что преобразует целое число в строку. Один символ возвращает одну строку, а специальные клавиши возвращают длинную строку, аналогичнуюKEY_UPили^G

позвонивnodelay()Функцию можно реализовать, не дожидаясь ввода пользователя, если установленоnodelay(True),getch()а такжеgetkey()Функция больше не ожидает ввода. Если нет ввода,getch()вернусьcurses.ERR(Значение -1),getkey()Функция выдает исключение.getch()есть еще одинhalfdelay()Функцию можно настроить так, чтобы она выдавала исключение, если в течение заданного времени (в десятых долях секунды) пользовательский ввод не получен.

getch()Функция возвращает целое число. Если он находится в диапазоне от 0 до 255, он представляет код ASCII.Если он больше 255, это могут быть некоторые специальные клавиши, такие как Page Up, Home или клавиши курсора. Вы можете определить ввод, сравнив входное значение с некоторыми константами. Константы похожи: curses.KEY_PPAGE, curses.KEY_HOME, curses.KEY_LEFT. Таким образом, основной цикл вашего кода может выглядеть так:

while True:
  c = stdscr.getch()
  if c == ord('p'):
    PrintDocunment()
  elif c == ord('q'):
    break
  elif c == curses.KEY_HOME:
    x = y = 0

curses.asciiМодуль обеспечивает функции обработки ASCII, параметр представляет собой целое число или один символ. Полезно для написания более читаемого кода. Также предоставляет диалоговые функции, которые принимают целое число или символ. Например:curses.ascii.ctrl()Возвращает управляющий символ в соответствии с параметром.

Также есть функция, которая может получить всю строку, т.е.getstr(), редко используется из-за функциональных ограничений. Единственными клавишами редактирования являются клавиши Backspace и Enter.getstr()Может использоваться для получения строки заданной длины.

curses.echo()            # Enable echoing of characters
# Get a 15-character string, with the cursor on the top line
s = stdscr.getstr(0,0, 15)

curses.textpadМодуль предоставляет текстовое поле, которое поддерживает сочетания клавиш, подобные Emacs.TextboxРазличные методы поддержки редактирования ввода и агрегирования результатов редактирования с дополнительными пробелами или без них.
Ниже приведен пример

import curses
from curses.textpad import Textbox, rectangle
def main(stdscr):
    stdscr.addstr(0, 0, "Enter IM message: (hit Ctrl-G to send)")
    editwin = curses.newwin(5,30, 2,1)
    rectangle(stdscr, 1,0, 1+5+1, 1+30+1)
    stdscr.refresh()
    box = Textbox(editwin)
    # Let the user edit until Ctrl-G is struck.
    box.edit()
    # Get resulting contents
    message = box.gather()

Дополнительная ссылка на контентcurses.textpadдокументация.

Дополнительная информация

В этом руководстве не рассматриваются сложные темы, такие как чтение информации с экрана и захват движений мыши. Но у ПитонаcursesДокументация для модулей завершена, вы должны прочитать их дальше.

Если вы все еще сомневаетесь в некоторых особенностях поведения функций curses, обратитесь к документации по вашей реализации curses, будь то ncurses или другая реализация Unix. В руководстве описаны различные приемы, а также доступен полный список функций, свойств и символов ACS_*.

Поскольку API curses очень сложен, некоторые функции не поддерживаются Python. Обычно это происходит не потому, что эти функции сложно реализовать, а потому, что они никому больше не нужны. Точно так же Python не поддерживает библиотеку меню ncurses. Вы можете реализовать эти нереализованные функции, читайтеРуководство разработчика PythonУзнайте, как отправить код для Python.