<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://wiki2.linuxformat.ru/skins/common/feed.css?97"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF134%3APython</id>
		<title>LXF134:Python - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF134%3APython"/>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF134:Python&amp;action=history"/>
		<updated>2026-05-14T00:45:38Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.11.1</generator>

	<entry>
		<id>http://wiki2.linuxformat.ru/index.php?title=LXF134:Python&amp;diff=12578&amp;oldid=prev</id>
		<title>Crazy Rebel: /* От­лад­ка в Quickly */</title>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF134:Python&amp;diff=12578&amp;oldid=prev"/>
				<updated>2011-09-08T09:09:59Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;От­лад­ка в Quickly&lt;/span&gt;&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;← Предыдущая&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Версия 09:09, 8 сентября 2011&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Строка 351:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Строка 351:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;===От­лад­ка в Quickly===&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;===От­лад­ка в Quickly===&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;{{Врезка|Содержание=[[Изображение:&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;LXF133_75_1&lt;/del&gt;.jpg|300px]] Это не центр управ­ле­ния энер­го­под­стан­ци­ей, это ок­ру­же­ние для от­лад­ки.|Ширина=300px}}&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;{{Врезка|Содержание=[[Изображение:&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;LXF134_75_1&lt;/ins&gt;.jpg|300px]] Это не центр управ­ле­ния энер­го­под­стан­ци­ей, это ок­ру­же­ние для от­лад­ки.|Ширина=300px}}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Да­же масти­тые ко­де­ры здесь у нас в Башне LXF иногда оши­ба­ют­ся в су­ж­дениях. Во­об­ще-то лю­ди, имею­щие при­выч­ку все оценивать, счи­та­ют, что 80 % вре­мени раз­ра­бот­ки ПО ухо­дит на ис­прав­ление оши­бок. Но ис­прав­ление оши­бок – во­все не ка­тор­га: это путь к от­кры­ти­ям (как мы пы­та­ем­ся убе­дить са­ми се­бя), даю­щий нам ощу­щение востре­бо­ван­но­сти и по­лез­но­сти.&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Да­же масти­тые ко­де­ры здесь у нас в Башне LXF иногда оши­ба­ют­ся в су­ж­дениях. Во­об­ще-то лю­ди, имею­щие при­выч­ку все оценивать, счи­та­ют, что 80 % вре­мени раз­ра­бот­ки ПО ухо­дит на ис­прав­ление оши­бок. Но ис­прав­ление оши­бок – во­все не ка­тор­га: это путь к от­кры­ти­ям (как мы пы­та­ем­ся убе­дить са­ми се­бя), даю­щий нам ощу­щение востре­бо­ван­но­сти и по­лез­но­сти.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	<entry>
		<id>http://wiki2.linuxformat.ru/index.php?title=LXF134:Python&amp;diff=12569&amp;oldid=prev</id>
		<title>Crazy Rebel: викификация, оформление, иллюстрация</title>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF134:Python&amp;diff=12569&amp;oldid=prev"/>
				<updated>2011-09-08T08:44:33Z</updated>
		
		<summary type="html">&lt;p&gt;викификация, оформление, иллюстрация&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая статья&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: ''''''Python''''' Ре­аль­ные про­ек­ты, от­та­чи­ваю­щие на­вы­ки ха­ке­ра&lt;br /&gt;
&lt;br /&gt;
==''Python'': Бу­дем грузить подкасты==&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Python}}&lt;br /&gt;
&lt;br /&gt;
: По­зна­комь­тесь с пре­крас­ным ин­ст­ру­мен­том для соз­дания и вы­пуска при­ло­жений от коман­ды Ubuntu. '''Ник Вейч''' на­страи­ва­ет­ся на лю­би­мый под­каст…&lt;br /&gt;
&lt;br /&gt;
На этом эпи­че­ском и зре­лищ­ном уро­ке на­ша за­да­ча, ни мно­го ни ма­ло, напи­сать пол­но­цен­ное на­столь­ное при­ло­жение, соз­дать для него па­кет Debian и вы­пустить его в боль­шой мир. Ду­мае­те, невоз­мож­но соз­дать пол­но­цен­ное ра­бо­таю­щее на­столь­ное при­ло­жение, ко­то­рое и вправ­ду что-то де­ла­ет, в рам­ках че­ты­рех­странич­но­го уро­ка? В чем-то вы пра­вы; вот мы и рас­ши­ри­ли урок это­го но­ме­ра в два раза, до вось­ми стра­ниц. И на сей раз у нас есть силь­ный со­юзник – ''Quickly''. &lt;br /&gt;
&lt;br /&gt;
''Quickly'' [англ. «бы­ст­ро»] – это на­бор средств раз­ра­бот­ки, с при­ла­гае­мы­ми шаб­ло­на­ми, для соз­дания по­до­бия RAD-сре­ды (Rapid Application Development – бы­ст­рая раз­ра­бот­ка при­ло­жений). Оно до­воль­но ско­ро­ст­ное: мож­но соз­дать и за­пустить при­ло­жение за несколь­ко се­кунд – про­смот­ри­те далее по­ша­го­вое ру­ко­во­дство и убе­ди­тесь на­гляд­но. Од­на­ко, хоть мы и мо­жем соз­дать ра­бо­таю­щее при­ло­жение, в нем не бу­дет ни грам­ма функ­цио­на­ла, необ­хо­ди­мо­го для ме­га­заг­ру­чи­ка под­кастов TuxRadar (а его-то мы и со­би­ра­ем­ся де­лать). И все же про­бе­ги­тесь по тек­сту, что­бы по­нять, как все ра­бо­та­ет, за­тем вернитесь сю­да – и мы раз­бе­рем­ся с под­каста­ми.&lt;br /&gt;
&lt;br /&gt;
===Что нам пона­добится===&lt;br /&gt;
&lt;br /&gt;
Наш урок ос­но­ван на ''Quickly'', ин­ст­ру­мен­те раз­ра­бот­ки Ubuntu; по­это­му бу­дет на­мно­го про­ще, ес­ли вы возь­ме­те Ubuntu (на­при­мер, с дис­ка '''LXF133'''). То­гда про­сто ус­та­но­ви­те па­ке­ты '''quickly''' и '''python-feedparser''' из ре­по­зи­то­рия, и все бу­дет го­то­во.&lt;br /&gt;
&lt;br /&gt;
Ес­ли вы рас­па­ко­ва­ли код с LXFDVD в удоб­ное ме­сто, мо­же­те ис­поль­зо­вать для уро­ка его – на­стро­ен­ное ''Quickly'' уже го­то­во к ра­бо­те, и мож­но ис­поль­зо­вать ко­ман­ды ''Quickly''.&lt;br /&gt;
&lt;br /&gt;
===Соз­да­ем при­ло­жение===&lt;br /&gt;
&lt;br /&gt;
Итак, мы оз­на­ко­ми­лись с ба­зо­вы­ми ме­ханиз­ма­ми ра­бо­ты ''Quickly''; по­ра сде­лать что-то по­лез­ное. Как уже ска­за­но, мы на­ме­ре­ны соз­дать за­груз­чик под­кастов. По­нят­но, при­дет­ся по­во­зить­ся с но­во­ст­ны­ми лен­та­ми и то­му по­доб­ным, но для на­ча­ла при­па­сем ме­сто для хранения за­гру­жае­мых фай­лов. Мы обя­за­ны дать поль­зо­ва­те­лям воз­мож­ность вы­брать ме­сто хранения (или соз­дать но­вое, ес­ли на­до); зна­чит, необ­хо­дим диа­лог, в ко­то­ром они смо­гут это сде­лать.&lt;br /&gt;
&lt;br /&gt;
Весь­ма удоб­но, что шаб­лон на­ше­го при­ло­жения со­дер­жит ре­дак­тор па­ра­мет­ров. В нем еще ниче­го нет, но это уже хо­ро­шее на­ча­ло. В та­ких си­туа­ци­ях обыч­но луч­ше на­чать с ин­тер­фей­са поль­зо­ва­те­ля, чем с са­мо­го ко­да – хо­тя бы по­то­му, что это по­мо­жет уз­нать име­на объ­ек­тов и их сиг­на­лы до напи­сания ко­да, объ­е­ди­няю­ще­го их. Итак, за­пусти­те ''Glade'' коман­дой ''quickly design'' в ка­та­ло­ге при­ло­жения.&lt;br /&gt;
&lt;br /&gt;
От­кро­ет­ся ''Glade'' с глав­ным UI-фай­лом про­ек­та, но нам-то ну­жен дру­гой, так что от­крой­те пра­виль­ный, с именем '''PreferencesMyAppDialog.ui'''. По­сле его от­кры­тия вы уви­ди­те по­се­ре­дине при­ят­ную пусто­ту. Пер­вым де­лом раз­местим в ней эле­мент '''vbox''', вер­тикаль­ный кон­тейнер – он раз­ме­ща­ет свои до­черние эле­мен­ты по вер­тика­ли. Щелкните в ле­вой панели на икон­ке '''vbox''', а за­тем в се­рой об­ласти, что­бы раз­местить его. Всплы­вет диа­лог, за­пра­ши­ваю­щий, сколь­ко эле­мен­тов вы хо­ти­те раз­местить – оставь­те их 3. По­ка мы упот­ре­бим толь­ко два из них, но это не бе­да – один бу­дет про за­пас, по­сколь­ку, ве­ро­ятнее все­го, он по­на­до­бит­ся нам позднее. Но не за­па­сай­те слиш­ком мно­го: до­ба­вить эле­мен­ты в вер­тикаль­ный кон­тейнер про­сто, а вот уда­лить – боль­шая мо­ро­ка.&lt;br /&gt;
&lt;br /&gt;
В верхней части раз­местим мет­ку, что­бы поль­зо­ва­тель по­нимал, что про­ис­хо­дит. Вы­бе­ри­те эле­мент '''Label''' в панели сле­ва и щелкните в верхней части '''vbox'''. Сей­час в ней напи­са­но просто «Label», но текст мож­но из­менить при по­мо­щи ин­спек­то­ра свойств спра­ва внизу.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF134_70_1.jpg|300px]] Сде­лай­те дей­ст­ви­ем кноп­ки фай­ло­во­го диа­ло­га «Вы­бор ка­та­ло­га», ина­че поль­зо­ва­те­ли смо­гут вы­би­рать во всплы­ваю­щем спи­ске толь­ко фай­лы.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
По­местив бо­лее осмыс­лен­ный текст в свой­стве '''Мет­ка''', до­бавь­те ка­кой-нибудь спо­соб вы­бо­ра ка­та­ло­га. Та­ко­вых мож­но при­ду­мать мно­го, но ''GTK'' со­дер­жит спе­ци­аль­ную кноп­ку имен­но для этой це­ли, и бы­ло бы глу­по ею не восполь­зо­вать­ся. Вы­бе­ри­те объ­ект '''FileDialogButton''' в панели сле­ва и по­мести­те его в сре­дин­ный слот.&lt;br /&gt;
&lt;br /&gt;
Нам нуж­но из­менить неко­то­рые свой­ства. На вклад­ке «'''Основ­ные'''» про­кру­чи­вай­те спи­сок вниз, по­ка не на­ткнетесь на пункт «'''Дей­ствие'''». Из­мените его на «'''Вы­бор ка­та­ло­га'''». Стандарт­ное дей­ствие – это вы­бор фай­ла, но это не то, что нам нуж­но. По­сле вы­бо­ра это­го дей­ствия, щел­чок на кноп­ке при­ве­дет к за­полнению спи­ска со­от­вет­ствую­щим со­дер­жи­мым. Мы мо­жем оп­ро­бо­вать ее уже в ''Glade'' – про­сто щелкните на икон­ке у пра­во­го края кноп­ки.&lt;br /&gt;
&lt;br /&gt;
Од­на­ко пре­ж­де чем со­хранить наш но­вый диа­лог, сде­лай­те еще од­ну важ­ную вещь. Когда кто-нибудь вы­би­ра­ет ка­та­лог, мы долж­ны как-то уз­нать, что же он вы­брал. Для это­го мы по­да­ем сиг­нал от объ­ек­та, со­об­щаю­щий, что некое зна­чение из­менилось. С точ­ки зрения ко­да, нуж­но напи­сать ме­тод-об­ра­бот­чик, ра­бо­таю­щий с дан­ны­ми, но об­ра­бот­чик необ­хо­ди­мо ука­зать здесь при ди­зайне UI-фай­ла. Щелкните на вклад­ке «'''Сиг­на­лы'''». Вы уви­ди­те, что сиг­на­лов, к ко­то­рым мож­но под­клю­чить­ся, пол­но. Нас ин­те­ре­су­ет сиг­нал из раз­де­ла ‘'''GTKFileChooser'''’ – от­крой­те его. В пер­вом столб­це два­ж­ды щелкните спра­ва от на­звания ‘'''current-folder-changed'''’ и вве­ди­те имя об­ра­бот­чи­ка ‘'''folder_changed'''’. Те­перь, сто­ит поль­зо­ва­те­лю вы­брать дру­гой ка­та­лог, мы уз­на­ем об этом и из­меним со­от­вет­ствую­щий па­ра­метр при­ло­жения.&lt;br /&gt;
&lt;br /&gt;
Не за­будь­те со­хранить файл пе­ред вы­хо­дом из ''Glade''. Те­перь при­шло вре­мя вве­сти ''quickly save ‘prefs dialog’'', что пе­ре­даст ва­ши но­вые фай­лы систе­ме управ­ления вер­сия­ми (см. со­вет ''Quickly'' Со­хра­няй­те по­ча­ще).&lt;br /&gt;
&lt;br /&gt;
===Что в име­ни тво­ем?===&lt;br /&gt;
&lt;br /&gt;
Не ис­клю­че­но, что вы счи­тае­те UI-фай­лы ''Glade'' про­сто XML-ко­дом, од­на­ко вы не смо­же­те про­сто пе­ре­не­сти их из од­но­го про­ек­та в дру­гой без зна­чи­тель­но­го ре­фак­то­рин­га. Они на­пич­ка­ны ссыл­ка­ми на имя про­ек­та, так что вы не смо­же­те да­же про­сто им­пор­ти­ро­вать их в ваш про­ект – луч­ше по­зво­лить ''Quickly'' соз­дать для вас ба­зо­вые UI-фай­лы.&lt;br /&gt;
&lt;br /&gt;
===Храните здесь===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF134_70_2.jpg|300px]] Эле­мен­ты ин­тер­фей­са мож­но вы­би­рать ли­бо на са­мой фор­ме, ли­бо в дре­во­вид­ном спи­ске спра­ва. Со­дер­жи­мое ин­спек­то­ра свойств из­ме­нит­ся в со­от­вет­ст­вии с вы­бран­ным эле­мен­том, и мож­но бу­дет ре­дак­ти­ро­вать его по­ве­де­ние.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Пре­ж­де чем по­гру­зить­ся в код, что­бы сде­лать этот ше­девр ин­тер­фей­са ра­бо­чим, при­кинем, где мы бу­дем все раз­ме­щать: ведь глав­ный смысл на­стро­ек в том, что они со­хра­ня­ют­ся на бу­ду­щее. Так что тре­бу­ет­ся ме­сто для хранения. Дан­ные бу­дут ти­па на­стро­ек при­ло­жения, лен­т, на ко­то­рые мы под­пи­шем­ся, и, воз­мож­но, мно­гого дру­гого, о чем мы еще не за­ду­мы­ва­лись. Луч­шее все­го вы­брать нечто лег­ко­доступ­ное. Име­ет­ся мно­же­ство по­пу­ляр­ных и хо­ро­шо до­ку­мен­ти­ро­ван­ных мо­ду­лей ''Python'' для со­хранения на­стро­ек, вро­де ''ConfigObj, ConfigParser'' и т. д., но мы ис­поль­зу­ем нечто иное: ба­зу дан­ных под на­званием ''CouchDB''.&lt;br /&gt;
&lt;br /&gt;
Воз­мож­но, вы со­чте­те, что ба­за дан­ных для хранения па­ры па­ра­мет­ров – это пе­ре­бор, но в ее поль­зу есть веский до­вод: она уже яв­ля­ет­ся ча­стью шаб­ло­на про­ек­та, ко­то­рый ''Quickly'' ис­поль­зу­ет для генера­ции на­ше­го при­ло­жения, а ко­ли она есть, на­до ею поль­зо­вать­ся.&lt;br /&gt;
&lt;br /&gt;
На са­мом де­ле в про­ект вклю­че­на не толь­ко ба­за, но и код для досту­па к ней; оста­ет­ся до­ба­вить там и сям несколь­ко строк. Ес­ли вы же­лае­те спер­ва оз­нко­мить­ся с ''CouchDB'', про­смот­ри­те раздел ''Что та­кое CouchDB?''&lt;br /&gt;
&lt;br /&gt;
За­пусти­те ''Gedit'' коман­дой ''quickly edit'', и все фай­лы с ко­дом от­кро­ют­ся ав­то­ма­ти­че­ски. Най­ди­те '''PreferencesMyAppDialog.py''' с ко­дом об­ра­бот­ки на­стро­ек. Неваж­но, понимае­те ли вы весь этот код или нет, но чтение его вам по­мо­жет. Здесь про­ис­хо­дит несколь­ко ве­щей: несколь­ко функ­ций инициа­ли­за­ции, генери­рую­щих ок­но диа­ло­га, и некий код для ра­бо­ты с ба­зой дан­ных. К сча­стью, в нем име­ют­ся ком­мен­та­рии, и най­ти его бу­дет не слож­но. При вы­полнении дан­ный код про­ве­ря­ет, не за­да­ны ли уже неко­то­рые на­строй­ки; ес­ли нет, он от­кры­ва­ет ба­зу дан­ных (и за­пуска­ет ''CouchDB'', ес­ли она еще не за­пу­ще­на) и пы­та­ет­ся за­гру­зить их из нее. Ес­ли там их нет, необ­хо­ди­мо вве­сти в код уста­нов­ку зна­чений по умол­чанию, что мы да­лее и сде­ла­ем. Здесь есть неболь­шой код для кно­пок '''‘OK’''' и '''‘Cancel’''', ко­то­рые вско­ре поя­вят­ся.&lt;br /&gt;
&lt;br /&gt;
===Что за шту­ка – ''CouchDB''?===&lt;br /&gt;
&lt;br /&gt;
* ''Итак, я понимаю, что '''CouchDB''' — еще од­на ба­за дан­ных, как '''SQL''' и вся­кое та­кое?''&lt;br /&gt;
: Не со­всем. ''CouchDB'' – ско­рее дви­жок хранили­ща до­ку­мен­тов. В от­ли­чие от ба­зы дан­ных, он про­сто хранит све­дения, ко­то­рые вы ему пе­ре­дае­те, поч­ти их не струк­ту­ри­руя, лег­ким для досту­па спо­со­бом. Же­ст­кой схе­мы дан­ных нет (все ор­ганизо­ва­но в ви­де пар ключ:зна­чение, по ти­пу объ­ек­та-сло­ва­ря в ''Python''), что весь­ма удоб­но для нас.&lt;br /&gt;
* ''Он мо­жет хранить толь­ко текст? А как на­счет дру­гих дан­ных, ко­то­рые я за­хо­чу туда по­местить?''&lt;br /&gt;
: Зна­чение клю­ча мо­жет быть прак­ти­че­ски лю­бым ти­пом дан­ных ''Python'' – чис­лом, стро­кой и на­бо­ром раз­лич­ных объ­ек­тов, спи­ском и да­же дру­гим сло­ва­рем. Вы мо­же­те до­бав­лять дру­гие объ­ек­ты – на­при­мер, фай­лы с изо­бра­жения­ми – в ка­че­стве при­ло­жений к ба­зе дан­ных, но бо­лее эф­фек­тив­но хранить их дру­гим спо­со­бом.&lt;br /&gt;
* ''Зна­чит, тот, кто возь­мет мое при­ло­жение для сво­ей ра­бо­ты, дол­жен за­пустить еще один сер­вер ба­зы данных?''&lt;br /&gt;
: Нет, об этом в ''Python'' по­за­бо­тит­ся биб­лио­те­ка '''Desktopcouch'''. Она за­пуска­ет ба­зу дан­ных по лю­бо­му тре­бо­ванию. ''CouchDB'' раз­ра­бо­та­н нетре­бо­ва­тель­ным к ре­сур­сам, так что ско­рее все­го вы да­же не по­чув­ствуе­те, что он за­пусти­лся. Ес­ли, конеч­но, вы не сле­ди­те за ним…&lt;br /&gt;
* ''То есть как это — «сле­дить за ним»?''&lt;br /&gt;
: Ну, од­но из са­мых за­ме­ча­тель­ных свойств этой ба­зы дан­ных – то, что она соз­да­на с при­це­лом на web. Она бы­ла раз­ра­бо­та­на для ра­бо­ты с неслож­ны­ми API, реа­ли­зо­ван­ны­ми че­рез HTTP, что­бы сде­лать ее по­лез­ной для web-при­ло­жений. Ба­зи­ру­ясь на прин­ци­пах ACID (для фа­на­тов аб­бре­виа­тур: Atomicity, Consistency, Isolation и Durability – Ато­мар­ность, Со­гла­со­ван­ность, Изо­ли­ро­ван­ность, Дол­го­веч­ность), она соз­да­ва­лась с це­лью быть по­сто­ян­но в ра­бо­чем со­стоянии, что­бы со­про­тив­лять­ся сбо­ям или от­клю­чению. Она мо­жет вы­пол­нять вся­кие по­лез­ные дей­ствия, вро­де P2P-ре­п­ли­ка­ций. Для на­ших це­лей, сле­ду­ет лишь на­пра­вить брау­зер по ад­ре­су file:///home/&amp;lt;имя_поль­зо­ва­те­ля&amp;gt;/.local/share/desktop-couch/couchdb.html – там вы об­на­ру­жи­те все ба­зы дан­ных, ис­поль­зуе­мые ''desktop-couch''.&lt;br /&gt;
* ''Вы­хо­дит, это нечто вро­де '''MySQL-Admin'''?''&lt;br /&gt;
: По­хо­же, толь­ко работать с этим про­ще. Ис­поль­зо­вание web-ин­тер­фей­са для из­менения дан­ных в лю­бой ба­зе весь­ма про­сто и, конеч­но же, от­ла­жи­вать тран­зак­ции ба­зы дан­ных так­же лег­ко.&lt;br /&gt;
&lt;br /&gt;
===Сброс ''CouchDB''===&lt;br /&gt;
&lt;br /&gt;
Ко­гда на­ше при­ло­же­ние ищет со­хра­нен­ные на­строй­ки при стар­те, оно по­слуш­но за­гру­жа­ет то, что на­хо­дит. Но ес­ли вы нач­не­те до­бав­лять в раз­ные ве­щи код, их мо­жет не ока­зать­ся в ба­зе дан­ных, и ни­че­го не про­изой­дет. В этом слу­чае про­ще все­го уда­лить ба­зу дан­ных ''CouchDB'' из брау­зе­ра. Пе­рей­ди­те в file:///home/&amp;lt;имя_поль­зо­ва­те­ля&amp;gt;/.local/share/desktop-couch/couchdb.html и про­сто вы­де­ли­те и уда­ли­те ба­зу дан­ных ва­ше­го при­ло­же­ния. При сле­дую­щем за­пус­ке она бу­дет соз­да­на из стан­дарт­ных зна­че­ний.&lt;br /&gt;
&lt;br /&gt;
===Со­хра­няй­те по­ча­ще===&lt;br /&gt;
&lt;br /&gt;
Ино­гда нам слу­ча­ет­ся на­пор­та­чить. Для фай­лов ис­ход­ных тек­стов это обыч­но не про­бле­ма, но для фай­лов ин­тер­фей­са ''Glade'' прак­ти­че­ски фа­таль­но, по­то­му что в них мно­го не­об­ра­ти­мых дей­ст­вий.&lt;br /&gt;
&lt;br /&gt;
По этой при­чи­не ''Quickly'' име­ет встро­ен­ную сис­те­му управ­ле­ния вер­сия­ми. Это не про­сто спо­соб упа­ков­ки и пуб­ли­ка­ции про­ек­та на Launchpad; это по­лез­ная вещь по су­ти для все­го. Ес­ли вве­сти ко­ман­ду ''quickly save ‘ком­мен­та­рий к но­вой вер­сии’'', то но­вая вер­сия ва­ше­го про­ек­та за­не­сет­ся в сис­те­му кон­тро­ля вер­сий ''Bazaar''. Про­ве­рить со­хра­нен­ные вер­сии мож­но, ско­ман­до­вав ''bzr log'' – вы­ве­дет­ся спи­сок всех вы­пол­нен­ных тран­зак­ций, вме­сте с за­мет­ка­ми и да­той-вре­ме­нем. Ес­ли уг­ро­би­лось во­об­ще все, вве­ди­те в глав­ном ка­та­ло­ге при­ло­же­ния ''bzr revert'' – и файл с с ис­ход­ны­ми тек­ста­ми, гра­фи­че­ский ин­тер­фейс и лю­бые дру­гие фай­лы вос­ста­но­вят­ся из пре­ды­ду­щей вер­сии.&lt;br /&gt;
&lt;br /&gt;
Под­сказ­ка-бо­нус: при же­ла­нии вос­ста­но­вить лишь часть про­ек­та, вы­пол­ни­те ''quickly design'' и ''quickly edit'', ука­жи­те ко­ман­ду '''revert''' и сохра­ни­те фай­лы, ко­то­рые хо­ти­те ос­та­вить как бы­ли.&lt;br /&gt;
&lt;br /&gt;
===Со­хра­ня­ем вво­ди­мые зна­чения===&lt;br /&gt;
&lt;br /&gt;
Итак, мы ре­ши­ли со­хра­нять в на­строй­ках ка­та­лог, ку­да бу­дут за­гру­жать­ся фай­лы. Со­глас­но ко­ду, на­строй­ки хра­нят­ся в объ­ек­те-сло­ва­ре с именем '''self._preferences''' (часть ‘self’ оз­на­ча­ет, что это часть дан­ных для объ­ек­та-диа­ло­га, соз­да­вае­мо­го при вы­зо­ве это­го ко­да). Здесь есть да­же под­хо­дя­щее ме­сто для раз­ме­щения умол­чаний – в ме­то­де с именем '''_load_preferences''', а так­же име­ет­ся ком­мен­та­рий '''TODO''', со­об­щаю­щий, что здесь-то и сле­ду­ет раз­местить зна­чения по умол­чанию. Здесь и вве­ди­те&lt;br /&gt;
&lt;br /&gt;
 self._preferences[“savedir”]=”~/”&lt;br /&gt;
&lt;br /&gt;
(Убе­ди­тесь, что в ко­де долж­ное ко­ли­че­ство от­сту­пов, ина­че по­лу­чи­те ошиб­ку). Это ку­со­чек ма­гии со­кра­щений в Linux. Сим­вол «тиль­да» (~) в запи­си пу­ти к фай­лу рас­по­зна­ет­ся как путь к до­машней ди­рек­то­рии поль­зо­ва­те­ля, так что эта стро­ка ав­то­ма­ти­че­ски уста­нав­ли­ва­ет его в ка­че­стве ка­та­ло­га со­хранений, ес­ли поль­зо­ва­тель не из­менит это.&lt;br /&gt;
&lt;br /&gt;
Те­перь до­ба­вим об­ра­бот­чик сиг­на­ла, ко­то­рый мы вве­ли при раз­ра­бот­ке ин­тер­фей­са поль­зо­ва­те­ля. Раз­местить его мож­но в лю­бом месте клас­са, но, на­вер­но, луч­шим ва­ри­ан­том бу­дет непо­сред­ствен­но пе­ред стро­кой, на­чи­наю­щей­ся с '''def ok(self,widget,...''' – об­ра­бот­чи­ком на­жа­тия кла­ви­ши '''OK''':&lt;br /&gt;
&lt;br /&gt;
 def folder_changed(self, widget, data=None):&lt;br /&gt;
 self._preferences[“savedir”]=widget.get_current_folder()&lt;br /&gt;
&lt;br /&gt;
Все очень про­сто. В ''PyGTK'', вид­жет, по­даю­щий сиг­нал, вклю­ча­ет са­мо­го се­бя в об­рат­ный вы­зов об­ра­бот­чи­ка. Как мы зна­ем, это сиг­нал от '''FileChooserDialog;''' мы так­же зна­ем, что у него есть ме­тод до­бы­вания те­ку­ще­го вы­бран­но­го зна­чения (в ви­де стро­ки), и мож­но про­сто со­хранить их в на­шем сло­ва­ре на­стро­ек.&lt;br /&gt;
&lt;br /&gt;
Тут, од­на­ко, вста­ет ин­те­рес­ный во­прос: с ка­ким зна­чением по­яв­ля­ет­ся вид­жет? От­вет та­ков: ес­ли мы ранее ниче­го не оп­ре­де­ли­ли, то за­пуска­ет­ся он с пустым зна­чением. Это мо­жет обеску­ра­жить поль­зо­ва­те­ля; нуж­но за­ранее вклю­чить неко­то­рый код, что­бы кор­рект­но за­дать зна­чение. Для это­го по­тре­бу­ет­ся раз­до­быть ссыл­ку на сам вид­жет.&lt;br /&gt;
&lt;br /&gt;
Код в на­шем фай­ле ис­поль­зу­ет са­мо­стоя­тель­ный сбор­щик при­ло­жения для соз­дания ре­аль­но­го диа­ло­га из фай­ла '''.ui''', ко­то­рый мы со­хранили, так что на гра­фи­че­ский ин­тер­фейс ссыла­ют­ся локаль­но че­рез объ­ект '''self.builder'''. Имя вид­же­та мы помнимn ('''filechooserbutton1'''), и мо­жем про­сто ра­зы­скать этот объ­ект и со­хранить в нем пе­ре­мен­ную с на­строй­ка­ми при по­мо­щи под­хо­дя­ще­го ме­то­да:&lt;br /&gt;
&lt;br /&gt;
 o=self.builder.get_object(‘filechooserbutton1’)&lt;br /&gt;
 o.set_current_folder(self._preferences[“savedir”])&lt;br /&gt;
&lt;br /&gt;
Луч­ше все­го раз­местить это где-то сра­зу по­сле соз­дания диа­ло­га и за­груз­ки на­стро­ек. К сча­стью, вы вновь об­на­ру­жи­те по­лез­ную за­мет­ку где-то в стро­ке 60: '''#TODO: code for other initialization actions should be added here''' [#Сде­лать: код дру­гих дей­ствий инициа­ли­за­ции сле­ду­ет раз­местить здесь], так что до­бавь­те его сра­зу по­сле нее (точ­ный но­мер стро­ки за­ви­сит от дру­гих функ­ций, та­ких как генера­ция ли­цен­зии и про­чее – про­сто при­зо­ви­те свой ин­тел­лект, что­бы най­ти ее!).&lt;br /&gt;
&lt;br /&gt;
Итак, мы соз­да­ли ме­сто для хранения на­стро­ек, при­вя­за­ли сиг­нал к ме­то­ду по­лу­чения но­во­го зна­чения при его из­менении поль­зо­ва­те­лем и не за­бы­ли взять зна­чение и по­местить его в вид­жет при от­кры­тии диа­ло­га. Код для кноп­ки '''OK''' по­за­бо­тит­ся о со­хранении лю­бых из­менений. На­до еще что-нибудь?&lt;br /&gt;
&lt;br /&gt;
Что про­изой­дет, ес­ли поль­зо­ва­тель из­менит ка­та­лог, а за­тем пе­ре­ду­ма­ет и на­жмет кноп­ку '''Cancel''' [От­ме­на]? Со­глас­но те­ку­ще­му ко­ду, на­строй­ки из­ме­ня­ют­ся (но не со­хра­ня­ют­ся) в мо­мент, когда поль­зо­ва­тель вы­би­ра­ет дру­гой ка­та­лог. Ес­ли он на­жм­ет '''Cancel''', то ка­та­лог хо­тя и не со­хранит­ся, но оста­нет­ся в па­мя­ти как вы­бран­ный па­ра­метр на­строй­ки. Сле­ду­ет учесть это и дать знать основ­но­му при­ло­жению об из­менении па­ра­мет­ров, про­сто пе­ре­за­гру­зив их из ба­зы дан­ных при за­кры­тии диа­ло­га. Для это­го нуж­но из­менить глав­ный файл '''MyApp.py''' (ну или как вы там его на­зва­ли), а так­же обес­пе­чить, что­бы на­строй­ки за­гру­жа­лись при стар­те при­ло­жения. Код, вы­пол­няю­щий это, прак­ти­че­ски тот же, и не будь он все­го из двух строк, его сле­до­ва­ло бы офор­мить в ви­де функ­ции:&lt;br /&gt;
&lt;br /&gt;
 dlg = PreferencesPlopDialog.PreferencesPlopDialog()&lt;br /&gt;
 self.preferences = dlg.get_preferences()&lt;br /&gt;
&lt;br /&gt;
Здесь про­сто соз­да­ет­ся (но не по­ка­зы­ва­ет­ся) диа­лог, а за­тем из него бе­рут­ся на­строй­ки. Ме­сто для это­го ко­да в основ­ном фай­ле – при­бли­зи­тель­но око­ло стро­ки 90 (по­сле ком­мен­та­рия '''# Code for other initialization actions should be added here''' [осталь­ной код инициа­ли­за­ции раз­местить здесь]) и стро­ки 103 (по­сле ком­мен­та­рия '''# Make any updates based on changed preferences here''' [Лю­бые из­менения на осно­ве па­ра­мет­ров на­строй­ки вы­пол­-нять здесь]).&lt;br /&gt;
&lt;br /&gt;
Это­го долж­но хватить. Те­перь за­пусти­те при­ло­жение и по­смот­ри­те, как оно ра­бо­та­ет. Про­тести­руй­те вы­бор ка­та­ло­га и за­крой­те и от­крой­те при­ло­жение вновь, пре­ж­де чем мы двинем­ся даль­ше.&lt;br /&gt;
&lt;br /&gt;
ОК, до сих пор мы вас ща­ди­ли, по­сколь­ку вы, ско­рее все­го, но­вич­ки в ''Quickly'', но те­перь вы знае­те до­ро­гу, и нам сле­ду­ет уско­рить­ся, ес­ли мы хо­тим за­вер­шить наш за­груз­чик под­кастов – уж из­вините, ка­ж­дое на­жа­тие кноп­ки раз­же­вы­вать не бу­дем. Ес­ли вы в чем-то не уве­ре­ны, все­гда мож­но об­ра­тить­ся к фай­лам про­ек­та на '''LXFDVD'''!&lt;br /&gt;
&lt;br /&gt;
На­ша сле­дую­щая за­да­ча – соз­дать основ­ной ин­тер­фейс, так что на­бе­ри­те ''quickly design'' и за­гру­зи­те со­от­вет­ствую­щий файл. Уда­ли­те имею­щие­ся там объ­ек­ты, но вер­тикаль­ный кон­тейнер мож­но оста­вить.&lt;br /&gt;
&lt;br /&gt;
Нам ну­жен спо­соб по­ка­зать спи­сок источников и спи­сок фай­лов вы­бран­но­го источника. Это мож­но сде­лать по-раз­но­му, но в на­шем при­ло­жении мы восполь­зу­ем­ся про­смот­ром в го­ри­зон­таль­ной панели, что­бы два спи­ска раз­де­ля­лись вер­тикаль­ной чер­той. Дей­ствуй­те: раз­мести­те ее в пустом кон­тейнере.&lt;br /&gt;
&lt;br /&gt;
Внутрь ка­ж­дой панели сле­ду­ет по­местить кон­тейнер '''Про­кру­чи­вае­мое ок­но''' (возь­мем его в том же раз­де­ле па­лит­ры сле­ва), это по­мо­жет про­смат­ри­вать спи­ски боль­шой дли­ны.&lt;br /&gt;
&lt;br /&gt;
Те­перь в пра­вой панели раз­мести­те объ­ект '''Де­ре­во'''. Это по­хо­же на спи­сок, и мы бу­дем при­ме­нять его для ото­бра­жения гра­фи­ки, иден­ти­фи­ци­рую­щей под­касты, на ко­то­рые мы подпи­са­ны. При раз­ме­щении объ­ек­та '''Де­ре­во''' ''Glade'' по­тре­бу­ет ука­зать его мо­дель. Про­сто соз­дай­те но­вую. Мо­дель – это обыч­ный спи­сок ти­пов дан­ных и ме­ток, ис­поль­зую­щих­ся для манипу­ля­ций с дан­ны­ми или ото­бра­жения их в ин­тер­фей­се поль­зо­ва­те­ля. Мы начнем с че­ты­рех зна­чений – '''guint''' (це­лое без зна­ка) с именем '''source_id''', '''gchararray''' (мас­сив сим­во­лов – стро­ка) с именем '''source_name''', еще один '''gchararray''' с именем '''source_url''' и '''GdkPixBuf''' (мас­сив пик­се­лей) с именем '''source_img'''.&lt;br /&gt;
&lt;br /&gt;
===Что это бы­ло?===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF134_72_1.jpg|300px]] Ра­ди это­го стои­ло по­по­теть — те­перь мож­но слу­шать бри­тан­скую ко­ман­ду LXF, ко­гда толь­ко за­хо­чет­ся.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
По­следний тип – изо­бра­жение; по умол­чанию, его-то мы и бу­дем ото­бра­жать спра­ва. Щелкните по объ­ек­ту Де­ре­во в дре­во­вид­ном спи­ске объ­ек­тов и вы­бе­ри­те пункт ме­ню '''Edit''', что­бы ре­дак­ти­ро­вать свой­ства объ­ек­та бо­лее под­роб­но в от­дель­ном окне. Про­кру­чи­вай­те вниз, по­ка не уви­ди­те пункт «'''Стол­бец всплы­ваю­щей под­сказ­ки'''», и вве­ди­те зна­чение «'''1'''». Этим мы вы­би­ра­ем пер­вый стол­бец толь­ко что соз­дан­но­го спи­ска (мо­де­ли) в ка­че­стве всплы­ваю­щей под­сказ­ки к ка­ж­дой запи­си. Те­перь пе­рей­ди­те на вклад­ку '''Ие­рар­хия''' и на­жми­те внизу спи­ска кноп­ку '''До­ба­вить''', и до­бавь­те од­ну ко­лон­ку. Спра­ва за­да­ет­ся за­го­ло­вок и на­бор свойств. Те­перь щелкните на до­бав­лен­ном столб­це пра­вой кноп­кой мы­ши и в поя­вив­шем­ся ме­ню вы­бе­ри­те ‘'''До­ба­вить до­черний эле­мент Изо­бра­жение'''’. В панели спра­ва уста­но­ви­те для пунк­та '''Объ­ект''' зна­чок (Pixbuf) в зна­чение '''3''', или вы­бе­ри­те '''source_img''' в вы­па­даю­щем спи­ске. Это по­зво­лит ото­бра­жать на­ше изо­бра­жения в спи­ске в ячей­ках.&lt;br /&gt;
&lt;br /&gt;
Пе­ред вы­хо­дом до­бавь­те ссыл­ку на об­ра­бот­чик сиг­на­ла. На вклад­ке '''Сиг­на­лы''' объ­ек­та '''Де­ре­во''', най­ди­те пункт ‘'''row-activated'''’ и до­бавь­те запись с именем ‘'''row_chosen'''’. Со­храните все!&lt;br /&gt;
&lt;br /&gt;
При­шло вре­мя по­ра­бо­тать с ко­дом. Пре­ж­де все­го нам ну­жен хит­рый ме­тод для из­вле­чения изо­бра­жения-икон­ки для кон­крет­ной лен­ты. Мы мо­жем ука­зать URL и из­влечь изо­бра­жение Pixbuf. Лег­ко! (Это ес­ли вы сле­ди­ли за на­шей се­ри­ей.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 def fetch_image(self,url):&lt;br /&gt;
  import feedparser,urllib&lt;br /&gt;
  #най­дем имя изо­бра­же­ния&lt;br /&gt;
  f=feedparser.parse(url)&lt;br /&gt;
  name = f.feed.image.href&lt;br /&gt;
  imgfile,data = urllib.urlretrieve(name)&lt;br /&gt;
  img=gtk.gdk.pixbuf_new_from_file(imgfile)&lt;br /&gt;
  img=img.scale_simple(150,150,gtk.gdk.INTERP_BILINEAR)&lt;br /&gt;
  return img&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На до­су­ге мож­но по­ду­мать и о кэ­ши­ро­вании изо­бра­жений (помните: име­на фай­лов мо­гут кон­флик­то­вать, так что не помешает до­бав­лять к ним и хэш URL’а); но по­ка оста­вим это. Они, конеч­но, бу­дут за­гру­жать­ся при ка­ж­дом за­про­се, но благодаря их ма­лому раз­ме­ру вы ед­ва ли по­чув­ствуе­те серьезное снижение ско­ро­сти.&lt;br /&gt;
&lt;br /&gt;
Объ­е­дините этот ме­тод с дру­ги­ми в глав­ном фай­ле '''MyApp.py''', и раз уж файл от­крыт, про­смот­ри­те код, сле­дую­щий по­сле ком­мен­та­рия '''# Code for other initialization actions should be added here'''&lt;br /&gt;
[осталь­ной код инициа­ли­за­ции раз­местить здесь]. До­бавь­те сле­дую­щий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 store1=self.builder.get_object(“liststore1”)&lt;br /&gt;
 for index, sub in enumerate(self.preferences[‘subs’]):&lt;br /&gt;
   # струк­ту­ра дан­ных subs долж­на&lt;br /&gt;
   # со­дер­жать name и url&lt;br /&gt;
   img=self.fetch_image(sub[1])&lt;br /&gt;
   store1.append([index,sub[0],sub[1],img])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пе­ре­мен­ная '''store1''' со­дер­жит объ­ект '''liststore''', генери­руе­мый в UI, и мы мо­жем за­полнить его дан­ны­ми. Я так ви­жу, что дан­ные о на­ших лен­тах бу­дут хранить­ся в на­строй­ках в ви­де спи­ска: имя лен­ты и URL (мы сде­ла­ем это че­рез ми­ну­ту). Ис­поль­зуя URL, мы до­бу­дем изо­бра­жение и по­местим весь на­бор в хранили­ще спи­ска. Про­смотр в цик­ле (по спи­ску спи­сков) соз­да­ет до­полнитель­ную пе­ре­мен­ную – но­мер ите­ра­ции; его мы ис­поль­зу­ем для соз­дания иден­ти­фи­ка­то­ра ID. Оста­лось толь­ко вер­нуть­ся в файл '''PreferencesMyAppDialog.py''' и до­ба­вить сле­дую­щее к пе­ре­мен­ным по умол­чанию:&lt;br /&gt;
&lt;br /&gt;
 self._preferences[“subs”]=[[“Tux Radar podcast (ogg) “http:// www.tuxradar.com/files/podcast/podcast_ogg.rss”]]&lt;br /&gt;
&lt;br /&gt;
По­мести­те это сра­зу по­сле умол­чаний '''savedir''', вве­ден­ных на­ми ранее. Со­храните все опять и вновь за­пусти­те при­ло­жение. Те­перь вы долж­ны уви­деть за­гру­жен­ный ло­го­тип TuxRadar в ле­вой панели!&lt;br /&gt;
&lt;br /&gt;
Соз­дание при­ло­жений с гра­фи­че­ским ин­тер­фей­сом на­чи­на­ет на­по­ми­нать уп­ражнение в про­клад­ке труб. В на­шем пер­вом спи­ске необ­хо­ди­мо что-то сде­лать, ес­ли кто-то вы­бе­рет в нем эле­мент. Ме­ханизм дей­ствий та­кой: пе­ре­хва­ты­ва­ем сиг­нал, по­да­вае­мый спи­ском, а за­тем де­ла­ем нечто с дру­гим спи­ском; на­до лишь со­единить ме­ж­ду со­бой части ко­да. Нас не вол­ну­ет, когда они бу­дут ис­пол­нять­ся – это де­ло поль­зо­ва­те­ля; глав­ное – про­ду­мать все по­след­ствия пред­принимае­мых дей­ствий.&lt;br /&gt;
&lt;br /&gt;
===Поль­зуй­тесь жур­на­лом===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF134_73_1.jpg|300px]] За­пуск при­ло­же­ния с оп­ци­ей '''-v''' по­зво­ля­ет вес­ти жур­нал. Я на­пло­дил их не­ма­ло — они бес­цен­ны при от­лад­ке.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Древ­ний при­ем на­шпи­го­вы­вать про­грам­му опе­ра­то­ра­ми вы­во­да раз­лич­ных зна­че­ний и объ­ек­тов для про­вер­ки – это от­стой. Оно, ко­неч­но, по­мо­га­ет, но по­сле от­лад­ки ка­кой-ли­бо час­ти ко­да их нуж­но вы­чи­щать, не то ваш код раз­бух­нет и при ка­ж­дом за­пус­ке кон­соль бу­дет за­пол­нять­ся му­со­ром. Ос­нов­ной файл про­грам­мы, соз­да­вае­мый ''Quickly'', ини­циа­ли­зи­ру­ет жур­нал, соз­да­вае­мый со­от­вет­ст­вую­щим мо­ду­лем ''Python'', ес­ли вы за­пус­ти­те при­ло­же­ние с клю­чом '''-v''' (это мож­но де­лать и в ''Quickly''). Так что для вы­во­да со­об­ще­ний про­сто ис­поль­зуй­те:&lt;br /&gt;
&lt;br /&gt;
 logging.debug(“ prefs= %s”,self.preferences[‘subs’])&lt;br /&gt;
&lt;br /&gt;
Этот ме­тод сле­ду­ет стан­дарт­ным пра­ви­лам под­ста­нов­ки; его пре­лесть в том, что вы­вод он про­из­во­дит, толь­ко ес­ли его об этом просят.&lt;br /&gt;
&lt;br /&gt;
===Тру­бо­про­во­ды===&lt;br /&gt;
&lt;br /&gt;
Пре­ж­де чем под­клю­чать­ся ко вто­ро­му спи­ску, не ху­до уз­нать, что в нем со­дер­жит­ся. От­крой­те ''Glade'' сно­ва и раз­мести­те '''Де­ре­во''' во вто­ром про­кру­чи­вае­мом окне. В соз­дан­ном для него пред­став­лении спи­ском сле­ду­ет соз­дать несколь­ко столб­цов – '''boolean''' (ло­ги­че­ское) с именем '''downloaded''' [за­гру­же­но], '''gfloat''' (чис­ло с пла­ваю­щей точ­кой) с именем '''progress''' [про­гресс] и во­семь '''gchararrays''' – их я на­завл '''title''' [на­звание], '''subtitle''' [под­за­го­ло­вок], '''summary''' [опи­сание], '''tags''' [тэ­ги], '''size''' [раз­мер], '''duration''' [дли­тель­ность], '''media_type''' [тип со­дер­жи­мо­го] и '''media_url''' [URL со­дер­жи­мо­го]. Их на­зна­чение яс­но из имен, и, че­ст­но го­во­ря, де­ло до них ско­рее все­го не дой­дет.&lt;br /&gt;
&lt;br /&gt;
Есте­ствен­но бы­ло бы хранить все эти дан­ные в объ­ек­те и ко­пи­ро­вать его в мо­дель спи­ска при необ­хо­ди­мо­сти, но в ито­ге у вас по­лу­чит­ся две ко­пии всех дан­ных, и за­бо­та об их син­хрониза­ции станет про­бле­мой – на­ко­пив опыт, вы при­де­те к вы­во­ду, что про­ще хранить дан­ные в спи­ске-пред­став­лении и ссылать­ся на не­го при необ­хо­ди­мо­сти, а не оп­ра­ши­вать пе­ре­мен­ные на ка­ж­дом ша­гу. При до­бав­лении столб­цов в са­мо '''Де­ре­во''', нет ну­ж­ды до­бав­лять все, од­на­ко пер­вым до­бавь­те '''cellrendererprogress''' и свя­жи­те его с дан­ны­ми о про­грес­се вы­полнения.&lt;br /&gt;
&lt;br /&gt;
Для это­го '''Де­ре­ва''' же­ла­тель­но убе­дить­ся, что в мет­ке '''Об­щие''' для свой­ства '''Со­бы­тия''' уста­нов­ле­но зна­чение '''по­лу­чать все'''. Так­же до­бавь­те сиг­нал с именем '''file_chosen''' в '''row-activated'''. Мы соз­да­дим для него ме­тод об­ра­бот­ки двой­но­го щелч­ка на фай­ле.&lt;br /&gt;
&lt;br /&gt;
Для из­вле­чения дан­ных и со­дер­жи­мо­го в ваш спи­сок-пред­став­ление до­бавь­те та­кой код в глав­ный файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
  def row_chosen(self,treeview,selection,treeviewcolumn):&lt;br /&gt;
     “”” Обработчик сигнала для выбора элемента в строке источника”””&lt;br /&gt;
     import feedparser&lt;br /&gt;
     listmodel=treeview.get_model()&lt;br /&gt;
     store2=self.builder.get_object(“liststore2”)&lt;br /&gt;
     store2.clear()&lt;br /&gt;
    savedir=self.preferences[“savedir”]&lt;br /&gt;
    index=listmodel.get_iter(selection[0])&lt;br /&gt;
    source_url =listmodel.get_value(index,2)&lt;br /&gt;
    # получаем список файлов&lt;br /&gt;
    f=feedparser.parse(source_url)&lt;br /&gt;
    for entry in f.entries:&lt;br /&gt;
      media_url=entry.enclosures[0][“href”]&lt;br /&gt;
      logging.debug(“media url = %s”,media_url)&lt;br /&gt;
      fname=os.path.split(media_url)[­1]&lt;br /&gt;
      #проверяем что файл уже загру жен&lt;br /&gt;
      downloaded=os.path.exists(os.path.join(savedir,fname))&lt;br /&gt;
      progress=0.0&lt;br /&gt;
      if downloaded:&lt;br /&gt;
         progress=100&lt;br /&gt;
      title= entry.title if entry.has_key(“title”) else “Unnamed”&lt;br /&gt;
      subtitle= entry.subtitle if entry.has_key(“subtitle”) else “no information”&lt;br /&gt;
      summary=entry.summary if entry.has_key(“summary”) else “no information”&lt;br /&gt;
      tags = ‘’&lt;br /&gt;
      if entry.has_key(“tags”):&lt;br /&gt;
         for item in tags:&lt;br /&gt;
           tags+=item.term&lt;br /&gt;
      size= entry.enclosures[0].length&lt;br /&gt;
      duration= entry.itunes_duration if entry.has_key(‘itunes_duration’) else “??:??”&lt;br /&gt;
      media_type= entry.enclosures[0].type&lt;br /&gt;
      logging.debug(“data:%s”,[downloaded,progress,title,subtitle,summary,tags,size,duration,media_type,media_url])&lt;br /&gt;
      store2.append([downloaded,progress,title,subtitle,summary,tags,size,duration,media_type,media_url])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF134_74_1.jpg|300px]] Во вто­ром де­ре­ве боль­ше эле­мен­тов. Не обя­за­тель­но до­бав­лять их толь­ко для ото­бра­же­ния — мож­но, ска­жем, ис­поль­зо­вать текст опи­са­ния для под­сказ­ки.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Здесь нет ниче­го сверх­слож­но­го. Мы рас­смат­ри­ва­ли чтение RSS-лент в пре­ды­ду­щих учебниках: при лю­бой об­ра­бот­ке RSS-лент, в фор­ма­те Atom или нет, неза­чем искать до­б­ра от до­б­ра, а точнее – за­ме­ча­тель­но­го мо­ду­ля ''Feedparser'' от Мар­ка Пил­гри­ма [Mark Pilgrim] (http://www.feedparser.org). По скры­тым от че­ло­ве­че­ства при­чи­нам этот мо­дуль не вклю­чен в стан­дарт­ный пан­те­он при уста­нов­ке при­ло­жений Ubuntu, но до­ба­вить его про­ще про­сто­го: ''sudo apt-get install python-feedparser''. Под­лин­ная кра­со­та это­го мо­ду­ля в том, что он про­че­сы­ва­ет все мыс­ли­мые фор­ма­ты лент и вы­да­ет при­ят­ный объ­ект ''Python'', с ко­то­рым уже мож­но ра­бо­тать, не пу­та­ясь со вся­ки­ми уз­ла­ми, про­вер­ка­ми ис­поль­зуе­мой вер­сии RSS и про­чим. Пе­ре­дае­те ему URL лен­ты – по­лу­чае­те чет­кую струк­ту­ру. Для лен­ты под­кастов воз­вра­щае­мый объ­ект бу­дет со­дер­жать раз­лич­ные кон­тейнеры '''entry''' [запись], с ин­фор­ма­ци­ей о ка­ж­дом доступ­ном эпи­зо­де. Они раз­би­ва­ют­ся на несколь­ко стан­дарт­ных по­лей – за­го­ло­вок, опи­сание, тэ­ги, а так­же ин­фор­ма­цию о да­те и URL для ме­диа-со­дер­жи­мо­го, что вполне доста­точ­но для соз­дания таб­ли­цы эпи­зо­дов.&lt;br /&gt;
&lt;br /&gt;
===Для вы­бо­ра фай­ла…===&lt;br /&gt;
&lt;br /&gt;
С этим ра­зо­бра­лись; те­перь об­ра­бо­та­ем сиг­нал, по­лу­чае­мый при вы­бо­ре фай­ла. До­бавь­те сле­дую­щий ме­тод:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
  def file_chosen(self, treeview,selection,column):&lt;br /&gt;
    import thread&lt;br /&gt;
    listmodel=treeview.get_model()&lt;br /&gt;
    index=listmodel.get_iter(selection[0])&lt;br /&gt;
    downloaded=listmodel.get_value(index,0)&lt;br /&gt;
    if downloaded:&lt;br /&gt;
       self.file_play(listmodel.get_value(index,9))&lt;br /&gt;
    else:&lt;br /&gt;
       self.file_download(listmodel,index)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Он определяет, какой файл выбран, и проверяет, не загру­жен ли он. Если да, подставляется ссылка на другой обработчик:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
  def file_play(self,url):&lt;br /&gt;
    “”” Инициа лизирует PlayerDialog и проиг рывает за данный файл”””&lt;br /&gt;
    logging.debug(“caught signal for file play”)&lt;br /&gt;
    filename=os.path.split(url)[­1]&lt;br /&gt;
    filename=os.path.join(self.preferences[“savedir”],filename)&lt;br /&gt;
    player=PlayerDialog.PlayerDialog()&lt;br /&gt;
    player.set_playfile(filename)&lt;br /&gt;
    player.run()&lt;br /&gt;
    player.destroy()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Во­об­ще-то здесь об­ра­ща­ют­ся к но­во­му диа­ло­гу. Что­бы все ра­бо­та­ло, до­бавь­те диа­лог че­рез ''Quickly'', вклю­чив его в опи­са­ние про­ек­та. Для это­го в ка­та­ло­ге про­ек­та вве­ди­те ''quickly add dialog Player'' Об осталь­ном по­за­бо­тит­ся ''Quickly''. За­тем вы мо­же­те от­крыть эти фай­лы и из­менить их при по­мо­щи ''quickly edit'' и ''quickly design''. Наш ин­тер­фейс диа­ло­га – это все­го лишь сиг­нал, по­ка­зы­ваю­щий: что-то слу­чи­лось, и мы от­реа­ги­ро­ва­ли. Ес­ли че­ст­но, то и в ко­де про­иг­ры­ва­те­ля ма­ло что про­ис­хо­дит. Это про­сто бы­ст­рый спо­соб из­дать звук.&lt;br /&gt;
&lt;br /&gt;
В кон­це ме­то­да '''finish_initializing''' нуж­но соз­дать про­иг­ры­ва­тель из мо­ду­ля '''gst''' (ах да, необ­хо­ди­мо до­ба­вить в на­ча­ло фай­ла '''import gst'''):&lt;br /&gt;
&lt;br /&gt;
 self.player=gst.element_factory_make(“playbin”,”PodPlayer”)&lt;br /&gt;
&lt;br /&gt;
За­тем мы про­сто реа­ли­зу­ем ме­тод про­иг­ры­ва­ния фай­ла:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 def set_playfile(self,filename):&lt;br /&gt;
  #по­лу­ча­ет путь к фай­лу и за­пус­ка­ет про­иг­ры­ва­тель&lt;br /&gt;
  uri =”file://”+filename&lt;br /&gt;
  print uri&lt;br /&gt;
  self.player.set_property(“uri”,uri)&lt;br /&gt;
  self.player.set_state(gst.STATE_PLAYING)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF134_74_2.jpg|300px]] Как вид­но, про­иг­ры­ва­тель — лишь мо­даль­ный диа­лог, по­ро­ж­даю­щий эк­зем­п­ляр ''Gstreamer'', но сто­рон­ние раз­ра­бот­ки при­вет­ст­ву­ют­ся!|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Да не за­будь­те оста­но­вить про­иг­ры­ва­тель. Не оболь­щай­тесь, что объ­ект бу­дет унич­то­жен вме­сте с мо­даль­ным диа­ло­гом: звук в Linux – шту­ка ка­приз­ная, и вы неод­но­крат­но мо­же­те столк­нуть­ся с си­туа­ци­ей упор­но­го про­иг­ры­вания MP3‑фай­лов, хо­тя пред­по­ла­га­лось, что воспро­из­ве­дение оста­нов­ле­но. Мож­но про­сто по­местить вы­зов оста­нов­ки про­иг­ры­ва­те­ля в об­ра­бот­чик кно­пок '''OK''' и '''Cancel'''.&lt;br /&gt;
