Бои за Авдеевку 2023
Loki (обсуждение | вклад) (полностью поменял форматирование кода т.к. не работал) |
м (SEO TROLLING переименовал страницу LXF80:Python в Бои за Авдеевку 2023) |
||
(не показаны 6 промежуточных версий 3 участников) | |||
Строка 18: | Строка 18: | ||
=== Очарование простоты === | === Очарование простоты === | ||
− | Проверить наличие ''Tkinter ''в вашем дистрибутиве достаточно просто (он должен быть, но всякое случается): запустите ''Python ''и выполните команду import ''Tkinter ''(обратите внимание на заглавную первую букву). Если вам не повезло и вы увидели сообщение об ошибке, придётся установить этот модуль отдельно. Проконсультируйтесь с вашим менеджером пакетов, не знает ли он случайно про ''Tkinter ''(имя пакета, в отличие от модуля, обычно записывается только маленькими буквами). Если он окажется из партизанской семьи, то прямая дорога вам на | + | Проверить наличие ''Tkinter'' в вашем дистрибутиве достаточно просто (он должен быть, но всякое случается): запустите ''Python'' и выполните команду import ''Tkinter'' (обратите внимание на заглавную первую букву). Если вам не повезло и вы увидели сообщение об ошибке, придётся установить этот модуль отдельно. Проконсультируйтесь с вашим менеджером пакетов, не знает ли он случайно про ''Tkinter'' (имя пакета, в отличие от модуля, обычно записывается только маленькими буквами). Если он окажется из партизанской семьи, то прямая дорога вам на http://www.python.org/ (который с новым дизайном смотрится очень даже приятно). |
+ | |||
+ | [[Изображение:Img 80 98 2.jpg|thumb|400px|Рисунок 1. Tkinter – лучший способ сделать не так, как у других!]] | ||
Разобравшись с модулем, приступим сразу к серьёзной работе. В качестве примера выберем такую задачу: разработать графический интерфейс для просмотра man-страниц. Хорош он тем, что логика предельно проста, и нам почти не придётся отвлекаться от основной задачи. Итак, сразу код (по мере необходимости, будем прерывать его некоторыми пояснениями): | Разобравшись с модулем, приступим сразу к серьёзной работе. В качестве примера выберем такую задачу: разработать графический интерфейс для просмотра man-страниц. Хорош он тем, что логика предельно проста, и нам почти не придётся отвлекаться от основной задачи. Итак, сразу код (по мере необходимости, будем прерывать его некоторыми пояснениями): | ||
− | + | <source lang="python"> | |
− | + | #!/usr/bin/Python | |
− | + | # -*- coding: utf-8 -*- | |
+ | import os, re | ||
+ | from Tkinter import * | ||
+ | </source> | ||
Здесь мы объявили кодировку нашей локали и подключили необходимые для работы модули (не забывайте следить за регистром символов). Далее опишем класс, который будет отвечать за работу нашего приложения. Использование объектного подхода позволит в дальнейшем, если потребуется, легко создавать модифицированные приложения на базе этого класса или интегрировать его функциональность в другие объекты: | Здесь мы объявили кодировку нашей локали и подключили необходимые для работы модули (не забывайте следить за регистром символов). Далее опишем класс, который будет отвечать за работу нашего приложения. Использование объектного подхода позволит в дальнейшем, если потребуется, легко создавать модифицированные приложения на базе этого класса или интегрировать его функциональность в другие объекты: | ||
− | + | <source lang="python"> | |
− | + | class ManReader: | |
− | + | def getman(self, manpage, sn): | |
− | + | bschar = '\b' | |
− | + | tmp = os.popen('man %s %s 2>/dev/null' % (sn, manpage)).read() | |
− | + | if tmp: | |
− | + | tmp = re.sub(r'(.)%c\1' % bschar, r'\1', tmp) | |
− | + | tmp = tmp.replace('_%c' % bschar, '') | |
− | + | else: | |
− | + | tmp = 'Page "%s" in section "%s" not found' % (manpage, sn or 'Auto') | |
− | + | return tmp | |
− | + | </source> | |
Метод с украинским именем '''getman()''' отвечает за то, чтобы вернуть запрошенную man-страницу в виде текстовой переменной. Для этого используем уже знакомую нам функцию '''popen()''' модуля '''os'''. Нужно учитывать, что man-страницы могут содержать специальное форматирование: подсветку и подчёркивание. Чтобы не усложнять наш пример, мы просто избавляемся от ненужных символов, оставляя чистый текст. Пожалуй, нужно пояснить, как мы это делаем. | Метод с украинским именем '''getman()''' отвечает за то, чтобы вернуть запрошенную man-страницу в виде текстовой переменной. Для этого используем уже знакомую нам функцию '''popen()''' модуля '''os'''. Нужно учитывать, что man-страницы могут содержать специальное форматирование: подсветку и подчёркивание. Чтобы не усложнять наш пример, мы просто избавляемся от ненужных символов, оставляя чистый текст. Пожалуй, нужно пояснить, как мы это делаем. | ||
Строка 47: | Строка 52: | ||
def pressBtn(self): | def pressBtn(self): | ||
<nowiki>sn = sectno.get()[0]</nowiki> | <nowiki>sn = sectno.get()[0]</nowiki> | ||
− | if sn == | + | if sn == '-': sn = '' |
tx.delete(1.0, END) | tx.delete(1.0, END) | ||
tx.insert(1.0, self.getman(ent.get(), sn)) | tx.insert(1.0, self.getman(ent.get(), sn)) | ||
Строка 59: | Строка 64: | ||
win = Tk() | win = Tk() | ||
− | win.title( | + | win.title('Просмотрщик man-страниц') |
Так мы создаём объект, который будет являться нашим рабочим окном. Заодно задаём ему заголовок. | Так мы создаём объект, который будет являться нашим рабочим окном. Заодно задаём ему заголовок. | ||
sectno = StringVar() | sectno = StringVar() | ||
− | sectno.set( | + | sectno.set('---Auto---') |
В будущем нам понадобится эта переменная – она должна представлять собой особый объект, поэтому и создаём её как экземпляр класса '''Tkinter.StringVar()'''. | В будущем нам понадобится эта переменная – она должна представлять собой особый объект, поэтому и создаём её как экземпляр класса '''Tkinter.StringVar()'''. | ||
Строка 75: | Строка 80: | ||
Здесь нужно сказать, что '''pack''' – не единственный метод упаковки в T''kinter''. В ряде случаев удобнее использовать упаковку «по сетке» – '''grid''' (подробности можно узнать в документации). Приступаем к созданию графических элементов: | Здесь нужно сказать, что '''pack''' – не единственный метод упаковки в T''kinter''. В ряде случаев удобнее использовать упаковку «по сетке» – '''grid''' (подробности можно узнать в документации). Приступаем к созданию графических элементов: | ||
− | lbl1 = Label(fcmd, text= | + | lbl1 = Label(fcmd, text='Read about ') |
lbl1.pack(side=LEFT) | lbl1.pack(side=LEFT) | ||
Строка 81: | Строка 86: | ||
ent = Entry(fcmd) | ent = Entry(fcmd) | ||
− | <nowiki>ent.bind( | + | <nowiki>ent.bind('<Return>', (lambda event: self.pressBtn()))</nowiki> |
ent.pack(side=LEFT) | ent.pack(side=LEFT) | ||
Строка 88: | Строка 93: | ||
Метод '''bind()''' <nowiki>задаёт реакцию поля на нажатие клавиши [Enter] (a.k.a. Return) – будет вызван метод </nowiki>'''pressBtn().''' | Метод '''bind()''' <nowiki>задаёт реакцию поля на нажатие клавиши [Enter] (a.k.a. Return) – будет вызван метод </nowiki>'''pressBtn().''' | ||
− | lbl2 = Label(fcmd, text= | + | lbl2 = Label(fcmd, text=' in section ') |
lbl2.pack(side=LEFT) | lbl2.pack(side=LEFT) | ||
slt = OptionMenu(fcmd, sectno, | slt = OptionMenu(fcmd, sectno, | ||
− | + | '---Auto---', | |
− | + | '1 User Utilities', | |
− | + | '2 System Calls', | |
− | + | '3 Library Functions', | |
− | + | '4 Devices & Kernel Interfaces', | |
− | + | '5 File Formats', | |
− | + | '6 Games', | |
− | + | '7 Macros & SQL Commands', | |
− | + | '8 System Utilities', | |
− | + | '9 X Window', | |
− | + | 'n Built-In commands', | |
) | ) | ||
Строка 108: | Строка 113: | ||
Ещё одна текстовая метка, и далее – выпадающий список. В нём мы перечисляем имеющиеся разделы справки, к которым будет относиться наш запрос. | Ещё одна текстовая метка, и далее – выпадающий список. В нём мы перечисляем имеющиеся разделы справки, к которым будет относиться наш запрос. | ||
− | btn1 = Button(fcmd, command=win.quit, text= | + | btn1 = Button(fcmd, command=win.quit, text='Quit') |
btn1.pack(side=RIGHT) | btn1.pack(side=RIGHT) | ||
− | btn2 = Button(fcmd, command=self.pressBtn, text= | + | btn2 = Button(fcmd, command=self.pressBtn, text='Open') |
btn2.pack(side=RIGHT) | btn2.pack(side=RIGHT) | ||
Строка 132: | Строка 137: | ||
Всё выше было просто подготовкой. А вот этой командой мы запускаем наше окно в работу. С этого момента управление передаётся ''Tkinterо''бъекту, и влиять на его поведение можно только с помощью описанных ранее обработчиков событий. | Всё выше было просто подготовкой. А вот этой командой мы запускаем наше окно в работу. С этого момента управление передаётся ''Tkinterо''бъекту, и влиять на его поведение можно только с помощью описанных ранее обработчиков событий. | ||
− | if __name__ == | + | if __name__ == '__main__': |
test = ManReader() | test = ManReader() | ||
test.Drawface() | test.Drawface() | ||
Строка 170: | Строка 175: | ||
btn.connect('pressed', lambda button: gtk.main_quit()) | btn.connect('pressed', lambda button: gtk.main_quit()) | ||
btn.show() | btn.show() | ||
− | # объект Window может содержать только один элемент, так что им будет HBox, который служит контейнером для остальных | + | # объект Window может содержать только один элемент, так что им будет HBox, |
+ | # который служит контейнером для остальных | ||
box = gtk.HBox() | box = gtk.HBox() | ||
box.pack_start(txt) | box.pack_start(txt) | ||
Строка 184: | Строка 190: | ||
Результат представлен на рисунке 2. | Результат представлен на рисунке 2. | ||
− | [[Изображение: | + | [[Изображение:Img 80 98 1.jpg|left|thumb|400px|Рисунок 2. Именно так вы и должны представлять себе GTK- |
приложение.]] | приложение.]] | ||
=== Фанатам KDE посвящается === | === Фанатам KDE посвящается === | ||
− | Если для вас Linux не мыслим без KDE, то ''PyQt ''– как раз тот инструмент, который способен обеспечить «бесшовную» интеграцию ваших '' | + | Если для вас Linux не мыслим без KDE, то ''PyQt ''– как раз тот инструмент, который способен обеспечить «бесшовную» интеграцию ваших ''Python''-сценариев с окружением рабочего стола. (Впрочем, ''Qt ''работает не только в Linux, так что ваши решения по-прежнему сохранят определённый уровень переносимости.) К тому же, для разработки интерфейса к вашим услугам ''Qt Designer''. А создадим мы программу для просмотра запущенных в системе процессов. Итак, в путь! |
− | [[Изображение: | + | [[Изображение:Img 80 99 1.jpg|thumb|400px|Рисунок 3. Мышкой влево, мышкой вправо – а зачем вам |
вообще клавиатура?]] | вообще клавиатура?]] | ||
Строка 215: | Строка 221: | ||
<nowiki># </nowiki>Формируем нужные ключи команды ps | <nowiki># </nowiki>Формируем нужные ключи команды ps | ||
if self.radioButton1.isChecked(): | if self.radioButton1.isChecked(): | ||
− | all = | + | all = 'a' |
else: | else: | ||
− | all = | + | all = '' |
<nowiki># Выводимые поля описываются после ключа «o»</nowiki> | <nowiki># Выводимые поля описываются после ключа «o»</nowiki> | ||
<nowiki>#- Очень важно не допускать пробелов!</nowiki> | <nowiki>#- Очень важно не допускать пробелов!</nowiki> | ||
− | fields = | + | fields = 'o' |
if self.checkBox1.isChecked(): | if self.checkBox1.isChecked(): | ||
− | fields += | + | fields += 'pid,' |
if self.checkBox2.isChecked(): | if self.checkBox2.isChecked(): | ||
− | fields += | + | fields += 'user,' |
if self.checkBox3.isChecked(): | if self.checkBox3.isChecked(): | ||
− | fields += | + | fields += 'stat,' |
if self.checkBox4.isChecked(): | if self.checkBox4.isChecked(): | ||
− | fields += | + | fields += 'command,' |
<nowiki>fields = fields[:-1] # </nowiki>последнюю запятую – долой! | <nowiki>fields = fields[:-1] # </nowiki>последнюю запятую – долой! | ||
filter = self.lineEdit1.text() | filter = self.lineEdit1.text() | ||
Строка 234: | Строка 240: | ||
<nowiki>#- отдельной командой (head – чтобы не выводить лишнее)</nowiki> | <nowiki>#- отдельной командой (head – чтобы не выводить лишнее)</nowiki> | ||
if filter: | if filter: | ||
− | cmd = | + | cmd = 'ps %sx%s | grep %s | grep -v grep' % (all, fields, |
filter) | filter) | ||
− | head = os.popen( | + | head = os.popen('ps %s | head' % fields).readline() |
body = os.popen(cmd).read() | body = os.popen(cmd).read() | ||
else: | else: | ||
− | cmd = | + | cmd = 'ps %sx%s' % (all, fields) |
pspipe = os.popen(cmd) | pspipe = os.popen(cmd) | ||
head = pspipe.readline() # первая строка | head = pspipe.readline() # первая строка | ||
Строка 253: | Строка 259: | ||
app.exec_loop() | app.exec_loop() | ||
− | [[Изображение: | + | [[Изображение:Img 80 99 2.jpg|thumb|400px|Рисунок 4. Ну, нравится мне стиль Redmond – ничего с собой |
поделать не могу…]] | поделать не могу…]] | ||
Текущая версия на 07:12, 13 октября 2023
|
|
|
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
УЧЕБНИК Python
ПРОГРАММИРОВАНИЕ СЦЕНАРИЕВ
Содержание |
[править] Уроки Python
ЧАСТЬ 6
Теперь, когда мы научились обрабатывать строки, самое время показать наше умение другим. Но кто будет смотреть сценарий «без лица», пусть даже в Konsole с красивым прозрачным фоном? Для тех, кто не Квентин Тарантино, Сергей Супрунов покажет, как создаются на Python графические интерфейсы.
Чем больше работаешь с Python, тем сильнее ощущаешь его мощь и гибкость. Порой кажется, что для этого языка нет ничего невозможного. Это же можно отнести и к разработке графического интерфейса пользователя (хотя здесь Python просто использует возможности мощных библиотек). Как вы увидите, Python и в этом вопросе сохраняет простоту и эффективность, становясь весьма удобным инструментом для решения таких задач, как создание «обёрток» к различным консольным утилитам, разработка графических конфигураторов для ваших любимых инструментов, проектирование прототипов программ (куда проще за пару дней согласовать с заказчиком все «интерфейсные» моменты разрабатываемого проекта, меняя внешний вид прямо на переговорах, чем спустя месяцы напряжённой работы переделывать многомегабайтный проект на C++, только лишь потому, что заказчик счёл интерфейс слишком сложным для освоения), и т.д. Кстати, инсталлятор Gentoo, появившийся в версии 2006.0 и наделавший столько шума, тоже написан на Python.
Для Python разработано множество инструментов, отличающихся по гибкости, сложности, степени интеграции с вашим окружением. В рамках одного урока сложно рассмотреть всё это многообразие даже в общих чертах. Поэтому мы ограничимся кратким знакомством с модулем Tkinter и «привязками» PyQt и PyGTK.
Есть ещё достаточно мощный и переносимый модуль wxPython, являющийся привязкой к графической библиотеке wxWidgets, который тоже заслуживает внимания, но думаю, вы сможете разобраться с ним самостоятельно.
Начнём со старого доброго Tkinter, который, несмотря на некоторую «неказистость» и плохую интеграцию с системой, всё же остаётся стандартным модулем, входящим в поставку практически всех дистрибутивов. К тому же его простота – идеальная особенность для учебных целей. А разобравшись с ним, вы без труда освоите и другие инструменты.
[править] Очарование простоты
Проверить наличие Tkinter в вашем дистрибутиве достаточно просто (он должен быть, но всякое случается): запустите Python и выполните команду import Tkinter (обратите внимание на заглавную первую букву). Если вам не повезло и вы увидели сообщение об ошибке, придётся установить этот модуль отдельно. Проконсультируйтесь с вашим менеджером пакетов, не знает ли он случайно про Tkinter (имя пакета, в отличие от модуля, обычно записывается только маленькими буквами). Если он окажется из партизанской семьи, то прямая дорога вам на http://www.python.org/ (который с новым дизайном смотрится очень даже приятно).
Разобравшись с модулем, приступим сразу к серьёзной работе. В качестве примера выберем такую задачу: разработать графический интерфейс для просмотра man-страниц. Хорош он тем, что логика предельно проста, и нам почти не придётся отвлекаться от основной задачи. Итак, сразу код (по мере необходимости, будем прерывать его некоторыми пояснениями):
#!/usr/bin/Python # -*- coding: utf-8 -*- import os, re from Tkinter import *
Здесь мы объявили кодировку нашей локали и подключили необходимые для работы модули (не забывайте следить за регистром символов). Далее опишем класс, который будет отвечать за работу нашего приложения. Использование объектного подхода позволит в дальнейшем, если потребуется, легко создавать модифицированные приложения на базе этого класса или интегрировать его функциональность в другие объекты:
class ManReader: def getman(self, manpage, sn): bschar = '\b' tmp = os.popen('man %s %s 2>/dev/null' % (sn, manpage)).read() if tmp: tmp = re.sub(r'(.)%c\1' % bschar, r'\1', tmp) tmp = tmp.replace('_%c' % bschar, '') else: tmp = 'Page "%s" in section "%s" not found' % (manpage, sn or 'Auto') return tmp
Метод с украинским именем getman() отвечает за то, чтобы вернуть запрошенную man-страницу в виде текстовой переменной. Для этого используем уже знакомую нам функцию popen() модуля os. Нужно учитывать, что man-страницы могут содержать специальное форматирование: подсветку и подчёркивание. Чтобы не усложнять наш пример, мы просто избавляемся от ненужных символов, оставляя чистый текст. Пожалуй, нужно пояснить, как мы это делаем.
Если вы посмотрите на результат работы команды man в «натуральном» виде, например, сохранив его в файл, то заметите, что яркость создаётся следующим приёмом: символ выводится, стирается символом «\b» (Backspace) и затем снова выводится. Подчёркивание достигается выводом и последующим стиранием символа «_». То есть вы можете увидеть что-то такое: N\bNA\bAM\bME\bE = NAME,_\b/_\be_\bt_\bc = /etc. С удалением подчёркиваний всё понятно. А вот для удаления «символов яркости» мы используем регулярное выражение, причём на первый фрагмент, взятый в скобки, мы можем в дальнейшем ссылаться с помощью \1. То есть регулярное выражение «(.)!\1» означает два одинаковых символа, разделённых восклицательным знаком. Мы же используем символ \b. Обратите внимание, что его нельзя указывать непосредственно в регулярном выражении, иначе он будет трактоваться как граница слова. Вернёмся к нашим «виджетам»:
def pressBtn(self): sn = sectno.get()[0] if sn == '-': sn = tx.delete(1.0, END) tx.insert(1.0, self.getman(ent.get(), sn))
Это – функция-обработчик нажатия на кнопку (которую мы пока не нарисовали). Ещё ничего не понятно, но мы вернёмся к ней чуть позже, а сейчас перейдем к самому важному методу нашего класса, собственно и рисующему рабочее окно. Разберём его подробнее:
def Drawface(self): global ent, tx, sectno
Объявляем некоторые переменные как глобальные, чтобы мы могли обращаться к ним из других функций (в нашем примере – из pressBtn).
win = Tk() win.title('Просмотрщик man-страниц')
Так мы создаём объект, который будет являться нашим рабочим окном. Заодно задаём ему заголовок.
sectno = StringVar() sectno.set('---Auto---')
В будущем нам понадобится эта переменная – она должна представлять собой особый объект, поэтому и создаём её как экземпляр класса Tkinter.StringVar().
fcmd = Frame(win) fcmd.pack(side=TOP, fill=X)
В основном окне создаём фрейм, который будет являться контейнером для элементов управления. Второй строчкой «упаковываем» его, т.е. указываем место расположения на главном окне. Параметры метода pack() означают: прикрепить элемент к верхнему краю (TOP) и растянуть по горизонтальной оси.
Здесь нужно сказать, что pack – не единственный метод упаковки в Tkinter. В ряде случаев удобнее использовать упаковку «по сетке» – grid (подробности можно узнать в документации). Приступаем к созданию графических элементов:
lbl1 = Label(fcmd, text='Read about ') lbl1.pack(side=LEFT)
Это – обычная текстовая метка. Она размещается во фрейме (первый аргумент метода) и упакована по левому краю.
ent = Entry(fcmd) ent.bind('<Return>', (lambda event: self.pressBtn())) ent.pack(side=LEFT)
Текстовое поле ввода также упаковываем слева, сразу после lbl1.
Метод bind() задаёт реакцию поля на нажатие клавиши [Enter] (a.k.a. Return) – будет вызван метод pressBtn().
lbl2 = Label(fcmd, text=' in section ') lbl2.pack(side=LEFT) slt = OptionMenu(fcmd, sectno, '---Auto---', '1 User Utilities', '2 System Calls', '3 Library Functions', '4 Devices & Kernel Interfaces', '5 File Formats', '6 Games', '7 Macros & SQL Commands', '8 System Utilities', '9 X Window', 'n Built-In commands', ) slt.pack(side=LEFT)
Ещё одна текстовая метка, и далее – выпадающий список. В нём мы перечисляем имеющиеся разделы справки, к которым будет относиться наш запрос.
btn1 = Button(fcmd, command=win.quit, text='Quit') btn1.pack(side=RIGHT) btn2 = Button(fcmd, command=self.pressBtn, text='Open') btn2.pack(side=RIGHT)
Две кнопки – завершающая работу и отображающая запрошенную man-страницу. Обратите внимание, что здесь упаковка выполняется по правому краю, т.е. Quit будет самой правой, а Open – чуть левее. Важнейший параметр – command, задает функцию-обработчик. В первом случае используется встроенный метод quit, завершающий работу, во втором – наш метод pressBtn. Обратите внимание, что здесь происходит не вызов метода, а даётся ссылка на него, т.е. имя указывается без скобок.
fview = Frame(win) fview.pack(side=BOTTOM, fill=BOTH, expand=YES) sb = Scrollbar(fview) tx = Text(fview, relief=SUNKEN) sb.config(command=tx.yview) tx.config(yscrollcommand=sb.set) sb.pack(side=RIGHT, fill=Y) tx.pack(side=TOP, expand=YES, fill=BOTH)
Во втором фрейме, который мы прикрепляем к нижнему краю и растягиваем во все стороны, заполняя всё доступное пространство, размещается текстовое поле, где мы будем отображать содержимое man-страницы. Поскольку последняя может быть достаточно длинной, понадобится скроллинг (элемент Scrollbar). Обратите внимание на то, как методами config() мы обеспечиваем взаимную привязку текстового поля и полосы прокрутки. Параметр relief в описании текстового поля задаёт вид рамки вокруг поля.
Настало время поговорить о pressBtn. Как вы видели, этот метод будет выполняться в двух случаях – по щелчку на кнопке Open и при нажатии [Enter] в поле ввода. Получив цифру раздела справки и очистив текущее содержимое поля tx от начала (1,0) до конца (END), вызываем метод getman() и вставляем результат в tx.
win.mainloop()
Всё выше было просто подготовкой. А вот этой командой мы запускаем наше окно в работу. С этого момента управление передаётся Tkinterобъекту, и влиять на его поведение можно только с помощью описанных ранее обработчиков событий.
if __name__ == '__main__': test = ManReader() test.Drawface()
Ну, это должно быть понятно – если скрипт запускается автономно, а не экспортируется в другой, то создаём объект нашего класса и запускаем его в работу.
Фух… Кажется, мы сделали это. Результат наших трудов можно наблюдать на рисунке (Рисунок 1). Как видите, «виджеты» имеют свой уникальный дизайн и будут резко выделяться на фоне остального интерфейса, внешний вид которого вы с такой любовью выбирали среди десятков различных стилей. Но это работает (причём одинаково) и в KDE, и в Gnome, и даже в Windows и Mac OS X.
Теперь, когда мы разобрались с основами, самое время перейти к «родным» для Linux-окружения средствам – PyQt и PyGTK. Прежде чем приступать к работе, проверьте, есть ли в вашей системе нужные модули.
[править] Пара слов про PyGTK
Мощь библиотеки GTK позволяет создавать таких «гигантов графики», как Gimp. Отрадно, что мы можем в значительной степени воспользоваться её возможностями и в сценариях Python. В каталоге /usr/share/doc/pygtk<версия>/examples вы найдёте массу примеров её использования. Здесь приведём простейший вариант:
#!/usr/bin/python # -*- coding: utf-8 -*- import gtk # Создаём основное окно win = gtk.Window() def main(): # Задаём параметры окна (размер, заголовок и т.д.) win.set_default_size(300, 50) win.set_border_width(10) win.connect('destroy', gtk.main_quit) win.set_title('Небольшой пример') txtvar = 'Библиотека ''GTK ''привносит в ''Python ''небывалую мощь и высокий уровень интеграции в среду Gnome.' # Текстовая метка – не забывайте применять метод show() к каждому объекту, чтобы он был видимым txt = gtk.Label(txtvar) txt.show() # Кнопка. На неё «привязываем» завершение работы btn = gtk.Button('Закрыть') btn.connect('pressed', lambda button: gtk.main_quit()) btn.show() # объект Window может содержать только один элемент, так что им будет HBox, # который служит контейнером для остальных box = gtk.HBox() box.pack_start(txt) box.pack_start(btn) win.add(box) box.show() win.show() gtk.main() main()
Результат представлен на рисунке 2.
[править] Фанатам KDE посвящается
Если для вас Linux не мыслим без KDE, то PyQt – как раз тот инструмент, который способен обеспечить «бесшовную» интеграцию ваших Python-сценариев с окружением рабочего стола. (Впрочем, Qt работает не только в Linux, так что ваши решения по-прежнему сохранят определённый уровень переносимости.) К тому же, для разработки интерфейса к вашим услугам Qt Designer. А создадим мы программу для просмотра запущенных в системе процессов. Итак, в путь!
[править] Делай «РАЗ»!
Первым делом, запустите Qt Designer и откройте новый проект типа Widget. Для кнопки создайте соединение с формой (Connect Signal/ Slots) и объявите новый слот, назвав его showPs. В дальнейшем это будет наш обработчик нажатия кнопки. Сохранив интерфейс (Рисунок 3) под именем psview.ui, нужно конвертировать его в Python-код:
$ pyuic psview.ui > psview.py
Теперь в psview.py описан класс, отвечающий за наш интерфейс. Если вы посмотрите на него, то увидите, что всё не намного сложнее, чем в Tkinter, так что при желании интерфейс можно создать и вручную.
[править] Делай «ДВА»!
Далее, нам нужно довести всё это до ума. Непосредственное редактирование созданного сценария – самое плохое решение, поскольку вы лишитесь возможности корректировать интерфейс в Qt Designer, т.к. все изменения при этом будут потеряны. Поэтому правильно будет оставить psview.py в неприкосновенном виде, а для работы описать ещё один класс на базе созданного, пользуясь возможностями наследования. Просто создать экземпляр класса Form1 тоже не совсем хорошо – ведь нам нужно будет изменить поведение класса, отредактировав обработчик нажатия кнопки. Полученный код с переопределённой функциейобработчиком будет выглядеть так:
#!/usr/bin/Python # -*- coding: utf-8 -*import os, sys # Импортируем модуль, созданный автоматически from psview import * class PsForm(Form1): # наследуем от Form1 def __init__(self): # Помните, что при наследовании инициализацию #- родительского класса нужно делать вручную? Form1.__init__(self) def showPs(self): # Формируем нужные ключи команды ps if self.radioButton1.isChecked(): all = 'a' else: all = # Выводимые поля описываются после ключа «o» #- Очень важно не допускать пробелов! fields = 'o' if self.checkBox1.isChecked(): fields += 'pid,' if self.checkBox2.isChecked(): fields += 'user,' if self.checkBox3.isChecked(): fields += 'stat,' if self.checkBox4.isChecked(): fields += 'command,' fields = fields[:-1] # последнюю запятую – долой! filter = self.lineEdit1.text() # Если есть фильтр, то заголовок придётся забирать #- отдельной командой (head – чтобы не выводить лишнее) if filter: cmd = 'ps %sx%s | grep %s | grep -v grep' % (all, fields, filter) head = os.popen('ps %s | head' % fields).readline() body = os.popen(cmd).read() else: cmd = 'ps %sx%s' % (all, fields) pspipe = os.popen(cmd) head = pspipe.readline() # первая строка body = pspipe.read() # всё остальное pspipe.close() self.tl_header.setText(head) self.te_body.setText(body) # Создаём объект-приложение app = QApplication(sys.argv) form = PsForm() app.setMainWidget(form) form.show() app.exec_loop()
Небольшое пояснение: чтобы при прокрутке заголовок был всегда на виду, мы вынесли его в отдельную текстовую метку (tl_header). Поскольку при использовании grep заголовок теряется, придётся приложить чуточку усилий, чтобы всё-таки обеспечить его вывод (см. фрагмент «if filter – else»).
[править] Делай «ТРИ»!
Всё! Можно запускать нашу оболочку, не забыв сделать скрипт исполняемым (Рисунок 4). Конечно, это не верх совершенства – из множества доступных полей поддерживаются только четыре, нет проверки выражения фильтра на безопасность (а что, если пользователь введёт «root; rm -Rf /»?). Впрочем, это беда любого графического интерфейса – неизбежная потеря функциональности и гибкости в угоду сомнительным удобствам. Тем не менее, наша задача была всё-таки в другом – показать пример разработки ГИП, с чем мы успешно справились.
Как видите, изложенное сегодня – всего лишь основа. Но, надеюсь, этого будет достаточно, чтобы приступить к быстрой и эффективной разработке графических интерфейсов. На этом мы завершаем «Уроки Python», но не прощаемся – со следующего номера начинается серия «Python для профессионалов», где мы поговорим о многопоточных приложениях, обработке сетевых протоколов, взаимодействии с СУБД и библиотеке Python Image Library.