Выводы
В ходе данной работы мы изучили основные принципы построения веб-страниц на языке HTML, а также разработали кроссплатформенный легкопереносимый удобный генератор всего набора веб-страниц из исходных шаблонов. Кроме того, в программе использован модуль gettext, который позволяет создавать локализации приложения на любых языках в любых системах.
Ссылки
1. http://www.python.org
2. http://www.wxpython.org/
3. http://www.hoboes.com/Mimsy/
Приложение. Листинг приложения-генератора
# -*- coding: utf-8 -*-
import wx
from wx.lib.wordwrap import wordwrap
import sys
import os
import gettext
from string import Template
from time import localtime, strftime
import random
import makeHTML
import wx.lib.colourselect as csel
import string
import shutil
import wx.calendar
if 'win32' == sys.platform:
try :
import gettext_windows
gettext_windows.setup_env()
except :
print 'fail to import gettext windows'
gettext.install('default' , './lang' , unicode=True)
class mainWin(wx.Frame):
"""
Главный фрейм приложения
"""
def __init__(self, parent, title):
"""
@param parent: wx.Window
@param title: заголовок окна
"""
self.initializing = True
size = wx.DisplaySize()
wx.Frame.__init__(self, parent, -1, title, size = (800, 600),
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE | wx.TAB_TRAVERSAL,
pos=(40, 20))
self.SetMinSize((640,480))
self.SetBackgroundColour(wx.Colour(255, 255, 255))
self.buildMenuBar()
self.sizer = wx.BoxSizer(wx.VERTICAL)
outDirText = wx.StaticText(self, -1, _('output dir' ))
self.outDirField = wx.TextCtrl(self, -1, os.path.dirname(__file__)+'/out' , size=(400, -1))
outDirBtn = wx.Button(self, -1, _('Show dir dialog' ))
self.Bind(wx.EVT_BUTTON, self.outDirDialog, outDirBtn)
dirSizer = wx.BoxSizer(wx.HORIZONTAL)
dirSizer.AddMany([outDirText, self.outDirField, outDirBtn])
self.sizer.Add(dirSizer)
mSizer = wx.FlexGridSizer(cols=4, hgap=12, vgap=2)
struktTitleText = wx.StaticText(self, -1, _('Page title' ))
self.struktTitleField = wx.TextCtrl(self, -1, 'My first web page' , size=(200, -1))
metaKeywordText = wx.StaticText(self, -1, _('Meta keyword' ))
self.metaKeywordField = wx.TextCtrl(self, -1, size=(200, -1))
mSizer.AddMany([struktTitleText, self.struktTitleField,
metaKeywordText, self.metaKeywordField])
firstNameText = wx.StaticText(self, -1, _('First name' ))
self.firstNameField = wx.TextCtrl(self, -1, size=(200, -1))
secondNameText = wx.StaticText(self, -1, _('Second name' ))
self.secondNameField = wx.TextCtrl(self, -1, size=(200, -1))
lastNameText = wx.StaticText(self, -1, _('Last name' ))
self.lastNameField = wx.TextCtrl(self, -1, size=(200, -1))
mSizer.AddMany([firstNameText, self.firstNameField,
secondNameText, self.secondNameField,
lastNameText, self.lastNameField])
groupNameText = wx.StaticText(self, -1, _('Group name' ))
self.groupNameField = wx.TextCtrl(self, -1, size=(200, -1))
fakultetText = wx.StaticText(self, -1, _('Fakultet' ))
self.fakultetField = wx.TextCtrl(self, -1, size=(200, -1))
specText = wx.StaticText(self, -1, _('Specialnost' ))
self.specField = wx.TextCtrl(self, -1, size=(200, -1))
mSizer.AddMany([groupNameText, self.groupNameField,
fakultetText, self.fakultetField,
specText, self.specField])
textHtmText = wx.StaticText(self, -1, _('Text.htm title' ))
self.textHtmField = wx.TextCtrl(self, -1, size=(200, -1))
rostText = wx.StaticText(self, -1, _('rost' ))
self.rostField = wx.TextCtrl(self, -1, size=(200, -1))
vesText = wx.StaticText(self, -1, _('ves' ))
self.vesField = wx.TextCtrl(self, -1, size=(200, -1))
hairColorText = wx.StaticText(self, -1, _('hair color' ))
self.hairColorField = csel.ColourSelect(self, -1, '' , (0, 0, 0), size = (100, -1))
self.hairColor = '#000000'
self.hairColorField.Bind(csel.EVT_COLOURSELECT, self.onSelectHairColor)
#self.hairColorField = wx.TextCtrl(self, -1, size=(200, -1))
eyeColorText = wx.StaticText(self, -1, _('eye color' ))
self.eyeColorField = csel.ColourSelect(self, -1, '' , (0, 0, 0), size = (100, -1))
self.eyeColor = '#000000'
self.eyeColorField.Bind(csel.EVT_COLOURSELECT, self.onSelectEyeColor)
mSizer.AddMany([textHtmText, self.textHtmField,
rostText, self.rostField,
vesText, self.vesField,
hairColorText, self.hairColorField,
eyeColorText, self.eyeColorField])
homeAddrText = wx.StaticText(self, -1, _('Home adress' ))
self.homeAddrField = wx.TextCtrl(self, -1, size=(200, -1))
homeTelText = wx.StaticText(self, -1, _('Home telefon' ))
self.homeTelField = wx.TextCtrl(self, -1, size=(200, -1))
workPlaceText = wx.StaticText(self, -1, _('Work place' ))
self.workPlaceField = wx.TextCtrl(self, -1, size=(200, -1))
workDoljnText = wx.StaticText(self, -1, _('Work doljn' ))
self.workDoljnField = wx.TextCtrl(self, -1, size=(200, -1))
workTelText = wx.StaticText(self, -1, _('Work telefon' ))
self.workTelField = wx.TextCtrl(self, -1, size=(200, -1))
mSizer.AddMany([homeAddrText, self.homeAddrField,
homeTelText, self.homeTelField,
workPlaceText, self.workPlaceField,
workDoljnText, self.workDoljnField,
workTelText, self.workTelField])
studBilNumText = wx.StaticText(self, -1, _('Student number' ))
self.studBilNumField = wx.TextCtrl(self, -1, size=(200, -1))
studDateText = wx.StaticText(self, -1, _('Date vidachi' ))
self.studDateField = wx.TextCtrl(self, -1, size=(200, -1))
self.studDateField.Bind(wx.EVT_LEFT_DOWN, self.leftDown)
prikazText = wx.StaticText(self, -1, _('Prikaz o vidache' ))
self.prikazField = wx.TextCtrl(self, -1, size=(200, -1))
mSizer.AddMany([studBilNumText, self.studBilNumField,
studDateText, self.studDateField,
prikazText, self.prikazField])
self.sizer.Add(mSizer)
genBtn = wx.Button(self, -1, _('Generate' ))
self.Bind(wx.EVT_BUTTON, self.generate, genBtn)
self.sizer.Add(genBtn)
self.SetSizer(self.sizer)
self.Bind(wx.EVT_CLOSE, self.onCloseWindow)
def leftDown(self, event):
"""
Событие по клику на поле календаря
"""
cal = wx.calendar.CalendarCtrl(self, -1, wx.DateTime_Now(), pos = (self.studDateField.GetPosition()[0], self.studDateField.GetPosition()[1]+20),
style = wx.calendar.CAL_SHOW_HOLIDAYS
| wx.calendar.CAL_SEQUENTIAL_MONTH_SELECTION
)
self.cal = cal
self.Bind(wx.calendar.EVT_CALENDAR, self.onCalSelected, id=cal.GetId())
def onCalSelected(self, event):
"""
Событие по клику на календарь
@param event: Event
@type event: wx.Event
"""
date = '%s' %event.GetDate()
date = date.split(' ' )[0]
date = date.replace('/' , '.' )
self.studDateField.SetValue(date)
self.cal.Close()
self.cal.Destroy()
def onSelectHairColor(self, event):
color = event.GetValue()
self.hairColor = '#%2x%2x%2x' %(color[0], color[1], color[2])
def onSelectEyeColor(self, event):
color = event.GetValue()
self.eyeColor = '#%2x%2x%2x' %(color[0], color[1], color[2])
def onCloseWindow(self, event):
"""
Закрывает окно
@param event: wx.Event
"""
self.Destroy()
def buildMenuBar(self):
"""
Отрисовывает верхнее меню
"""
self.mainmenu = wx.MenuBar()
menu = wx.Menu()
exitItem = wx.MenuItem(menu, -1, _('E&xit\tCtrl-Q' ), _('Main menu exit status bar' ))
menu.AppendItem(exitItem)
self.Bind(wx.EVT_MENU, self.onCloseWindow, exitItem)
wx.App.SetMacExitMenuItemId(exitItem.GetId())
self.mainmenu.Append(menu, _('&File' ))
menu = wx.Menu()
aboutItem = wx.MenuItem(menu, -1, _('About' ), _('Main menu about status bar' ))
menu.AppendItem(aboutItem)
self.Bind(wx.EVT_MENU, self.showAbout, aboutItem)
self.mainmenu.Append(menu, _('&Help' ))
self.SetMenuBar(self.mainmenu)
def showAbout(self, event):
"""
Показывает окно с информацией о программе
"""
info = wx.AboutDialogInfo()
info.Name = _("Lab 1 creator" )
info.Copyright = _("(C) 2011 MrXaK" )
info.Description = wordwrap(
_("Created by Soloviev Alex (ITS-3-07)\n"
"Prepod: Holkin I.I.\n" ),
350, wx.ClientDC(self))
wx.AboutBox(info)
def outDirDialog(self, event):
"""
Показ диалогового окна для выбора директории сохранения
@param event: wx.Event
"""
dlg = wx.DirDialog(self, _("Choose a directory:" ),
style=wx.DD_DEFAULT_STYLE
#| wx.DD_DIR_MUST_EXIST
#| wx.DD_CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
self.outDirField.SetValue('%s' % dlg.GetPath())
dlg.Destroy()
def generate(self, event):
"""
@param event: wx.Event
"""
# парсинг первого файла strukt.htm
generator('strukt.htm' , dict(
struktPageTitle=self.struktTitleField.GetValue().encode('utf-8' ),
metaAuthor=('%s %s.%s.' %(self.secondNameField.GetValue(),
self.firstNameField.GetValue()[0:1],
self.lastNameField.GetValue()[0:1])).encode('utf-8' ),
metaKeyWords=self.metaKeywordField.GetValue().encode('utf-8' ),
bgcolor=generator.genRndColor('#' ).encode('utf-8' ),
comment="Created via mrxak's autogenerator at %s" %(strftime("%H:%M:%S" , localtime()), ),
secondName=self.secondNameField.GetValue().encode('utf-8' ),
firstName=self.firstNameField.GetValue().encode('utf-8' ),
lastName=self.lastNameField.GetValue().encode('utf-8' ),
groupName=self.groupNameField.GetValue().encode('utf-8' ),
fakultet=self.fakultetField.GetValue().encode('utf-8' ),
specialnost=self.specField.GetValue().encode('utf-8' ),
work=self.workPlaceField.GetValue().encode('utf-8' ),
), outDir=self.outDirField.GetValue())
# создание собственного strukt1.htm
generator.genStrukt1(dict(secondName=self.secondNameField.GetValue().encode('utf-8' ),
firstName=self.firstNameField.GetValue().encode('utf-8' ),
lastName=self.lastNameField.GetValue().encode('utf-8' ),
), outDir=self.outDirField.GetValue())
# обработка Text.htm
weight = generator.genWeight(dict(
rost=self.rostField.GetValue(),
ves=self.vesField.GetValue(),
hairColor=self.hairColor,
eyeColor=self.eyeColor,
))
generator('Text.htm' , dict(
opit=generator.genRandFormatText(),
weight=weight,
secondName=self.secondNameField.GetValue().encode('utf-8' ),
firstName=self.firstNameField.GetValue().encode('utf-8' ),
lastName=self.lastNameField.GetValue().encode('utf-8' ),
homeTel=self.homeTelField.GetValue().encode('utf-8' ),
homeAddr=self.homeAddrField.GetValue().encode('utf-8' ),
workPlace=self.workPlaceField.GetValue().encode('utf-8' ),
workDoljn=self.workDoljnField.GetValue().encode('utf-8' ),
workTel=self.workTelField.GetValue().encode('utf-8' ),
), outDir=self.outDirField.GetValue(), type='rnd1' )
# студенческий+CSS
shutil.copy('./templates/photo.jpg' , self.outDirField.GetValue()+'/photo.jpg' )
generator('StudBilet.htm' , dict(
secondName=self.secondNameField.GetValue().encode('utf-8' ),
firstName=self.firstNameField.GetValue().encode('utf-8' ),
lastName=self.lastNameField.GetValue().encode('utf-8' ),
studNum=self.studBilNumField.GetValue().encode('utf-8' ),
fakultet=self.fakultetField.GetValue().encode('utf-8' ),
relDate=self.studDateField.GetValue().encode('utf-8' ),
), outDir=self.outDirField.GetValue())
# зачётка
generator('ZachetnKnizhka.htm' , dict(
secondName=self.secondNameField.GetValue().encode('utf-8' ),
firstName=self.firstNameField.GetValue().encode('utf-8' ),
lastName=self.lastNameField.GetValue().encode('utf-8' ),
specialnost=self.specField.GetValue().encode('utf-8' ),
studNum=self.studBilNumField.GetValue().encode('utf-8' ),
fakultet=self.fakultetField.GetValue().encode('utf-8' ),
relDate=self.studDateField.GetValue().encode('utf-8' ),
prikaz=self.prikazField.GetValue().encode('utf-8' ),
), outDir=self.outDirField.GetValue(), outFile='ZachKnizhka.htm' )
# стили
generator('style.htm' , dict(
secondName=self.secondNameField.GetValue().encode('utf-8' ),
firstName=self.firstNameField.GetValue().encode('utf-8' ),
lastName=self.lastNameField.GetValue().encode('utf-8' ),
homeTel=self.homeTelField.GetValue().encode('utf-8' ),
homeAddr=self.homeAddrField.GetValue().encode('utf-8' ),
workPlace=self.workPlaceField.GetValue().encode('utf-8' ),
workDoljn=self.workDoljnField.GetValue().encode('utf-8' ),
workTel=self.workTelField.GetValue().encode('utf-8' ),
), outDir=self.outDirField.GetValue(), type='rnd2' )
# таблицы
shutil.copy('./templates/fon01.gif' , self.outDirField.GetValue()+'/fon01.gif' )
generator('ListTable.htm' , dict(
list=generator.genUlUlList(),
table=generator.genTable()
), outDir=self.outDirField.GetValue())
class generator():
def __init__(self, file, dict=None, **kwargs):
"""
Парсер шаблонов
@param file: имя файла-шаблона
@param dict: словарь замен
@keyword outDir: выходная директория
@keyword outFile: имя выходного файла
"""
self.file = open('./templates/' +file, 'r' ).read()
if ('rnd1' == kwargs.get('type' )):
for i in range(36):
dict['unique' +str(i)] = generator.genUnique()
elif ('rnd2' == kwargs.get('type' )):
for i in range(7):
dict['clr' +str(i)] = generator.genRndColor('#' )
dict['font1' ] = random.choice(['Arial' ,'Helvetica' ,'sans-serif' ,'Tahoma' ])
ch = random.choice(['Arial' ,'Helvetica' ,'sans-serif' ,'Tahoma' ])
while (ch == dict['font1' ]):
ch = random.choice(['Arial' ,'Helvetica' ,'sans-serif' ,'Tahoma' ])
dict['font2' ] = ch
for i in range(3):
dict['sz' +str(i)] = str(random.randint(10, 16))+'pt'
t = Template(self.file)
f = open(kwargs.get('outDir' , './out/' )+'/' +kwargs.get('outFile' , file), 'w' )
f.write(t.safe_substitute(dict))
f.close()
@staticmethod
def genRndColor(add='' ):
"""
Функция, возвращающая случайный цвет в HEX-формате (RRGGBB)
@param add: строка для добавления перед цветом
@return: строку
"""
a = random.randint(0, 255)
b = random.randint(0, 255)
c = random.randint(0, 255)
return "%s%2x%2x%2x" %(add,a,b,c)
@staticmethod
def genStrukt1(dict, **kwargs):
"""
Создаёт тестовый файл Strukt1
@param dict: словарь {имя, фамилия, отчество}
@keyword outDir: выходная директория
"""
pageTitle = 'Тестовая страница'
pageHead = makeHTML.part('head' )
pageHead.addPart('title' , content=pageTitle)
pageHead.addPart('meta' , attributes={'http-equiv' :"Content-Type" ,
'content' :"text/html; charset=utf-8" })
pageBody = makeHTML.part('body' )
pageBody.addPart('a' , attributes={'name' :'top' });
pageBody.addPart('hr' )
pageBody.addPart('h1' , content=dict['secondName' ])
pageBody.addPart('h2' , content=dict['firstName' ])
pageBody.addPart('h3' , content=dict['lastName' ])
pageBody.addPart('p' , content='Some test makeHTML features' )
pageBody.addPart('hr' )
pageBody.addPart('a' , content="Uses makeHTML by Mimsy" , attributes={'href' :'http://www.hoboes.com/Mimsy/' });
pageBody.addPart('hr' )
pageBody.addPart('a' , content="Наверх" , attributes={'href' :'#top' });
fullPage = makeHTML.part('html' )
fullPage.addPiece(pageHead)
fullPage.addPiece(pageBody)
s = fullPage.make()
f = open(kwargs.get('outDir' , './out/' )+'/strukt1.htm' , 'w' )
f.write(s)
f.close()
@staticmethod
def genUnique():
"""Генерит случайные строки
"""
return random.choice(["Этот текст из случайного набора" ,
"Используется Python 2.6" ,
"Плагин к питону: wxPython, makeHTML" ,
"Alldoc can be found at python.org" ,
'' .join(['%s' %(random.choice(string.letters)) for i in range(100)]),
' ' .join(['%s' %(random.choice(string.letters)) for i in range(100)]),
'_' .join(['%s' %(random.choice(string.letters)) for i in range(100)]),
'!' .join(['%s' %(random.choice(string.letters)) for i in range(100)]),
'ZPT' .join(['%s' %(random.choice(string.letters)) for i in range(100)]),
'...' .join(['%s' %(random.choice(string.letters)) for i in range(100)]),
])
@staticmethod
def getBmi(rost, ves):
"""
Считает индекс массы тела, выдаёт размер и цвет шрифта в соответствии с индексом
(http://ru.wikipedia.org/wiki/Индекс_массы_тела)
@param rost: рост
@param ves: вес
@return: dict[sz, color]
"""
bmi = float('%s' %ves)/((float('%s' %rost)/100)**2)
print bmi
if bmi < 16:
sz = 4
color = 'blue'
elif 16 < bmi < 18.49:
sz = 5
color = 'blue'
elif 18.5<bmi<24.99:
sz = 6
color = 'green'
elif 25<bmi<29.99:
sz = 6
color = 'pink'
elif 30<bmi<34.99:
sz = 7
color = 'pink'
elif 35<bmi<39.99:
sz = 8
color='red'
else :
sz = 10
color='red'
return {'sz' : sz, 'color' :color}
@staticmethod
def genWeight(dict):
"""
Создаёт текст, отображающий рост и вес с цветом и размером в соответствии
с индексом массы тела
@param dict: [rost, ves, hairColor, eyeColor]
@return: string
"""
ves = dict['ves' ].encode('utf-8' )
rost = dict['rost' ].encode('utf-8' )
ret = generator.getBmi(rost, ves)
sz = ret['sz' ]
color = ret['color' ]
s = '<p><font size=%d color="%s">1. Мой рост: %s</font></p>' %(sz, color, rost)
s += '<p><font size=%d color="%s">2. Мой вес: %s</font></p>' %(sz-1, color, ves)
s += '<p><font size=%d color="%s">3. Мои волосы</font></p>' %(random.randint(1,6), dict['hairColor' ])
s += '<p><font size=%d color="%s">4. Мои глаза</font></p>' %(random.randint(1,6), dict['eyeColor' ])
return s
@staticmethod
def genRandFormatText():
"""
Создаёт строку "Мой первый опыт форматирования текста" со случайными параметрами размера, цвета и т. п.
@return: string
"""
string = u"Мой__Первый__Опыт__Форматирования__Текста" .encode('utf-8' )
curP = 0
s = ''
while (curP < len(string)-5):
sz = random.randint(1, 7)
clr = generator.genRndColor('#' )
nextP = random.randint(curP, curP+8)
if (curP == nextP):