17 июля, 2011

Python GTK (PyGTK) / Пишем Hello World

Hello world

В этой статье описывается процесс создания простой GUI-программы на Python с использованием библиотеки PyGTK. Мы не будем использовать Glade (но процесс создания интерфейсом с Glade я все же опишу в следующих статьях) и какие-либо другие сторонние библиотеки или конструкторы интерфейсов, а, наоборот, опишем его непосредственно в коде программы. Первым делом мы создадим обычное окошко со стандартным размером (200x200, на скриншоте справа). Оно будет настолько банальным, что его даже нельзя будет закрыть, нажав на крестик, а придется задействовать CTRL+C в консоле. Далее немного усложним полученный результат (скриншот ниже, под катом). Приступим.

Первоначально скопируйте код ниже в свой любимый редактор, сохранив файл, например, как helloworld.py, а потом мы его детально разберем.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Импортирование библиотек, необходимых для работы
import pygtk
pygtk.require('2.0')
import gtk

class helloworld:
	# Этот метод вызывается при инициализации класса.
	def __init__(self):
		# Создание нового окна
		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
		# Отображение нового окна
		self.window.show()

	def main(self):
		gtk.main()

if __name__ == "__main__":
	helloworld = helloworld()
	helloworld.main()

А теперь по-порядку.

if __name__ == "__main__":
	helloworld = helloworld()
	helloworld.main()

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

>>> import helloworld
>>> helloworld.__name__
'helloworld'

А если запускаем модуль как отдельную программу, то есть, например, используя команду python helloworld.py, то атрибуту __name__ этого модуля будет присвоено значение __main__. Таким образом, мы сможем импортировать наш helloworld-модуль из другого модуля, выполнив инициализацию основного класса и, соответственно, отображение окна, в любом подходящем для нас месте.

self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)

Здесь мы создаем новое окно. Константы gtk.WINDOW_TOPLEVEL или gtk.WINDOW_POPUP определяют тип окна:

gtk.WINDOW_TOPLEVEL Окно, не имеющее родительских окон и обычно имеющие оформление, задаваемое оконным менеджером. Используется в качестве основного окна и диалогов.
gtk.WINDOW_POPUP Окно такого типа игнорируется оконным менеджером и не имеет оформления. Используется для меню и всплывающих подсказок.
self.window.show()

Здесь, при помощи метода show(), который есть у каждого PyGTK виджета (а окно им также является), мы показываем наше окно.

def main(self):
	gtk.main()

Здесь мы задаем метод main(), вызывающий main()-функцию PyGTK, запускающую основной цикл обработки событий GTK+, необходимый для обработки нажатий клавиш клавиатуры и мыши, а также событий окна(например, закрытие, сворачивание и так далее).

Вот мы и разобрались с тем, что, возможно, несколько минут назад казалось непонятным. Приступим к запуску программы. Открываем консоль, переходим в папку, куда был сохранен скрипт (cd /путь/) и вводим команду python helloworld.py.

Появится заветное окошко. После того как вы вдоволь насладитесь своей, возможно, первой GUI-программой на Python, вам снова придется перейти в консоль и нажать CTRL+C (как я отметил ранее, мы еще не научили нашу программу закрываться по нажатию на крестик).

Теперь немного модифицируем полученный результат и разберемся, что мы сделали.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Импортирование библиотек, необходимых для работы
import pygtk
pygtk.require('2.0')
import gtk

class HelloWorld:

	def hello(self, widget, data=None):
		self.window.set_title("Hello, user")

	def delete_event(self, widget, event, data=None):
		print "Вызван сигнал удаления"
		return False

	def destroy(self, widget, data=None):
		print "Вызван сигнал уничтожения"
		gtk.main_quit()

	def __init__(self):
		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)

		self.window.connect("delete_event", self.delete_event)
		self.window.connect("destroy", self.destroy)

		self.window.set_border_width(40)

		self.button = gtk.Button("Hello World")
		self.button.connect("clicked", self.hello, None)

		self.window.add(self.button)

		self.button.show()
		self.window.show()

	def main(self):
		gtk.main()

if __name__ == "__main__":
	hello = HelloWorld()
	hello.main()

Начнем разбираться:

self.window.set_border_width(40)

При помощи метода set_border_width() мы устанавливаем ширину окна.

self.window.connect("delete_event", self.delete_event)

Метод connect() связывает определенный сигнал (в данном случае, delete_event), отправляемый виджету, с обработчиком (то есть, с функцией или методом определенного объекта, в данном случае с методом delete_event()). Сигнал delete_event отправляется оконным менеджером (например, при нажатии на крестик или комбинации клавиш ALT+F4). Посмотрим на обработчик:

def delete_event(self, widget, event, data=None):
	print "Вызван сигнал удаления" # Это сообщение можно будет наблюдать в консоле после вызова метода.
	return False

В случае, если обработчик вернет FALSE, будет вызван другой сигнал, destroy, значения которого мы также коснемся ниже. Если наоборот, TRUE, то сигнал destroy вызван не будет. Это полезно для создания диалоговых окон, спрашивающий пользователя, действительно ли он хочет закрыть окно.

self.window.connect("destroy", self.destroy)

Здесь сигнал destroy связывается с методом destroy(), который и уничтожает окно:

def destroy(self, widget, data=None):
	print "Вызван сигнал уничтожения"
	gtk.main_quit()

Идем далее.

self.button = gtk.Button("Hello World")

Здесь, очевидно, мы создали кнопку с надписью "Hello World"!

self.button.connect("clicked", self.hello, None)

Здесь событие "кнопка нажата" связывается с методом hello():

def hello(self, widget, data=None):
	self.window.set_title("Hello, user")

Эта функция будет вызываться по нажатию клавиши "Hello world", меняя заголовок окна на "Hello, user" при помощи метода set_title().

self.window.add(self.button)

При помощи метода add() виджета "окно" мы добавляем на него кнопку, созданную ранее.

self.button.show()
self.window.show()

Здесь ничего объяснять не надо -- все вы уже знаете сами: у каждого PyGTK-виджета есть метод show(), который, собственно, и выводит наш виджет на экран. Помимо метода show(), существует и другой, show_all(), помимо самого виджета вызывающий еще и дочерние. Таким образом, достаточно было использовать метод show_all() виджета "window" для отображения и самого окна и кнопки, которая является дочерним виджетом.

Спасибо за внимание. Напомню, что оставлять отзывы можно в комментариях, отправлять на e-mail (i@daniil-r.ru).