Содержание


Обучение программированию в Linux на примере интегрированной среды разработки Geany

Часть 2. Работа в Geany с проектом

Comments

Серия контента:

Этот контент является частью # из серии # статей: Обучение программированию в Linux на примере интегрированной среды разработки Geany

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Обучение программированию в Linux на примере интегрированной среды разработки Geany

Следите за выходом новых статей этой серии.

В предыдущей статье рассматривалось, каким образом использование интегрированной среды Geany может помочь в процессе обучения программированию. Был разобран простой учебный пример на языке С. Надеюсь, что читатели оценили простоту и удобство среды программирования Geany как одного из средств обучения.

Как уже было сказано ранее, Geany поддерживает работу со многими языками программирования. В данной статье главное внимание будет уделено языку Python, который, к слову, многие образовательные методики рекомендуют в качестве первого и основного языка при обучении основам программирования. Почему именно Python? Его синтаксис не сложен, тексты программ легко читаются. Это объектно-ориентированный язык, но без излишней громоздкости, присущей, например, С++. В Python имеются все базовые программные конструкции (ветвление, циклы и т.п.), встроенная поддержка многочисленных простых и комплексных типов данных. И, наконец, он является интерпретируемым языком, что открывает богатые возможности для экспериментов. Знакомясь с Python'ом, люди начинают писать работающие программы уже после одного-двух часов обучения.

Писать на Python – это просто

Впрочем, хватит обобщённых фраз, перейдём к конкретным делам. Для доказательства того, что всё сказанное в предыдущем абзаце не было "пустой рекламной болтовнёй", мы напишем графическое объектно-ориентированное приложение. Да, вот так сразу, с чистого листа. Конечно, оно будет упрощённым до предела, и его интерфейс не восхитит своей изысканностью, но это завершённая, работающая программа.

Цель программы – обеспечить вывод списка файлов из каталога, задаваемого пользователем. Если список слишком длинный и в окне не умещается, то необходимо обеспечить возможность его прокрутки (скроллинга).

После запуска Geany мы почти наверняка увидим в рабочем окне исходный код предыдущего проекта, который в данный момент нам не нужен. От него можно избавиться без труда, инициализировав новый проект. Подробности этой операции были описаны в предыдущей статье. Кроме того, следует обратить внимание на то, что новый файл с требуемой подсветкой синтаксиса можно быстро открыть с помощью спускающегося меню, расположенного справа от кнопки "Создать новый файл" (первая кнопка слева на панели инструментов). Щёлкните по стрелке вниз, выберите пункт "Файл Python", и вы получите не только подсветку синтаксиса, но и шаблон главного модуля будущей программы, т.е. блок стартовых комментариев с информацией об авторских правах и определение базовой функции. Для "промышленной" программы это достойное начало, но у нас несколько другие цели, поэтому все автоматически созданные строки можно удалить без сомнений.

Hello, World!

Программа на языке Python может состоять из нескольких файлов-модулей. Вполне естественно, что разделение на модули определяется функциональностью. Начнём с основной части, так сказать, с ядра программы.

#!/usr/bin/python 
# -*- coding: utf-8 -*- 
import os 
from Tkinter import * 
from file_info import *

В первой строке объявляется полный путь к интерпретатору, который, собственно, и выполняет наше приложение. Далее определяется кодировка символов, используемая в данной программе (если я не ошибаюсь, UTF-8 стала стандартом для всех современных дистрибутивов). В следующих трёх строках выполняются операции импортирования из стандартных (установленных в составе основного комплекта) модулей Python'а. Первый способ import os позволяет обращаться к функциям модуля с указанием префикса "os.", что позволяет отличать "штатные" функции от тех, что определены пользователем. Модуль os предоставляет средства взаимодействия с операционной системой: работа с файлами, процессами и т.п.

После импортирования вторым способом функции из заданного модуля (в нашем случае Tkinter и file_info) можно использовать без каких бы то ни было префиксов; они становятся частью нашей программы. Здесь таится некоторая опасность: совпадающие имена функций и переменных замещаются импортируемыми без предупреждения.

Работаем с классами

Сразу определим класс списка файлов. Всё очень просто: ключевое слово class, имя класса и двоеточие. Двоеточием завершаются строки определений классов и функций (методов), а также строки стандартных конструкций языка (if – else, циклов). Теперь можно писать тело класса:

class ListFiles: 
  def getlist( self, pdir ): 
    if pdir: 
      tmplist = os.listdir( pdir ) 
    else: 
      tmplist = os.listdir( '.' ) 
    tmplist.sort() 
    listf = '' 
    for i in tmplist: 
      if pdir: 
        i = pdir + '/' + i 
      finfo = FileInfo( i ) 
      fsize = finfo.getSize() 
      listf = listf + i + fsize + '\n' 
    return listf

Тело класса начинается с определения функции getlist, которая получает список файлов каталога, путь к которому передаётся в параметре pdir, и формирует символьный массив (строку) для вывода средствами пользовательского интерфейса. Отметим обязательный первый параметр self – ссылка "на себя", т.е. на текущий объект класса. Для каждого метода класса первым, а иногда и единственным параметром непременно должен быть self.

Сразу выполняется проверка значения pdir. Если значение не пустое (имя каталога задано в виде строки символов), то локальной переменной tmplist присваивается результат выполнения стандартной функции listdir из модуля os, а именно: список имён файлов в заданном каталоге. Список аналогичен массиву в других языках программирования (C, Pascal и т.п.), поэтому в tmplist будет записано значение [ 'имя_файла1', 'имя_файла2', 'имя_файла3', ... ]. В данном случае список состоит из набора символьных строк, записываемых в одиночных кавычках, но, вообще говоря, списки могут содержать данные различных типов. Если pdir содержит пустую строку (имя каталога не было задано – это допустимо), то выполняется ветвь else конструкции проверки условия. Здесь tmplist присваивается список файлов из текущего каталога, передаваемого в функцию listdir в виде строки '.'. На этом конструкция проверки условия завершается, и я ещё раз напомню о важности возврата на предыдущий уровень отступов в исходном коде.

Следует отметить использование локальных переменных без предварительного объявления. Тип такой переменной определяется присваиваемыми данными. А поскольку мы уже знаем, что Python – язык объектно-ориентированный с концепцией "всё есть объект", то наша переменная tmplist является объектом типа "список" со всеми полагающимися атрибутами и методами. Сортировка полезна любому списку, и наш список имён файлов не исключение. Вызов метода соответствует общепринятому синтаксису: имя объекта, точка, имя метода – tmplist.sort().

Строка вывода

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

Начинается формирование с присваивания пустой строки listf=''. Здесь это необходимо, так как компоновка выполняется рекурсивно, и на первом шаге использование неинициализированной переменной приведёт к ошибке. Проход по списку tmplist осуществляется при помощи цикла for. На каждой итерации цикла очередное имя файла либо предваряется префиксом, взятым из pdir, если пользователь задал каталог, либо оставляется без изменений, если каталог не был задан, и по умолчанию принят текущий каталог программы. Следующая операция – создание объекта finfo класса (типа) FileInfo. Этот класс мы напишем несколько позже; он отвечает за получение информации о файле с именем, задаваемым при инициализации конкретного экземпляра. В нашем учебном примере мы считываем в переменную fsize строковое значение – это размер файла в байтах, преобразованный в символьный формат, или альтернативное сообщение в тех случаях, когда заданному имени соответствует не обычный файл, а каталог или другой объект файловой системы.

Последняя инструкция цикла добавляет имя текущего файла (i), его характеристику (fsize) и символ перехода на следующую строку '\n' к итоговой строке listf. После прохода по всем элементам списка и завершения цикла for получившаяся строка возвращается как результат выполнения функции getlist.

Наша следующая функция уместилась всего лишь на трёх строках:

  def clickButton( self ): 
    txt.delete( 1.0, END ) 
    txt.insert( 1.0, self.getlist( pdir.get() ) )

Общую логическую схему её работы можно понять: при щелчке по некой кнопке в каком-то текстовом поле сначала удаляется всё содержимое, затем в это поле выводится результат работы описанной выше функции getlist. Детали будут проясняться по мере нашего продвижения по исходному коду.