&lt;br /&gt;
 self.player.set_state(gst.STATE_PAUSED)&lt;br /&gt;
&lt;br /&gt;
Этот код по­за­бо­тит­ся о том, что­бы под­кас­ты не пе­ре­тру­ди­лись.&lt;br /&gt;
&lt;br /&gt;
Оста­лось по­за­бо­тить­ся о са­мой за­груз­ке ме­диа-фай­лов. Для по­лу­чения фай­лов восполь­зу­ем­ся '''urllib.urlretrieve()''': это часть стан­дарт­но­го па­ке­та ''Python'', и она ра­бо­та­ет доста­точ­но хо­ро­шо. В этом ко­де есть два хит­рых трю­ка, и его сле­ду­ет немно­го по­яснить.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 def file_download(self,listmodel,index):&lt;br /&gt;
   import urllib,thread&lt;br /&gt;
   url=listmodel.get_value(index,9)&lt;br /&gt;
   savename=os.path.split(url)[-1]&lt;br /&gt;
   savename=os.path.join(self.preferences[“savedir”],savename)&lt;br /&gt;
   reporthook = lambda a,b,c : self.progress_update(listmodel,index,a,b,c)&lt;br /&gt;
   thread.start_new_thread( urllib.urlretrieve,(url,savename,reporthook))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ме­тод '''urlretrieve''' пре­ду­смат­ри­ва­ет об­рат­ный вы­зов. Бе­да в том, что по­следний воз­вра­ща­ет лишь дан­ные о за­гру­жен­ных бло­ках, и ниче­го о за­гру­жае­мом фай­ле. За­пустив сра­зу несколь­ко за­гру­зок, мы уже не смо­жем рас­смат­ри­вать их по от­дель­но­сти. Я в об­щем про­тив при­менения лям­бда-функ­ций (функ­ций, встро­ен­ных в ''Python'') – они неред­ко услож­ня­ют понимание ко­да. Од­на­ко в дан­ном слу­чае ис­поль­зо­вание лям­бда-функ­ций в ка­че­стве про­кси оз­на­ча­ет, что мы мо­жем до­бав­лять по­лез­ную ин­фор­ма­цию к от­кли­ку про­цес­са за­груз­ки и пе­ре­да­вать ее в сле­дую­щую функ­цию. Пре­ж­де чем брать­ся за это, рас­смот­рим еще од­ну ис­поль­зуе­мую здесь улов­ку – а имен­но, по­то­ки.&lt;br /&gt;
