Журнал LinuxFormat - перейти на главную

Бои за Авдеевку 2023

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
м (Перенес рисунок и подправил форматирование первых листингов)
м (восстановление кавычек в коде AWB)
Строка 20: Строка 20:
 
Проверить наличие ''Tkinter'' в вашем дистрибутиве достаточно просто (он должен быть, но всякое случается): запустите ''Python'' и выполните команду import ''Tkinter'' (обратите внимание на заглавную первую букву). Если вам не повезло и вы увидели сообщение об ошибке, придётся установить этот модуль отдельно. Проконсультируйтесь с вашим менеджером пакетов, не знает ли он случайно про ''Tkinter'' (имя пакета, в отличие от модуля, обычно записывается только маленькими буквами). Если он окажется из партизанской семьи, то прямая дорога вам на http://www.python.org/ (который с новым дизайном смотрится очень даже приятно).
 
Проверить наличие ''Tkinter'' в вашем дистрибутиве достаточно просто (он должен быть, но всякое случается): запустите ''Python'' и выполните команду import ''Tkinter'' (обратите внимание на заглавную первую букву). Если вам не повезло и вы увидели сообщение об ошибке, придётся установить этот модуль отдельно. Проконсультируйтесь с вашим менеджером пакетов, не знает ли он случайно про ''Tkinter'' (имя пакета, в отличие от модуля, обычно записывается только маленькими буквами). Если он окажется из партизанской семьи, то прямая дорога вам на http://www.python.org/ (который с новым дизайном смотрится очень даже приятно).
  
[[Изображение:Img_80_98_2.jpg|thumb|400px|Рисунок 1. Tkinter – лучший способ сделать не так, как у других!]]
+
[[Изображение:Img 80 98 2.jpg|thumb|400px|Рисунок 1. Tkinter – лучший способ сделать не так, как у других!]]
  
 
Разобравшись с модулем, приступим сразу к серьёзной работе. В качестве примера выберем такую задачу: разработать графический интерфейс для просмотра man-страниц. Хорош он тем, что логика предельно проста, и нам почти не придётся отвлекаться от основной задачи. Итак, сразу код (по мере необходимости, будем прерывать его некоторыми пояснениями):
 
Разобравшись с модулем, приступим сразу к серьёзной работе. В качестве примера выберем такую задачу: разработать графический интерфейс для просмотра man-страниц. Хорош он тем, что логика предельно проста, и нам почти не придётся отвлекаться от основной задачи. Итак, сразу код (по мере необходимости, будем прерывать его некоторыми пояснениями):
Строка 38: Строка 38:
 
     tmp = os.popen('man %s %s 2>/dev/null' % (sn, manpage)).read()
 
     tmp = os.popen('man %s %s 2>/dev/null' % (sn, manpage)).read()
 
     if tmp:
 
     if tmp:
       tmp = re.sub(r’(.)%c\1’ % bschar, r’\1’, tmp)
+
       tmp = re.sub(r'(.)%c\1' % bschar, r'\1', tmp)
       tmp = tmp.replace(‘_%c’ % bschar, ‘’)
+
       tmp = tmp.replace('_%c' % bschar, '')
 
     else:
 
     else:
       tmp = ‘Page “%s” in section %s” not found’ % (manpage, sn or ‘Auto’)
+
       tmp = 'Page "%s" in section "%s" not found' % (manpage, sn or 'Auto')
 
     return tmp
 
     return tmp
 
</source>
 
</source>
Строка 51: Строка 51:
 
  def pressBtn(self):
 
  def pressBtn(self):
 
  <nowiki>sn = sectno.get()[0]</nowiki>
 
  <nowiki>sn = sectno.get()[0]</nowiki>
  if sn == -: 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))
Строка 63: Строка 63:
  
 
  win = Tk()
 
  win = Tk()
  win.title(‘Просмотрщик man-страниц’)
+
  win.title('Просмотрщик man-страниц')
  
 
Так мы создаём объект, который будет являться нашим рабочим окном. Заодно задаём ему заголовок.
 
Так мы создаём объект, который будет являться нашим рабочим окном. Заодно задаём ему заголовок.
  
 
  sectno = StringVar()
 
  sectno = StringVar()
  sectno.set(---Auto---)