Создание пользовательского интерфейса

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

  def PutList( self ): 
    global pdir, txt 
    lswin = Tk() 
    lswin.title( 'Список файлов заданного каталога' ) 
 
    frmc = Frame( lswin ) 
    frmc.pack( side=TOP, fill=X ) 
    lb1 = Label( frmc, text='Введите имя каталога: ' ) 
    lb1.pack( side=LEFT ) 
    pdir = Entry( frmc ) 
    pdir.bind( '<Return>', (lambda event: self.clickButton()) ) 
    pdir.pack( side=LEFT ) 
    btn1 = Button( frmc, command=lswin.quit, text='Выход' ) 
    btn1.pack( side=RIGHT ) 
    btn2 = Button( frmc, command=self.clickButton, text='Вывод списка' ) 
    btn2.pack( side=RIGHT ) 
 
    frml = Frame( lswin ) 
    frml.pack( side=BOTTOM, fill=BOTH, expand=YES ) 
    scrlb = Scrollbar( frml ) 
    txt = Text( frml, relief=SUNKEN ) 
    scrlb.config( command=txt.yview ) 
    txt.config( yscrollcommand=scrlb.set ) 
    scrlb.pack( side=RIGHT, fill=Y ) 
    txt.pack( side=TOP, expand=YES, fill=BOTH ) 
 
    lswin.mainloop()

Переменные pdir и txt объявлены глобальными для того, чтобы обеспечить доступ к ним из других функций, например из функции clickButton. Далее создаётся главное рабочее окно lswin и определяется его заголовок.

Во второй части функции создаётся фрейм (область) frmc внутри главного окна. Метод pack позволяет определять расположение данного фрейма относительно границ родительского объекта. В данном случае фрейм frmc "привязывается" к верхней границе главного окна lswin и заполняет всё доступное пространство по оси Х, т.е. по горизонтали. В этой области мы разместим все элементы управления. Сначала текстовую надпись lb1 (тип Label), затем поле ввода pdir (тип Entry). Здесь метод pack будет сдвигать элемент влево до тех пор, пока остаётся свободное место, поэтому надпись вплотную придвинется к левой границе фрейма, а левая граница поля ввода пристыкуется к правой границе надписи. Просто и удобно, никакой возни с вычислением координат. Для поля ввода pdir используется ещё и метод bind, позволяющий установить связь клавиши Return (она же Enter) с событием "щелчок по кнопке". Специальная функция lambda позволяет сгенерировать ссылку на это событие. Проще говоря, как при щелчке по кнопке, так и при нажатии клавиши Enter будет вызываться один и тот же метод clickButton.

Далее определяются кнопки btn1 (завершение работы программы) и btn2 (вывод списка файлов), которые компонуются по правым границам (максимально сдвигаются вправо). Для кнопок самое важное – обработчик их нажатия или щелчка по ним – второй параметр command. При щелчке по btn1 вызывается встроенный метод quit (выход из программы), щелчок по кнопке btn2 активизирует метод clickButton из нашего класса.

Третья часть функции занимается созданием и оформлением фрейма вывода frml с привязкой к нижней границе главного окна и заполнением всего оставшегося доступного пространства по обеим осям (параметр fill=BOTH). Вдоль правой границы фрейма размещается панель прокрутки (скроллинга) для тех случаев, когда список файлов не умещается в области вывода. Большую часть фрейма займёт поле вывода текста txt, в котором мы, собственно, и будем наблюдать результаты работы программы. Значение параметра relief придаёт полю псевдообъёмный вид (здесь SUNKEN – утоплено). С помощью методов config устанавливается взаимосвязь размещения содержимого текстового поля и положения бегунка в панели прокрутки.

Последняя часть функции состоит всего из одной строки, которая инициализирует рабочий цикл окна, т.е. передаёт управление объекту lswin. Теперь мы можем управлять программой только с помощью описанных выше кнопок и поля ввода.

В самом конце файла-модуля запишем ещё один короткий блок кода:

if __name__ == '__main__': 
  test = ListFiles() 
  test.PutList()

Это не обязательно, если модуль предназначен исключительно для импорта в другие модули. Но наш модуль можно запустить и как самостоятельную программу – в этом случае создаётся объект нашего класса ListFiles и активизируется его основная функция. На этом ввод исходного кода данного модуля заканчивается, и необходимо сохранить его в файле gui_ls.py текущего проекта. Надеюсь, что вы не забыли, как это делается.

Модуль file_info

Итак, модуль создан, но проект ещё не готов к работе. Мы ссылались на импортируемый модуль file_info, но его ещё нужно написать. Вот этим мы сейчас и займёмся, повторив процедуру создания нового файла с указанием типа "Файл Python". Снова удалим предлагаемую заготовку и введём следующий код:

#!/usr/bin/python 
# -*- coding: utf-8 -*- 
import os 
from stat import * 
 