&lt;br /&gt;
===При­ят­ные по­то­ки===&lt;br /&gt;
&lt;br /&gt;
Про­стой слу­чай по­то­ков (см. по­след­нюю стро­ку) оз­на­ча­ет, что мож­но за­пускать по­ток, пред­ста­вив функ­цию и ее ар­гу­мен­ты в ви­де кор­те­жа. Без по­то­ков ра­бо­та при­ло­жения бу­дет приоста­нов­ле­на до тех пор, по­ка файл не за­гру­зит­ся – оно не бу­дет ни на что от­кли­кать­ся, и поль­зо­ва­тель мо­жет ре­шить, что оно за­вис­ло. Вдо­ба­вок наш удоб­ный ин­ди­ка­тор про­грес­са бу­дет бес­по­ле­зен. Для соз­дания об­рат­ной свя­зи нам необ­хо­дим вто­рой ме­тод:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 def progress_update(self, listmodel,index,a,b,c):&lt;br /&gt;
  “”” Функ­ция об­рат­но­го вы­зо­ва, от­ра­жаю­щая про­гресс в таб­ли­це. Не­об­хо­ди­мы по­то­ки!”””&lt;br /&gt;
  blocks = float(c/b)&lt;br /&gt;
  progress=float(a/blocks)*100&lt;br /&gt;
  if progress &amp;gt; 100:&lt;br /&gt;
   progress = 100&lt;br /&gt;
   listmodel.set(index,0,True)&lt;br /&gt;
 listmodel.set(index,1,progress)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь вы­чис­ля­ет­ся про­цент за­вер­шен­но­сти и со­от­вет­ствен­но об­нов­ля­ет­ся мо­дель пред­став­ления спи­ска. Мож­но за­пустить несколь­ко за­гру­зок од­но­вре­мен­но, и при­ло­жение бу­дет об­нов­лять их все. Ис­ход­ная идея бы­ла в том, что­бы ин­ди­ка­тор про­грес­са ото­бра­жал­ся под ка­ж­дым эле­мен­том на всю ши­ри­ну ок­на. К со­жа­лению, ''GTK'' не под­дер­жи­ва­ет такого на­пря­мую (по крайней ме­ре, по­ка), но ес­ли вы же­лае­те соз­дать ваш соб­ствен­ный ва­ри­ант от­ри­сов­ки, то сде­лай­те это и дай­те нам знать, по­жа­луй­ста!&lt;br /&gt;