+
  sectno.set('---Auto---')
  
 
В будущем нам понадобится эта переменная – она должна представлять собой особый объект, поэтому и создаём её как экземпляр класса '''Tkinter.StringVar()'''.
 
В будущем нам понадобится эта переменная – она должна представлять собой особый объект, поэтому и создаём её как экземпляр класса '''Tkinter.StringVar()'''.
Строка 79: Строка 79:
 
Здесь нужно сказать, что '''pack''' – не единственный метод упаковки в T''kinter''. В ряде случаев удобнее использовать упаковку «по сетке» – '''grid''' (подробности можно узнать в документации). Приступаем к созданию графических элементов:
 
Здесь нужно сказать, что '''pack''' – не единственный метод упаковки в T''kinter''. В ряде случаев удобнее использовать упаковку «по сетке» – '''grid''' (подробности можно узнать в документации). Приступаем к созданию графических элементов:
  
  lbl1 = Label(fcmd, text=’Read about )
+
  lbl1 = Label(fcmd, text='Read about ')
 
  lbl1.pack(side=LEFT)
 
  lbl1.pack(side=LEFT)
  
Строка 85: Строка 85:
  
 
  ent = Entry(fcmd)
 
  ent = Entry(fcmd)
  <nowiki>ent.bind(<Return>, (lambda event: self.pressBtn()))</nowiki>
+
  <nowiki>ent.bind('<Return>', (lambda event: self.pressBtn()))</nowiki>
 
  ent.pack(side=LEFT)
 
  ent.pack(side=LEFT)
  
Строка 92: Строка 92:
 
Метод '''bind()''' <nowiki>задаёт реакцию поля на нажатие клавиши [Enter] (a.k.a. Return) – будет вызван метод </nowiki>'''pressBtn().'''
 
Метод '''bind()''' <nowiki>задаёт реакцию поля на нажатие клавиши [Enter] (a.k.a. Return) – будет вызван метод </nowiki>'''pressBtn().'''
  
  lbl2 = Label(fcmd, text=in section )
+
  lbl2 = Label(fcmd, text=' in section ')
 
  lbl2.pack(side=LEFT)
 
  lbl2.pack(side=LEFT)
 
  slt = OptionMenu(fcmd, sectno,
 
  slt = OptionMenu(fcmd, sectno,
  ---Auto---,
+
  '---Auto---',
  ‘1 User Utilities’,
+
  '1 User Utilities',
  ‘2 System Calls’,
+
  '2 System Calls',
  ‘3 Library Functions’,
+
  '3 Library Functions',
  ‘4 Devices & Kernel Interfaces’,
+
  '4 Devices & Kernel Interfaces',
  ‘5 File Formats’,
+
  '5 File Formats',
  ‘6 Games’,
+
  '6 Games',
  ‘7 Macros & SQL Commands’,
+
  '7 Macros & SQL Commands',
  ‘8 System Utilities’,
+
  '8 System Utilities',
  ‘9 X Window’,
+
  '9 X Window',
  ‘n Built-In commands’,
+
  'n Built-In commands',
 
  )
 
  )
 
   
 
   
Строка 112: Строка 112:
 
Ещё одна текстовая метка, и далее – выпадающий список. В нём мы перечисляем имеющиеся разделы справки, к которым будет относиться наш запрос.
 
Ещё одна текстовая метка, и далее – выпадающий список. В нём мы перечисляем имеющиеся разделы справки, к которым будет относиться наш запрос.
  
  btn1 = Button(fcmd, command=win.quit, text=’Quit’)
+
  btn1 = Button(fcmd, command=win.quit, text='Quit')
 
  btn1.pack(side=RIGHT)
 
  btn1.pack(side=RIGHT)
  btn2 = Button(fcmd, command=self.pressBtn, text=’Open’)
+
  btn2 = Button(fcmd, command=self.pressBtn, text='Open')
 
  btn2.pack(side=RIGHT)
 
  btn2.pack(side=RIGHT)
  
Строка 136: Строка 136:
 
Всё выше было просто подготовкой. А вот этой командой мы запускаем наше окно в работу. С этого момента управление передаётся ''Tkinterо''бъекту, и влиять на его поведение можно только с помощью описанных ранее обработчиков событий.
 
