Московский государственный институт
Электроники и Математики
(технический университет)
Кафедра ИКТ
КУРСОВАЯ РАБОТА
по дисциплине
«Аудио и видео средства»
Выполнили: __________________Зимин В.А.
________________Гришина О.А.
Проверил: _____________Кондрашов С. В.
Москва 2010 г
Оглавление
Оглавление 2
Цели и задачи проекта 3
Актуальность работы 3
Программные средства разработки 3
Язык программирования Python 4
PyScripter for Python 5
Glade 5
Описание проекта 6
Формат xml-файла 7
Алгоритм работы парсера xml-файла 8
Файл графического интерфейса в формате .glade 9
Алгоритм работы функциональной части программы 9
Интерфейс программы 10
Веб-программирование на Python 11
Проблемы переноса разработанной программы в веб-среду 11
Пример веб-программирования на Python 11
Планы на дальнейшую реализацию 13
Заключение 13
Приложение 1 14
Приложение 2 14
Приложение 3 16
Приложение 4 20
Приложение 5 22
Цели и задачи проекта
Целью данного проекта является разработка программного продукта, предоставляющего возможности на основании xml файла создавать тест и обрабатывать ответы на него. В тесте возможно использование вопросов следующих типов:
-
Короткий ответ
-
Одиночный выбор (single)
-
На соответствие (с использованием технологии drag & drop)
Актуальность работы
Создание программы для выполнения тестов и анализа их результатов является сложной, но в тоже время востребованной задачей. В основном это связано с тем, что программа должна анализировать входящий пакет данных и на их основании динамически создавать тест и обрабатывать результаты.
Программные средства разработки
Использованное программное обеспечения и программные средства:
-
Python (оф. сайт -- http://www.python.org/)
-
PyScripter for Python (оф. сайт -- http://code.google.com/p/pyscripter/)
-
Glade (оф. сайт -- http://glade.gnome.org/)
-
Дополнительные библиотеки:
-
GTK+ (оф. сайт -- http://www.gtk.org/)
-
PyGTK (оф. сайт -- http://www.pygtk.org/)
-
Pygobject (оф. сайт -- http://live.gnome.org/PyGObject)
-
Pycairo (оф. сайт -- http://cairographics.org/pycairo/)
-
Стандартная библиотека minidom
Основная работа велась на языке программирования Python в программном продукте PyScripter for Python. В программе Glade разрабатывался графический интерфейс программы.
Язык программирования Python
Python - высокоуровневый язык программирования общего назначения с акцентом на производительность разработчика и читаемость кода. Синтаксис ядра Python минималистичен. В то же время стандартная библиотека включает большой объём полезных функций.
Python поддерживает несколько парадигм программирования, в том числе структурное, объектно-ориентированное, функциональное, императивное и аспектно-ориентированное. Основные архитектурные черты — динамическая типизация, автоматическое управление памятью, полная интроспекция, механизм обработки исключений, поддержка многопоточных вычислений и удобные высокоуровневые структуры данных. Код в Python организовывается в функции и классы, которые могут объединяться в модули (которые в свою очередь могут быть объединены в пакеты).
Эталонной реализацией Python является интерпретатор CPython, поддерживающий большинство активно используемых платформ. Он распространяется свободно под очень либеральной лицензией, позволяющей использовать его без ограничений в любых приложениях, включая проприетарные. Есть реализации интерпретаторов для JVM (с возможностью компиляции), MSIL (с возможностью компиляции), LLVM и других. Проект PyPy предлагает реализацию Python на самом языке Python, что уменьшает затраты на изменения языка и постановку экспериментов над новыми возможностями.
Python — активно развивающийся язык программирования, новые версии (с добавлением/изменением языковых свойств) выходят примерно раз в два с половиной года. Вследствие этого и некоторых других причин на Python отсутствуют ANSI, ISO или другие официальные стандарты, их роль выполняет CPython.
PyScripter for Python
PyScripter является свободным программным обеспечением с открытым исходным кодом. Это интегрированная среда разработки (IDE) на языке Python, по функциональности конкурирующая с коммерческими Windows-средами разработки для других языков программирования.
Интерфейс программы выглядит следующим образом:
Рис 1. Интерфейс программы PyScripter
Glade
Glade — свободное приложение для визуального создания графических интерфейсов на основе GTK+. Описание визуально создаваемого разработчиком интерфейса сохраняется в файлах XML-формата GladeXML, которые затем могут быть подключены во время исполнения к программам с использованием библиотеки libglade. Таким образом, Glade можно применять для описания и создания графических интерфейсов в программах на различных языках.
Ранние версии позволяли также создавать шаблонные обработчики событий на языке С, но эту возможность было рекомендовано не использовать, так как она вела к появлению кода, который было очень сложно поддерживать и модифицировать. В версии 3 генерация кода убрана из программы вообще.
Интерфейс программы выглядит следующим образом:
Рис 2. Интерфейс программы Glade
Описание проекта
Код программы можно разделить на несколько блоков:
-
Парсер xml-файла
-
Графический интерфейс в формате .glade
-
Функциональная часть, отвечающая за выполнение следующих операций:
-
Определение типа вопроса и отображение его текста и ответов на него в соответствующем блоке программы
-
Реализация функции кнопок:
-
Отправить результаты (проверка ответов)
-
Выход
-
Обработка действий пользователя
-
Вывод результатов
Таким образом, программа работает следующим образом: пользователем загружается xml файл, имеющий определенную структуру, программа анализирует данный файл и получает из него все необходимые данные, которые заносятся в соответствующие переменные. Затем, создается окно программы, тут возможно использование дополнительных шаблонов или изменение существующего графического интерфейса без изменения кода самой программы. Далее выводятся вопросы и ответы на них, а также обрабатываются ответы пользователей.
Формат xml-файла
Структура вопроса типа single, одиночный выбор:
Блок-схема 1. Вопрос типа single
Структура вопроса типа text, короткий текстовый вопрос:
Блок-схема 2. Вопрос типа text
Структура вопроса типа box, вопрос на соответствие:
Блок-схема 3. Вопрос типа box
Листинг исходного xml-файла в Приложении 1.
Алгоритм работы парсера xml-файла
Листинга кода, отвечающего за разбор xml-файла в Приложении 2.
Блок-схема 4. Парсер
Файл графического интерфейса в формате .glade
Описание визуально создаваемого интерфейса сохраняется в файлах XML-формата, которые затем подключаются во время исполнения к программы.
Листинг кода файла, отвечающего за графический интерфейс в Приложении3.
Алгоритм работы функциональной части программы
Листинга кода, отвечающего за работу функциональной части программы в Приложении 4.
Блок-схема 5. Функциональная часть
Интерфейс программы
-
Рабочая область служит для непосредственного отображения текста вопросов и ответов. Включает в себя все статические и интерактивные графические элементы.
-
Кнопка «Отправить» позволяет передать ответы на вопросы на проверку и, следовательно, получить результаты, а кнопка «Закрыть» позволяет закрыть работающую программу.
-
Интерактивное поле ввода в вопросе с коротким текстовым ответом предназначено для того, чтобы пользователь непосредственно вводил ответ на вопрос. В проекте также используются другие интерактивные элементы, такие как кнопки.
Веб-программирование на Python
Язык программирования Python имеет возможности для разработки как серверной части веб-приложений, так и клиентской.
Программирование клиентских приложений включает в себя:
-
браузерное веб-программирование – взаимодействие с существующими браузерами и соответствующими им технологиями (http://wiki.python.org/moin/WebBrowserProgramming);
-
клиентское веб-программирование – программирование непосредственно клиентской части приложений (http://wiki.python.org/moin/WebClientProgramming);
-
программирование веб-сервисов – использование API-инструментов (http://wiki.python.org/moin/WebServices).
Проблемы переноса разработанной программы в веб-среду
При попытке перенести разработанное и описанное в рамках данной курсовой работы приложение в веб-среду, были выявлены следующие проблемы:
-
для веб-программирования на Python необходим набор библиотек, отличный от тех, которые были использованы в данной курсовой работе. Таким образом, для переноса программы в веб-среду, необходимо переработать существующий код и несколько изменить алгоритм работы;
-
отсутствие инструментов для конвертирования кода на языке Python, использующего стандартные библиотеки, в его веб-версию.
Отсюда следует сделать вывод, что программист, работающий с языком Python, должен твердо определиться с платформой, под которую он разрабатывает приложение.
Пример веб-программирования на Python
В данном примере используется реализация Python под названием PyJamas (официальный сайт -- http://pyjs.org/). Это средство, позволяющее веб-программисту писать код на Python, компилировать его в JavaScript и запускать в любом современном браузере, не задумываясь о совместимости.
PyJamas выполняет компиляцию Python в JavaScript, поэтому программисту при создании приложения для PyJamas не требуется особых знаний HTML/CSS/JS. Возможность внедрять в код JS-скрипты существует, но без нее можно обойтись. PyJamas предоставляет библиотеку классов, позволяющую задать внешний вид и поведение пользовательского интерфейса, путем создания экземпляров классов и заданием их свойств, связей и методов.
Рассмотрим пример реализации простого пользовательского интерфейса:
from pyjamas.ui.SimplePanel import SimplePanel
from pyjamas.ui.VerticalPanel import VerticalPanel
from labeledpanel import LabeledPanel
class Statistic(SimplePanel) :
def __init__(self,query,count,engrank,rusrank) :
SimplePanel.__init__(self)
v = VerticalPanel()
v.setWidth("100%")
v.setBorderWidth("1px")
v.add(LabeledPanel("Оценка, английский:",engrank))
v.add(LabeledPanel("Оценка, русский:",rusrank))
v.add(LabeledPanel("Предъявлений:",count))
v.add(LabeledPanel("Длина выборки:",query))
self.add(v)
Здесь используется элемент оформления VerticalPanel, в который добавляются четыре элемента вывода LabeledPanel, снабженных названием и переменной. При запуске приложения появится панель, разделенная на четыре строки, в каждой из которых выводится название и значение переменной:
Планы на дальнейшую реализацию
Так как любая система тестирования предоставляет огромное количество возможностей по работе с тестами и по их настройке, и с учетом того, что далеко не все из них были реализованы в данной программе, то планируется дальнейшее расширение функциональных возможностей, а так же добавление новых элементов навигации и поддержки пользователя.
Заключение
В ходе работы над проектом были изучены базовые методы работы в программных продуктах PyScripter for Python и Glade, принципы программирования на языке Python.
В результате чего, можно сделать вывод, что язык программирования Python не является наилучшим вариантом для реализации систем тестирования и других систем, подразумевающих большое количество интерактивных возможностей и динамическое построение интерфейса. Таким образом реализация простейшей функции drag&drop на данном языке требует весьма серьезной работы. Кроме того, следует отметить, что создание exe-файла и последующее его использование также вызывает сложности.
Приложение 1
Кто автор произведения «Евгений Онегин»?
Лермонтов
Пушкин
Грибоедов
Тютчев
Вычислите значение выражения: 2+2=
Четыре
Соотнесите город и герб, которому он принадлежит.
Изображение 1
Изображение 2
Изображение 3
Москва
Санкт-Петербург
Курск
Приложение 2
#Импорт стандартной библиотеки для работы с xml файлами
from xml.dom import minidom
dom = minidom.parse('test.xml')
dom2 = dom.getElementsByTagName("questions") # Получение из файла всех элементов с тегом
dom3 = dom.getElementsByTagName("answer") # Получение из файла всех элементов с тегом
k=0 # количество вопросов
l=0
z=0 #количество ответов
questions = [] # Список с вопросами
answers = [] # Список с ответами
get_tyre_ans = [] # Список типов вопросов
get_correct_num=[] # Список номеров ответов
number_of_answers = [] # список с количеством отвтеов на каждый вопрос
number_of_correct = [] # Список номеров правильных ответов ответов
# Вычисление количества вопросов
for node in dom2:
k = k+1
for i in range(0,k):
kkk = dom2[i] # Обращение к i-ому поддереву с тегом
i = i+1
m=0
for node in kkk.getElementsByTagName('answer'):
m = m+1 # количество ответов на данный вопрос
z=z+1
number_of_answers.append(m) # добавление в список m
# Определение правильных номеров ответов
for i in range(0,z):
ddd = dom3[i]
i = i+1
d = ddd.attributes["rating"] # получение всех элементов с тегом "rating"
if d.value == "0": # неправильный ответ
get_correct_num.append(0)
if d.value == "1": # правильный ответ
get_correct_num.append(1)
# Для реализации drag & drop
if d.value == "2":
get_correct_num.append(2)
if d.value == "3":
get_correct_num.append(3)
if d.value == "4":
get_correct_num.append(4)
# Создание списка правильных отвтеов
for i in range(0,z):
if get_correct_num[i] == 1:
number_of_correct.append(i)
if get_correct_num[i] == 2:
number_of_correct_drop.append(i)
if get_correct_num[i] == 3:
number_of_correct_drop.append(i)
if get_correct_num[i] == 4:
number_of_correct_drop.append(i)
else:
print ""
i=i+1
# Получение текста вопросов и определение их типа
for i in range(0,k):
dom1 = dom2[i]
a = dom1.attributes["id"]
i = i+1
dom.normalize()
if a.value == "text":
get_tyre_ans.append("text")
for node in dom2:
node = node.childNodes[0] # рассматриваем только ноды, содержащие вопрос
questions.append(node.nodeValue)
if a.value == "single":
get_tyre_ans.append("single")
if a.value == "box":
get_tyre_ans.append("box")
# Получение текста ответов
for node in dom3:
node = node.childNodes[0]
answers.append(node.nodeValue)
Приложение 3
400
500
True
Тестовая система Учебная
False
True
GDK_WINDOW_TYPE_HINT_DOCK
True
True
Вопрос №1
True
label
GTK_JUSTIFY_FILL
1
True
True
0
GTK_SHADOW_NONE
True
True
True
True
label_item
False
Правильный ответ!
1
2
False
Вы ответили неправильно, попытайтесь еще раз!
3
True
Вопрос №2
GTK_JUSTIFY_CENTER
4
True
0.43999999761581421
label
5
True
True
True
radiobutton
0
True
True
radiobutton4
False
Правильный ответ!
0.18000000715255737
15
1
6
True
True
True
radiobutton
0
True
True
radiobutton1
False
Правильный ответ!
1
7
True
True
True
radiobutton
0
True
True
radiobutton4
False
Правильный ответ!
1
8
True
True
True
radiobutton
0
True
True
radiobutton1
False
Правильный ответ!
1
9
False
Вы ответили неправильно, попытайтесь еще раз!
10
True
Вопрос №3
11
True
label
12
True
True
True
True
Отправить
0
True
True
True
Закрыть
0
1
13
Приложение 4
# Импорт библиотек для создания графического интерфейса, необходима предварительная установка
import pygtk
pygtk.require('2.0')
import gtk
import gtk.glade
# Импорт файлов из minidom1_import
from xml.dom import minidom
import minidom1_import
from minidom1_import import questions
from minidom1_import import answers
from minidom1_import import number_of_answers
# Импорт стандартных библиотек
import sys
class TestClass:
# Инициализация начальных параметров
def __init__(self):
from minidom1_import import get_tyre_ans
from minidom1_import import k
# Получение xml-файла, опичсывающего графический интерфейс
self.wTree = gtk.glade.XML("test1_2.glade")
# Создание словаря действий, действия зада.тся в программе Glade при создании интерфейса
dic = {
"on_exit_click" : self.exit,
"on_send_click" : self.send
}
self.wTree.signal_autoconnect(dic)
# Вызов функции в соответствии с типом вопроса
for i in range (0,k):
if get_tyre_ans[i] == "single":
k=number_of_answers[i]
self.single_add(self,i,k,number_of_answers)
if get_tyre_ans[i] == "text":
self.text_add(self,i)
if get_tyre_ans[i] == "box":
self.box_add(self,i)
# Выход
def exit(self, widget):
sys.exit(0)
# Отправить результаты
def send(self, widget):
from minidom1_import import number_of_correct
from minidom1_import import answers
# Скрыть видимые ране результаты (при повторной отправке)
self.wTree.get_widget("label10").hide()
self.wTree.get_widget("label6").hide()
self.wTree.get_widget("label12").hide()
self.wTree.get_widget("label11").hide()
r=0
# Получение текстового ответа и его проверка
entry1= self.wTree.get_widget("entry1").get_text()
if entry1 == answers[number_of_correct[1]]:
# Показать текст
self.wTree.get_widget("label12").show()
else:
self.wTree.get_widget("label11").show()
# Определение нажатой радио-кнопки
rad0 = self.wTree.get_widget("radiobutton1").get_active()
rad1 = self.wTree.get_widget("radiobutton2").get_active()
rad2 = self.wTree.get_widget("radiobutton3").get_active()
rad3 = self.wTree.get_widget("radiobutton4").get_active()
if rad0 == True:
r=1
if rad1 == True:
r=2
if rad2 == True:
r=3
if rad3 == True:
r=0
# Сравнение полученного ответа с исходным значением
if r == number_of_correct[0]:
self.wTree.get_widget("label6").show()
else:
self.wTree.get_widget("label10").show()
# Функция вывода для вопроса типа single
def single_add(self,widget,num_question,k, num_answer):
# Значение label2 устанавливаем из списка questions
self.wTree.get_widget("label2").set_text(questions[num_question])
f=0
for s in range (0,num_question+1):
# Определtybt количествf ответов на вопрос
f= f+num_answer[s]
# Присвоение значений радиокнопкам
rad0 = self.wTree.get_widget("radiobutton2").set_label(answers[f-4])
rad1 = self.wTree.get_widget("radiobutton1").set_label(answers[f-3])
rad2 = self.wTree.get_widget("radiobutton4").set_label(answers[f-2])
rad3 = self.wTree.get_widget("radiobutton3").set_label(answers[f-1])
# Функция вывода для вопроса типа text
def text_add(self,widget,num_question):
self.wTree.get_widget("label1").set_text(questions[num_question])
# Функция вывода для вопроса типа box
def box_add(self,widget,num_question):
c ="200px-Coat_of_Arms_of_Moscow.png"
a= "Coat_of_Arms_of_Kursk.png"
b= "200px-Coat_of_Arms_of_Saint_Petersburg_(2003).png"
# Установка изобажений
self.wTree.get_widget("image4").set_from_file(c)
self.wTree.get_widget("image5").set_from_file(a)
self.wTree.get_widget("image6").set_from_file(b)
self.wTree.get_widget("label4").set_text(questions[num_question])
if __name__ == "__main__":
window = TestClass()
gtk.main()
Приложение 5
Код модуля drop.py
# Импорт бибилиотек
import pygtk
pygtk.require('2.0')
import gtk
import string
import gtkxpm
class DragNDropExample:
# Установка начальных значений
HEIGHT = 900
WIDTH = 900
TARGET_TYPE_TEXT = 80
TARGET_TYPE_PIXMAP = 81
fromImage = [ ( "text/plain", 0, TARGET_TYPE_TEXT ),
( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]
toButton = [ ( "text/plain", 0, TARGET_TYPE_TEXT ) ]
toCanvas = [ ( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]
# Функция отвечающая за размеры и расположение элементов
def layout_resize(self, widget, event):
x, y, width, height = widget.get_allocation()
if width > self.lwidth or height > self.lheight:
# Установка максимальных значений
self.lwidth = max(width, self.lwidth)
self.lheight = max(height, self.lheight)
widget.set_size(self.lwidth, self.lheight)
def makeLayout(self):
self.lwidth = self.WIDTH
self.lheight = self.HEIGHT
# Создание сетки для элементов
box = gtk.VBox(False,0)
box.show()
# Добавление таблицы с изображениями
table = gtk.Table(2, 2, False)
table.show()
box.pack_start(table, True, True, 0)
# Установка размеров элементов
layout = gtk.Layout()
self.layout = layout
layout.set_size(self.lwidth, self.lheight)
layout.connect("size-allocate", self.layout_resize)
layout.show()
table.attach(layout, 0, 1, 0, 1, gtk.FILL|gtk.EXPAND,
gtk.FILL|gtk.EXPAND, 0, 0)
#layout.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
# gtk.DEST_DEFAULT_HIGHLIGHT |
# gtk.DEST_DEFAULT_DROP,
# self.toCanvas, gtk.gdk.ACTION_COPY)
# Добавление изображений
self.addImage(gtkxpm.gtk_xpm, 0, 0)
# Создание кнопок
button = gtk.Button("1032")
button.show()
button2 = gtk.Button("1272")
button2.show()
button1 = gtk.Button("1703")
button1.show()
# Привязка события и функции
button.connect("drag_data_received", self.receiveCallback)
button.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
gtk.DEST_DEFAULT_HIGHLIGHT |
gtk.DEST_DEFAULT_DROP,
self.toButton, gtk.gdk.ACTION_COPY)
button2.connect("drag_data_received", self.receiveCallback)
button2.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
gtk.DEST_DEFAULT_HIGHLIGHT |
gtk.DEST_DEFAULT_DROP,
self.toButton, gtk.gdk.ACTION_COPY)
button1.connect("drag_data_received", self.receiveCallback)
button1.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
gtk.DEST_DEFAULT_HIGHLIGHT |
gtk.DEST_DEFAULT_DROP,
self.toButton, gtk.gdk.ACTION_COPY)
box.pack_start(button, False, False, 10)
box.pack_start(button2, False, False, 10)
box.pack_start(button1, False, False, 10)
return box
def addImage(self, xpm, xd, yd):
# Определение элементов и начальных координат
hadj = self.layout.get_hadjustment()
vadj = self.layout.get_vadjustment()
style = self.window.get_style()
pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
self.window.window, style.bg[gtk.STATE_NORMAL], xpm)
ramka="200px-Coat_of_Arms_of_Moscow.png"
a= "Coat_of_Arms_of_Kursk.png"
b="200px-Coat_of_Arms_of_Saint_Petersburg_(2003).png"
# Создание изображений
image1 = gtk.Image()
image1.set_from_file(ramka)
image = gtk.Image()
image.set_from_file(a)
image2 = gtk.Image()
image2.set_from_file(b)
# Создание кнопок и добавление им изображений
button = gtk.Button()
button2 = gtk.Button()
button.add(image)
button2.add(image1)
button3 = gtk.Button()
button3.add(image2)
# Вызов соответствующей функции, в зависимости от перетаскиваемой кнопки
if button.connect("drag_data_get", self.sendCallback2):
button.drag_source_set(gtk.gdk.BUTTON1_MASK, self.fromImage,
gtk.gdk.ACTION_COPY)
if button2.connect("drag_data_get", self.sendCallback1):
button2.drag_source_set(gtk.gdk.BUTTON1_MASK, self.fromImage,
gtk.gdk.ACTION_COPY)
if button3.connect("drag_data_get", self.sendCallback3):
button3.drag_source_set(gtk.gdk.BUTTON1_MASK, self.fromImage,
gtk.gdk.ACTION_COPY)
button.show_all()
button2.show_all()
button3.show_all()
# Передача в функцию элемента и его координат
self.layout.put(button, int(xd+hadj.value), int(yd+vadj.value))
self.layout.put(button2, 150, int(yd+vadj.value))
self.layout.put(button3, 300, int(yd+vadj.value))
return
# Функции реализующие передачу текста, выводящегося на кнопке при drag & drop
def sendCallback1(self, widget, context, selection, targetType, eventTime):
str = "Moscow"
selection.set(selection.target, 8, str)
def sendCallback3(self, widget, context, selection, targetType, eventTime):
str = "Piter"
selection.set(selection.target, 8, str)
def sendCallback2(self, widget, context, selection, targetType, eventTime):
str = "Kyrsk"
selection.set(selection.target, 8, str)
# Функция выводящая текст и изображение для drag & drop
def receiveCallback(self, widget, context, x, y, selection, targetType,
time):
if targetType == self.TARGET_TYPE_TEXT:
label = widget.get_children()[0]
label.set_text(selection.data)
elif targetType == self.TARGET_TYPE_PIXMAP:
self.addImage(string.split(selection.data, '\n'), x, y)
# Инициализация программы
def __init__(self):
# Создание окна программы
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_default_size(450, 300)
self.window.show_all()
self.window.connect("destroy", lambda w: gtk.main_quit())
self.window.show()
# Запуск выполнения функций
layout = self.makeLayout()
self.window.add(layout)
def main():
gtk.main()
if __name__ == "__main__":
DragNDropExample()
main() |