&lt;br /&gt;
Что­бы за­ста­вить по­то­ки ра­бо­тать, при­пи­ши­те сле­дую­щее в конец основ­но­го фай­ла, сра­зу по­сле '''import optparse''':&lt;br /&gt;
&lt;br /&gt;
 import gobject&lt;br /&gt;
 gobject.threads_init()&lt;br /&gt;
&lt;br /&gt;
Ес­ли это­го не сде­лать, ''GTK''-часть при­ло­жения не по­ла­дит с мо­ду­лем по­то­ков ''Python''.&lt;br /&gt;
&lt;br /&gt;
===Ле­ти­те на во­лю===&lt;br /&gt;
&lt;br /&gt;
Ес­ли вы про­бо­ва­ли при­ло­жение по хо­ду уро­ка, то те­перь уви­ди­те, что оно вполне го­то­во к упот­реб­лению. Конеч­но, до­ра­бо­тать еще есть что, и, кста­ти, в ис­ход­ном ко­де в се­ти или на DVD раз­бро­са­но мно­же­ство при­ме­чаний и за­дач '''[TODO]'''. Для на­ча­ла, несколь­ко пунк­тов ме­ню не ра­бо­та­ют! Ох, и еще од­на за­гвозд­ка – мы так и не да­ли поль­зо­ва­те­лю воз­мож­ность до­бав­лять свои лен­ты под­кастов (это ес­ли им ма­ло од­но­го TuxRadar...).&lt;br /&gt;
&lt;br /&gt;
Од­на­ко мы долж­ны вы­полнить по­след­нюю часть на­шей мис­сии, то есть вы­пустить при­ло­жение на во­лю. Коман­да­ми ''Quickly'' это де­ла­ет­ся лег­ко, нуж­на толь­ко учет­ная запись на Launchpad. Ес­ли у вас та­кой нет, соз­дать ее недол­го; но что­бы вы­гру­жать дан­ные в PPA, по­тре­бу­ет­ся так­же иметь ключ GPG и от­кры­тый ключ ''SSH'', для про­вер­ки ва­ших фай­лов.&lt;br /&gt;
&lt;br /&gt;
Ну, а для про­сто­го соз­дания Deb-фай­ла и то­го не на­до. Про­сто вве­ди­те коман­ду ''quickly package'', и скрип­ты по­тру­дят­ся за вас, соз­дав го­то­вый к рас­про­странению Deb-па­кет. Ес­ли вы упор­но же­лае­те вы­гру­зить­ся на Launchpad, сде­лай­те это коман­дой ''quickly release'', про­сто сле­дуя ее ин­ст­рук­ци­ям. Од­на­ко хо­ро­шей иде­ей бу­дет сна­ча­ла пред­ста­вить­ся ''Bazaar'', а за­тем убе­дить­ся, что ваш поч­то­вый ад­рес со­от­вет­ству­ет учет­ной запи­си Launchpad:&lt;br /&gt;
&lt;br /&gt;
 bzr whoami ‘My Name &amp;lt;email@example.com&amp;gt;’&lt;br /&gt;