Всё выше было просто подготовкой. А вот этой командой мы запускаем наше окно в работу. С этого момента управление передаётся ''Tkinterо''бъекту, и влиять на его поведение можно только с помощью описанных ранее обработчиков событий.
  
  if __name__ == ‘__main__’:
+
  if __name__ == '__main__':
 
  test = ManReader()
 
  test = ManReader()
 
  test.Drawface()
 
  test.Drawface()
Строка 189: Строка 189:
 
Результат представлен на рисунке 2.
 
Результат представлен на рисунке 2.
  
[[Изображение:Img_80_98_1.jpg|left|thumb|400px|Рисунок 2. Именно так вы и должны представлять себе GTK-
+
[[Изображение:Img 80 98 1.jpg|left|thumb|400px|Рисунок 2. Именно так вы и должны представлять себе GTK-
 
приложение.]]
 
приложение.]]
  
Строка 195: Строка 195:
 
Если для вас Linux не мыслим без KDE, то ''PyQt ''– как раз тот инструмент, который способен обеспечить «бесшовную» интеграцию ваших ''Pythonс''ценариев с окружением рабочего стола. (Впрочем, ''Qt ''работает не только в Linux, так что ваши решения по-прежнему сохранят определённый уровень переносимости.) К тому же, для разработки интерфейса к вашим услугам ''Qt Designer''. А создадим мы программу для просмотра запущенных в системе процессов. Итак, в путь!
 
Если для вас Linux не мыслим без KDE, то ''PyQt ''– как раз тот инструмент, который способен обеспечить «бесшовную» интеграцию ваших ''Pythonс''ценариев с окружением рабочего стола. (Впрочем, ''Qt ''работает не только в Linux, так что ваши решения по-прежнему сохранят определённый уровень переносимости.) К тому же, для разработки интерфейса к вашим услугам ''Qt Designer''. А создадим мы программу для просмотра запущенных в системе процессов. Итак, в путь!
  
[[Изображение:Img_80_99_1.jpg|thumb|400px|Рисунок 3. Мышкой влево, мышкой вправо – а зачем вам
+
[[Изображение:Img 80 99 1.jpg|thumb|400px|Рисунок 3. Мышкой влево, мышкой вправо – а зачем вам
 
вообще клавиатура?]]
 
вообще клавиатура?]]
  
Строка 220: Строка 220:
 
  <nowiki># </nowiki>Формируем нужные ключи команды ps
 
  <nowiki># </nowiki>Формируем нужные ключи команды ps
 
  if self.radioButton1.isChecked():
 
  if self.radioButton1.isChecked():
  all = ‘a’
+
  all = 'a'
 
  else:
 
  else:
  all = ‘’
+
  all = ''
 
  <nowiki># Выводимые поля описываются после ключа «o»</nowiki>
 
  <nowiki># Выводимые поля описываются после ключа «o»</nowiki>
 
  <nowiki>#- Очень важно не допускать пробелов!</nowiki>
 
  <nowiki>#- Очень важно не допускать пробелов!</nowiki>
  fields = ‘o’
+
  fields = 'o'
 
  if self.checkBox1.isChecked():
 
  if self.checkBox1.isChecked():
  fields += ‘pid,
+
  fields += 'pid,'
 
  if self.checkBox2.isChecked():
 
  if self.checkBox2.isChecked():
  fields += ‘user,
+
  fields += 'user,'
 
  if self.checkBox3.isChecked():
 
  if self.checkBox3.isChecked():
  fields += ‘stat,
+
  fields += 'stat,'
 
  if self.checkBox4.isChecked():
 
  if self.checkBox4.isChecked():
  fields += ‘command,
+
  fields += 'command,'
 
  <nowiki>fields = fields[:-1] # </nowiki>последнюю запятую – долой!
 
  <nowiki>fields = fields[:-1] # </nowiki>последнюю запятую – долой!
 
  filter = self.lineEdit1.text()
 
  filter = self.lineEdit1.text()