class FileInfo: 
  def __init__( self, fname ): 
    self.file_name = fname 
    self.file_size = '' 
  def getSize( self ): 
    mode = os.stat( self.file_name )[ST_MODE] 
    if S_ISREG( mode ): 
      n_size = os.stat( self.file_name )[ST_SIZE] 
      self.file_size = '\t\t\t\t' + n_size.__str__() 
    elif S_ISDIR( mode ): 
      self.file_size = '\t\t\t\t' + 'каталог' 
    else: 
      self.file_size = '\t\t\t\t' + 'другой объект ФС' 
    return self.file_size

Первые три строки абсолютно идентичны строкам из предыдущего модуля, а в четвёртой строке импортируется всё из модуля stat, который обеспечивает получение информации о состоянии объектов файловой системы.

Далее определяется класс FileInfo, отличительной особенностью которого является наличие специального метода __init__(). В терминологии объектно-ориентированного программирования это конструктор класса, выполняемый автоматически при создании каждого нового экземпляра. Главная задача конструктора – инициализация атрибутов (внутренних переменных), обозначенных обязательным префиксом self. В данном случае при создании экземпляра ему передаётся параметр fname, который конструктор использует для инициализации атрибута self.file_name. Атрибуту self.file_size присваивается пустая строка ''.

Кроме конструктора наш класс содержит только один метод getSize. В нём определяется характеристика файла mode посредством вызова функции считывания состояния файла os.stat. После этого, в зависимости от полученной характеристики, выполняются соответствующие операции. Если это обычный файл (S_ISREG), то с помощью той же функции os.stat считывается его размер в байтах, который затем преобразуется в символьную форму с помощью встроенной функции n_size.__str__() и записывается в атрибут self.file_size с предваряющими символами табуляции, необходимыми для отделения при выводе столбца имён файлов от столбца их характеристик. Если это каталог (S_ISDIR), то мы так и запишем в атрибуте self.file_size. Во всех прочих случаях даём обобщённую характеристику 'другой объект ФС' (ФС – файловая система). После того как характеристика сформирована в виде строки, функция возвращает это значение.

Стартовый модуль (заканчиваем проект)

Чтобы придать проекту завершённый вид, напишем основной стартовый модуль программы, вынесенный в отдельный файл. Исходный код в нём краток и очевиден:

#!/usr/bin/python 
# -*- coding: utf-8 -*- 
from gui_ls import * 
 
test = ListFiles() 
test.PutList()

Надеюсь, что здесь всё понятно без пояснений. Скажу лишь, что необходимо сохранить этот код в файле ls_main.py. Вот теперь проект завершён и готов к работе (рисунки1 и 2).

Рисунок 1. Исходный код модуля с отображением тэгов
Рисунок 1. Исходный код модуля с отображением тэгов
Рисунок 1. Исходный код модуля с отображением тэгов
Рисунок 2. Общий вид с отображением состава проекта
Рисунок 2. Общий вид с отображением состава проекта
Рисунок 2. Общий вид с отображением состава проекта

Запускаем программу

Осталось только проверить, как работает наша программа. Для этого перейдите в модуль запуска ls_main.py (который введён последним и отображён на рисунке 2) и воспользуйтесь кнопкой пуска (шестерёнка с треугольником внутри) на панели инструментов, или быстрой клавишей F5, или пунктами меню "Сборка" –> "Выполнить". В появившемся окне сначала попробуем вывод по умолчанию, т.е. не вводя никаких данных, просто щёлкнем по кнопке "Вывод списка" или нажмём клавишу Enter. Результат показан на рисунке 3.

Рисунок 3. Вывод по умолчанию без введённых данных
Рисунок 3. Вывод по умолчанию без введённых данных
Рисунок 3. Вывод по умолчанию без введённых данных

Теперь в текстовом поле ввода наберём полное имя любого каталога, например /usr/local/bin и получим следующий список файлов (рисунок 4).

Рисунок 4. Список файлов из заданного каталога
Рисунок 4. Список файлов из заданного каталога
Рисунок 4. Список файлов из заданного каталога

Заключение

Итак, мы убедились, что в среде разработки Geany без труда можно вести проект, состоящий из нескольких файлов, а язык Python существенно облегчает труд программиста. Теперь вы сами сможете расширить функциональность нашей простенькой программы, добавляя собственные модули.

В следующей статье цикла будет рассматриваться работа с языком программирования FreePascal в среде разработки Geany.


Ресурсы для скачивания


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=456776
ArticleTitle=Обучение программированию в Linux на примере интегрированной среды разработки Geany: Часть 2. Работа в Geany с проектом
publish-date=12152009