&lt;br /&gt;
''Quickly'' раз­ме­ща­ет­ся на Launchpad (https://launchpad.net/quickly); соз­дав свою учет­ную за­пись, вы смо­же­те за­хо­дить, за­да­вать во­про­сы и ту­со­вать­ся с кру­ты­ми ко­де­ра­ми.&lt;br /&gt;
&lt;br /&gt;
===Шаг за шагом: Соз­да­ем про­стое при­ло­же­ние ''Quickly''===&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF134_69_1.jpg|Шаг 1]]&lt;br /&gt;
* '''1 Соз­да­ем в ''Quickly'''''&lt;br /&gt;
: Что­бы на­чать соз­да­вать свое при­ло­жение, от­крой­те тер­ми­нал и соз­дай­те но­вый ка­та­лог для всех ва­ших ''Quickly''-про­ек­тов коман­дой ''mkdir Quickly''. Вой­ди­те в этот ка­та­лог (''cd Quickly'') – и вы го­то­вы к соз­данию и сбор­ке ва­ше­го пер­во­го при­ло­жения. Вве­ди­те ''quickly create ubuntuapplication MyApp'', и все за­кру­тит­ся. ''Quickly'' соз­даст ка­та­лог и сгенери­ру­ет в нем все необ­хо­ди­мые фай­лы, а имен­но – фай­лы ин­тер­фей­са ''GTK'', фай­лы ''Python'', ба­зы дан­ных и систе­мы управ­ления вер­сия­ми. По за­вер­шении при­ло­жение за­пустит­ся.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF134_69_2.jpg|Шаг 2]]&lt;br /&gt;
* '''2 Про­ек­ти­ру­ем в ''Quickly'''''&lt;br /&gt;
: Вой­ди­те в ка­та­лог про­ек­та '''myapp''' и скоман­дуй­те ''quickly design''. За­пустит­ся ''Glade'', ре­дак­тор гра­фи­че­ских ин­тер­фей­сов для ''GTK'', и в нем ав­то­ма­ти­че­ски от­кро­ет­ся глав­ное ок­но ва­ше­го при­ло­жения. Все фай­лы ин­тер­фей­са поль­зо­ва­те­ля хра­нят­ся в од­ном и том же месте, так что лю­бой диа­лог ва­ше­го при­ло­жения мож­но лег­ко из­менить. Немно­го по­рез­ви­тесь в ''Glade'', ес­ли ранее вы с ним не стал­ки­ва­лись. Свой­ства ка­ж­до­го объ­ек­та лег­ко из­менить при по­мо­щи ин­ст­ру­мен­тов, рас­по­ло­жен­ных в пра­вом нижнем уг­лу. Здесь мы ме­ня­ли текст в на­шей мет­ке. Не за­будь­те со­хранить про­ект пе­ред вы­хо­дом!&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF134_69_3.jpg|Шаг 3]]&lt;br /&gt;
* '''3 Ре­дак­ти­ру­ем в ''Quickly'''''&lt;br /&gt;
: ''Quickly'' ис­поль­зу­ет ре­дак­тор ''Gedit'' из Gnome, пре­крас­но под­хо­дя­щий для неин­тен­сив­ной ра­бо­ты. Кро­ме то­го, он от­сле­жи­ва­ет фай­лы ва­ше­го про­ек­та, по­это­му для их из­менения, на­хо­дясь в тер­ми­нале в глав­ном ка­та­ло­ге при­ло­жения, про­сто вве­ди­те ''quickly edit. Gedit'' поя­вит­ся и от­кро­ет все ''Python''-фай­лы, свя­зан­ные с про­ек­том, так что вы мо­же­те на­чать соз­дание но­вых функ­ций. Из дру­гих фай­лов вы мо­же­те по­же­лать из­менить файл '''AUTHORS''' в глав­ном ка­та­ло­ге про­ек­та. Про­сто вве­ди­те крат­кое со­об­щение об ав­то­ре, что­бы все зна­ли, что это ва­ше. Со­храните файл и вый­ди­те.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF134_69_4.jpg|Шаг 4]]&lt;br /&gt;
* '''4 За­пуска­ем в ''Quickly'''''&lt;br /&gt;
: Пе­ред тем, как вы за­пусти­те свое слег­ка из­менен­ное при­ло­жение, сде­лай­те еще кое-что. В команд­ной стро­ке вве­ди­те ''quickly license''. Это соз­даст со­об­щение об ав­тор­ском пра­ве на осно­вании той ин­фор­ма­ции, что вы вве­ли в фай­ле '''AUTHORS''', и уве­дом­ление GPL v3 (по умол­чанию, хо­тя это мож­но из­менить) в за­го­лов­ке ка­ж­до­го фай­ла с ис­ход­ны­ми ко­да­ми; ну, и еще там всякое. Для за­пуска ва­ше­го при­ло­жения вве­ди­те ''quickly run''. Когда оно от­кро­ет­ся, вы­бе­ри­те в ме­ню '''Help &amp;gt; О про­грам­ме'''. Вы уви­ди­те, что диа­лог из­менил­ся и те­перь со­дер­жит ва­ше со­об­щение об ав­тор­ском пра­ве и ин­фор­ма­цию о ли­цен­зии!&lt;br /&gt;
&lt;br /&gt;
===От­лад­ка в Quickly===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF133_75_1.jpg|300px]] Это не центр управ­ле­ния энер­го­под­стан­ци­ей, это ок­ру­же­ние для от­лад­ки.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Да­же масти­тые ко­де­ры здесь у нас в Башне LXF иногда оши­ба­ют­ся в су­ж­дениях. Во­об­ще-то лю­ди, имею­щие при­выч­ку все оценивать, счи­та­ют, что 80 % вре­мени раз­ра­бот­ки ПО ухо­дит на ис­прав­ление оши­бок. Но ис­прав­ление оши­бок – во­все не ка­тор­га: это путь к от­кры­ти­ям (как мы пы­та­ем­ся убе­дить са­ми се­бя), даю­щий нам ощу­щение востре­бо­ван­но­сти и по­лез­но­сти.&lt;br /&gt;
&lt;br /&gt;
Для ''Python'' име­ет­ся несколь­ко пре­крас­ных ин­ст­ру­мен­тов от­лад­ки, но ''Quickly'' по­став­ля­ет­ся с одним уже на­стро­ен­ным и го­то­вым к ра­бо­те, так что мы восполь­зу­ем­ся им! Воз­мож­но, ранее вы не стал­ки­ва­лись с ''Winpdb'', а он со­дер­жит все функ­ции для по­ша­го­во­го пе­ре­ме­щения ме­ж­ду точ­ка­ми оста­но­ва, ана­ли­за про­стран­ства имен и про­вер­ки по­ве­дения пе­ре­мен­ных. Он оп­ре­де­лен­но бы­ст­рее стан­дарт­но­го ''PDB'', и уз­нать о нем боль­ше мож­но на http://winpdb.org/docs.&lt;br /&gt;
&lt;br /&gt;
===Ис­ход­ные тек­сты===&lt;br /&gt;
&lt;br /&gt;
Ис­ход­ные тек­сты име­ют­ся на '''LXFDVD''', но ес­ли вам лень их ис­кать, у вас нет DVD-при­во­да или вы чи­тае­те это в он­лайн-вер­сии, пе­ре­ве­ден­ной на рус­ский, за­тем на поль­ский и вновь на анг­лий­ский, то ис­ход­ные тек­сты мож­но ска­чать на­пря­мую с сай­та Ubuntu Launchpad. По­се­ти­те http://code.launchpad.net/podofile или вос­поль­зуй­тесь ''Bazaar'' для по­втор­но­го соз­да­ния ло­каль­но­го ре­по­зи­то­рия ко­ман­дой ''bzr branch lp:podofile''. Ар­хив со­дер­жит так­же фай­лы на­строй­ки ''Quickly'', так что ес­ли вы уже ус­та­но­ви­ли ''Quickly'', то мо­же­те по­иг­рать с ним са­мо­стоя­тель­но.&lt;/div&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	</feed>