Строка 239: Строка 239:
 
  <nowiki>#- отдельной командой (head – чтобы не выводить лишнее)</nowiki>
 
  <nowiki>#- отдельной командой (head – чтобы не выводить лишнее)</nowiki>
 
  if filter:
 
  if filter:
  cmd = ‘ps %sx%s | grep %s | grep -v grep’ % (all, fields,
+
  cmd = 'ps %sx%s | grep %s | grep -v grep' % (all, fields,
 
  filter)
 
  filter)
  head = os.popen(‘ps %s | head’ % fields).readline()
+
  head = os.popen('ps %s | head' % fields).readline()
 
  body = os.popen(cmd).read()
 
  body = os.popen(cmd).read()
 
  else:
 
  else:
  cmd = ‘ps %sx%s’ % (all, fields)
+
  cmd = 'ps %sx%s' % (all, fields)
 
  pspipe = os.popen(cmd)
 
  pspipe = os.popen(cmd)
 
  head = pspipe.readline() # первая строка
 
  head = pspipe.readline() # первая строка
Строка 258: Строка 258:
 
  app.exec_loop()
 
  app.exec_loop()
  
[[Изображение:Img_80_99_2.jpg|thumb|400px|Рисунок 4. Ну, нравится мне стиль Redmond – ничего с собой
+
[[Изображение:Img 80 99 2.jpg|thumb|400px|Рисунок 4. Ну, нравится мне стиль Redmond – ничего с собой
 
поделать не могу…]]
 
поделать не могу…]]
  

Версия 16:36, 27 апреля 2008

УЧЕБНИК 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/ (который с новым дизайном смотрится очень даже приятно).

(thumbnail)
Рисунок 1. Tkinter – лучший способ сделать не так, как у других!

Разобравшись с модулем, приступим сразу к серьёзной работе. В качестве примера выберем такую задачу: разработать графический интерфейс для просмотра man-страниц. Хорош он тем, что логика предельно проста, и нам почти не придётся отвлекаться от основной задачи. Итак, сразу код (по мере необходимости, будем прерывать его некоторыми пояснениями):

 #!/usr/bin/Python
 # -*- coding: utf-8 -*i</nowiki>mport 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.

(thumbnail)
Рисунок 2. Именно так вы и должны представлять себе GTK- приложение.

Фанатам KDE посвящается

Если для вас Linux не мыслим без KDE, то PyQt – как раз тот инструмент, который способен обеспечить «бесшовную» интеграцию ваших Pythonсценариев с окружением рабочего стола. (Впрочем, Qt работает не только в Linux, так что ваши решения по-прежнему сохранят определённый уровень переносимости.) К тому же, для разработки интерфейса к вашим услугам Qt Designer. А создадим мы программу для просмотра запущенных в системе процессов. Итак, в путь!

(thumbnail)
Рисунок 3. Мышкой влево, мышкой вправо – а зачем вам вообще клавиатура?

Делай «РАЗ»!

Первым делом, запустите 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()
(thumbnail)
Рисунок 4. Ну, нравится мне стиль Redmond – ничего с собой поделать не могу…

Небольшое пояснение: чтобы при прокрутке заголовок был всегда на виду, мы вынесли его в отдельную текстовую метку (tl_header). Поскольку при использовании grep заголовок теряется, придётся приложить чуточку усилий, чтобы всё-таки обеспечить его вывод (см. фрагмент «if filter – else»).

Делай «ТРИ»!

Всё! Можно запускать нашу оболочку, не забыв сделать скрипт исполняемым (Рисунок 4). Конечно, это не верх совершенства – из множества доступных полей поддерживаются только четыре, нет проверки выражения фильтра на безопасность (а что, если пользователь введёт «root; rm -Rf /»?). Впрочем, это беда любого графического интерфейса – неизбежная потеря функциональности и гибкости в угоду сомнительным удобствам. Тем не менее, наша задача была всё-таки в другом – показать пример разработки ГИП, с чем мы успешно справились.

Как видите, изложенное сегодня – всего лишь основа. Но, надеюсь, этого будет достаточно, чтобы приступить к быстрой и эффективной разработке графических интерфейсов. На этом мы завершаем «Уроки Python», но не прощаемся – со следующего номера начинается серия «Python для профессионалов», где мы поговорим о многопоточных приложениях, обработке сетевых протоколов, взаимодействии с СУБД и библиотеке Python Image Library.

Персональные инструменты
купить
подписаться
Яндекс.Метрика