Программирование на Python 3. Руководство издательство СимволПлюс
![]()
|
551 граммы, которой был передан один из файлов index.html, входя щих в состав документации к языку Python: html xmlns = http://www.w3.org/1999/xhtml meta httpequiv = ContentType content = text/html; charset=utf8 li class = right style = marginright: 10px Один из вариантов решения этой задачи заключается в использова нии двух регулярных выражений, одно из которых сохраняет име на тегов и их атрибутов, а второе извлекает имя и значение каждого атрибута. Значения атрибутов могут окружаться кавычками или апострофами (в этом случае они могут содержать пробелы и кавыч ки, по своему типу не совпадающие с кавычками, окружающими значение), но могут указываться и без кавычек (в этом случае они не могут содержать пробелы и кавычки). Вероятно, проще всего на чать с создания двух регулярных выражений для обработки значе ний в кавычках и без кавычек, а затем объединить их в общем регу лярном выражении, обрабатывающем оба случая. Чтобы сделать регулярное выражение более удобочитаемым, лучше использовать именованные группы. Эта задача не из легких, особенно если учесть, что обратные ссылки не могут использоваться в символь ных классах. Решение приводится в файле extract_tags.py, содержащем менее 35 строк программного кода. Регулярное выражение, извлекающее имена тегов и атрибутов, занимает одну строку. Регулярное выра жение, извлекающее имена атрибутов и их значения, занимает полдюжины строк и использует альтернативы, условное совпаде ние (дважды, одно вложено в другое), а также максимальные и ми нимальные квантификаторы. 13 Введение в программирование графического интерфейса В языке Python отсутствует собственная поддержка возможности соз дания графического интерфейса, но в этом нет никакой проблемы, так как программисты, разрабатывающие программы на языке Python, могут использовать библиотеки графического интерфейса, написан ные для других языков программирования. Такое возможно благодаря тому, что для языка Python существует множество оберток, или при вязок, для большинства распространенных библиотек создания графи ческого интерфейса. Эти пакеты и модули могут импортироваться и использоваться, как любые другие пакеты и модули в языке Python, при этом они обеспечивают доступ к функциональным возможностям, находящимся в библиотеках, написанных не на языке Python. Стандартная библиотека языка Python включает в себя связку Tcl/Tk. Tcl – это язык сценариев со свободным синтаксисом, а Tk – библиотека для создания графического интерфейса, написанная на языках Tcl и C. Модуль tkinter языка Python обеспечивает привязку к графическому интерфейсу библиотеки Tk. В сравнении с другими библиотеками гра фического интерфейса библиотека Tk обладает тремя преимущества ми, доступными для языка Python. Вопервых, она устанавливается вместе с интерпретатором Python, поэтому она всегда находится в рас поряжении программиста. Вовторых, она имеет небольшой размер (даже вместе с интерпретатором Tcl). И втретьих, она поставляется вместе со средой разработки IDLE, которую удобно использовать для разработки и отладки программ на языке Python. К сожалению, до версии 8.5 библиотека Tk воспроизводила графиче ский интерфейс в соответствии с отошедшими в прошлое представле ниями о графическом оформлении и содержала весьма ограниченный набор виджетов («элементов управления», или «контейнеров», в тер • Программы в виде диалога • Программы с главным окном Программы в виде диалога 553 минологии Windows). Хотя с помощью библиотеки Tk легко можно создавать свои собственные виджеты путем компоновки других вид жетов, но эта библиотека не обеспечивает прямую возможность созда ния собственных виджетов с нуля, позволяющую программисту рисо вать необходимые ему элементы. Дополнительные виджеты, совмес тимые с библиотекой Tk, можно найти в библиотеке Tix, также входя щей в состав стандартной библиотеки языка Python, но она не всегда предоставляется для платформ, отличных от Windows. Особняком в этом отношении стоит дистрибутив Ubuntu, который к моменту на писания этих строк был единственным, который содержал эту библио теку, хотя и в виде неподдерживаемого дополнения. Для библиотек Tk и Tix очень мало документации, ориентированной на применение этих библиотек в языке Python, – большая часть документации написана для программистов Tcl/Tk и сложна для понимания тем, кто не связан с программированием на языке Tcl. 1 Если перед вами стоит цель создавать программы на языке Python, ко торые могут выполняться на любых платформах (например, Windows, Mac OS X и Linux) и используют только стандартные возможности, без привлечения дополнительных библиотек, у вас остается единствен ный выбор: Tk. Если имеется возможность использовать сторонние библиотеки, число возможных вариантов возрастает существенно. Один из них состоит в том, чтобы получить комплект инструментов WCK (Widget Construc tion Kit – набор инструментов для создания виджетов, www.effbot.org/ zone/wck.htm ), обеспечивающий дополнительные функциональные возможности, совместимые с библиотекой Tk, включая создание собст венных виджетов, содержимое которых создается программным кодом. Все остальные варианты, в которых не используется библиотека Tk, делятся на две категории – конкретные для определенной платформы и платформеннонезависимые. Платформеннозависимые библиотеки графического интерфейса обеспечивают доступ к платформеннозави симым особенностям, но они жестко привязывают нас к определенной платформе. Наиболее известными кроссплатформенными привязка ми для библиотек графического интерфейса в языке Python являются: PyGtk (www.pygtk.org), PyQt (www.riverbankcomputing.com/software/ pyqt ) и wxPython (www.wxpython.org). Все три библиотеки предлагают намного большее количество виджетов, чем библиотека Tk, позволяют воспроизводить более привлекательный графический интерфейс (хотя 1 Автору известна единственная книга о применении Tk в языке Python – «Python and Tkinter Programming» Джона Грейсона (John Grayson), ISBN 1884777813, опубликованная в 2000 году; в некоторых вопросах она уже устарела. Хорошая книга о Tcl/Tk: «Practical Programming in Tcl and Tk» Брента Велша (Brent Welch) и Кена Джонса (Ken Jones), ISBN 0130385603. Вся документация по Tcl/Tk доступна по адресу www.tcl.tk. 554 Глава 13. Введение в программирование графического интерфейса этот недостаток в некоторой степени был устранен в версии Tk 8.5) и позволяют создавать собственные виджеты, которые воспроизводят ся программным кодом. В изучении и использовании все они более простые, чем Tk, и для всех имеется гораздо больше документации, ориентированной на программистов, использующих язык Python, чем для Tk. В общем случае программы, использующие PyGtk, PyQt или wxPython, получаются более короткими и дают более качественный результат, нежели программы, использующие Tk. И все же, несмотря на все ограничения и недостатки, библиотеку Tk можно использовать для создания полезных программ с графическим интерфейсом – среда разработки IDLE является наиболее известным в мире Python подтверждением этих слов. Кроме того, во время напи сания этой книги появились признаки оживления в разработке биб лиотеки Tk. Начиная с версии 8.5, в библиотеке была реализована под держка тем оформления, что обеспечивает большее сходство графиче ского интерфейса программ с графическим интерфейсом операцион ной системы, а также появилось множество новых виджетов. Цель этой главы состоит в том, чтобы дать вам общее представление о программировании с применением библиотеки Tk. При необходимо сти разработки серьезного графического интерфейса лучше не обра щаться к материалу этой главы (так как в ней демонстрируются уста ревшие подходы к использованию библиотеки Tk для создания графи ческого интерфейса) и воспользоваться одной из альтернативных биб лиотек. Но если Tk – единственная доступная для вас возможность, то вам определенно следует изучить язык Tcl, чтобы иметь возможность читать документацию для библиотеки Tk. В следующих разделах мы создадим две программы с графическим ин терфейсом с использованием библиотеки Tk. Первая, очень маленькая программа, в форме диалога, позволяет вычислять сложные проценты по банковским вкладам. Вторая программа – более сложная, она име ет главное окно и управляет списком закладок (имена и адреса URL). Благодаря использованию таких простых данных мы можем сконцен трировать все свое внимание на программировании графического ин терфейса, не отвлекаясь на посторонние детали. В процессе обзора программы управления закладками мы увидим, как создавать свои собственные диалоги и как создавать главное окно программы, с поло сой меню и панелями инструментов, а также как все это соединить в единую полноценную работающую программу. Но для начала нам необходимо рассмотреть некоторые основные принципы программи рования графического интерфейса, поскольку они существенно отли чаются от принципов создания консольных программ. Консольные программы на языке Python и файлы модулей всегда име ют расширение .py, но для файлов программ с графическим интерфей сом используется расширение .pyw (однако для файлов модулей всегда используется только расширение .py). Для операционной системы Программы в виде диалога 555 Linux нет никакой разницы между расширениями .py и .pyw, но в Win dows расширение .pyw ассоциировано не с выполняемым файлом ин терпретатора python.exe, а с pythonw.exe, вследствие чего при запуске программы на языке Python с графическим интерфейсом не будет по являться окно консоли. В операционной системе Mac OS X похожая ситуация – для файлов программ с графическим интерфейсом исполь зуется расширение .pyw. Когда запускается программа с графическим интерфейсом, она обыч но начинает с того, что создает главное окно и все виджеты главного окна, такие как полоса меню, панели инструментов, центральная об ласть и строка состояния. После создания окна программа с графиче ским интерфейсом, подобно серверной программе, переходит в режим ожидания. Однако если серверная программа ожидает получения за просов от программклиентов, то программа с графическим интерфей сом ожидает некоторых действий пользователя, таких как щелчок мышью или нажатие клавиши. Эти различия между консольными программами и программами с графическим интерфейсом изображе ны на рис. 13.1. Но программа с графическим интерфейсом не просто пассивно ожидает, она выполняет цикл обработки событий, алгоритм работы которого на псевдокоде выглядит, как показано ниже: Обработка Вывод результатов Завершение Типичная программа с графическим интерфейсом Да Да Нет Нет Типичная консольная программа Запуск Запуск Чтение входных данных Обработка Получен запрос на завершение? Есть событие для обработки? Создание графического интерфейса Запуск цикла обработки событий Завершение Рис. 13.1. Консольная программа и программа с графическим интерфейсом 556 Глава 13. Введение в программирование графического интерфейса while True: event = getNextEvent() if event: if event == Terminate: break processEvent(event) Когда пользователь взаимодействует с программой, или когда возни кают какиелибо другие события, такие как событие от таймера, или когда окно программы активируется (возможно, изза того что было закрыто окно какойнибудь другой программы), внутри библиотеки графического интерфейса генерируется событие, которое затем добав ляется в очередь событий. Цикл обработки событий в программе по стоянно проверяет эту очередь, чтобы определить, не появились ли со бытия, требующие обработки, и если такие события появились, обра батывает их (или передает для обработки соответствующим функциям и методам). При создании программ с графическим интерфейсом мы можем опи раться на цикл обработки событий, реализованный в библиотеке гра фического интерфейса. На нашу долю остается создать классы, пред ставляющие окна и виджеты, необходимые программе, и снабдить их методами, которые будут соответствующим образом обрабатывать дей ствия пользователя. Программы в виде диалога Первая программа, которую мы рассмотрим, – это программа Interest. Эта программа, имеющая вид диалога (то есть она не имеет полосы ме ню), может использоваться для вычисления сложных процентов по банковским вкладам. Окно программы представлено на рис. 13.2. В большинстве объектноориентированных программ с графическим интерфейсом для представления единственного главного окна или диа Рис. 13.2. Программа Interest Программы в виде диалога 557 логов используются классы, а большинство виджетов, содержащихся в окне, являются экземплярами стандартных виджетов, таких как кнопки или флажки, предоставляемые библиотекой. Как и большинст во кроссплатформенных библиотек графического интерфейса, библио тека Tk в действительности не различает главное окно и виджеты, ок но – это обычный виджет, который не имеет родительского виджета (то есть он не содержится внутри другого виджета). Виджеты, не имеющие родительского виджета (окна), автоматически снабжаются рамкой и прочими визуальными атрибутами окна (такими как строка заголов ка и кнопка закрытия окна) и, как правило, содержат другие виджеты. В большинстве своем виджеты создаются как дочерние по отношению к другим виджетам (и содержатся внутри своих родительских видже тов), а окна создаются как дочерние виджеты объекта tkinter.Tk. Этот объект обычно концептуально представляет приложение. Помимо раз деления на виджеты и окна (которые также называются виджетами верхнего уровня), отношения родительпотомок обеспечивают кор ректный порядок удаления виджетов и автоматическое удаление всех дочерних виджетов при удалении родительского виджета. Метод инициализации служит местом, где создается пользователь ский интерфейс (создаются и размещаются виджеты, выполняется привязка клавиатуры и мыши), а другие методы используются для об работки действий пользователя. Библиотека Tk позволяет создавать собственные виджеты либо посредством создания подклассов пред определенных виджетов, таких как tkinter.Frame, либо посредством создания обычных классов и добавления в них виджетов в виде атри бутов. В первом примере мы будем создавать свои подклассы, а в сле дующем будут применены оба подхода. Так как программа Interest имеет единственное главное окно, она реа лизована в виде единственного класса. Начнем разбор с метода инициа лизации, разбитого на пять частей, так как он достаточно длинный. class MainWindow(tkinter.Frame): def __init__(self, parent): super(MainWindow, self).__init__(parent) self.parent = parent self.grid(row=0, column=0) Сначала вызывается метод инициализации базового класса. (В идеале можно было бы вызвать метод как super().__init__(parent), но к мо менту написания этих строк такой способ уже не работал, поэтому вы зывается функция super() с базовым классом и объектом self в виде явно передаваемых аргументов.) Затем сохраняется копия родитель ского виджета для последующего использования. Виджеты располага ются внутри других виджетов с помощью менеджеров компоновки, а не с помощью абсолютных координат и размеров. Вызов метода grid() помещает окно внутрь менеджера компоновки типа «сетка». Каждый 558 Глава 13. Введение в программирование графического интерфейса отображаемый виджет должен быть помещен в менеджер компонов ки, даже виджет верхнего уровня. В библиотеке Tk имеется несколько менеджеров компоновки, но менеджер типа «сетка» является наибо лее простым в использовании, хотя для виджетов верхнего уровня, чтобы добиться того же эффекта, можно было бы использовать менед жер компоновки типа «мозаика» (packer), вызвав метод pack() вместо grid(row=0, column=0) self.principal = tkinter.DoubleVar() self.principal.set(1000.0) self.rate = tkinter.DoubleVar() self.rate.set(5.0) self.years = tkinter.IntVar() self.amount = tkinter.StringVar() Библиотека Tk позволяет создавать переменные, ассоциированные с виджетами. Если значение переменной изменяется программным способом, изменения тут же отражаются в соответствующем ей видже те, и точно так же, если пользователь изменяет значение в виджете, изменяется значение в ассоциированной переменной. Здесь были соз даны две переменные типа «double» (они хранят значения типа float), целочисленная переменная, строковая переменная и заданы началь ные значения в двух из них. principalLabel = tkinter.Label(self, text="Principal $:", anchor=tkinter.W, underline=0) principalScale = tkinter.Scale(self, variable=self.principal, command=self.updateUi, from_=100, to=10000000, resolution=100, orient=tkinter.HORIZONTAL) rateLabel = tkinter.Label(self, text="Rate %:", underline=0, anchor=tkinter.W) rateScale = tkinter.Scale(self, variable=self.rate, command=self.updateUi, from_=1, to=100, resolution=0.25, digits=5, orient=tkinter.HORIZONTAL) yearsLabel = tkinter.Label(self, text="Years:", underline=0, anchor=tkinter.W) yearsScale = tkinter.Scale(self, variable=self.years, command=self.updateUi, from_=1, to=50, orient=tkinter.HORIZONTAL) amountLabel = tkinter.Label(self, text="Amount $", anchor=tkinter.W) actualAmountLabel = tkinter.Label(self, textvariable=self.amount, relief=tkinter.SUNKEN, anchor=tkinter.E) В этой части метода инициализации создаются виджеты. Виджет tkinter.Label используется для отображения текста, доступного толь ко для чтения. Как и в случае любых других виджетов, при его созда нии определяется родительский виджет (в данном случае, как и в лю бом другом, родителем является содержащий его виджет), а затем че рез именованные аргументы задаются настройки различных аспектов |