пятница, 11 июня 2010 г.

автоматическое обновление картинок в сете

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

Рисовать «в стол», вернее сказать, на жесткий диск – занятие интересное на первых порах знакомства с редактором, но когда уже что-то начало получаться, хочется рассказать всему миру о своих творениях. Желание, конечно, похвальное, но в условиях повального цейтнота, на то, чтобы заняться популяризацией своего творчества, просто не хватает времени.

Раз у самого нет времени, то надо это дело кому-нибудь перепоручить – завести секретаршу. Расходно и не по-программерски, у нас же есть компьютер и интернет. Вот пусть компьютер сам и выкладывает наши картинки – чего ему зря пыль собирать и электричество кушать.

Где размещать наши творения? На многочисленных форумах и сайтах, посвященных 3D моделированию, конечно, надо бы, но это тоже отнимает время и накладывает некоторые обязательства. Мы же с Вами – художники свободные и больше всего ценим, свободу и независимость во всем, что касается жизни.

Лично я использую сервис от Google’а, и ничего в нем плохого не вижу. За любовь, как говорят, не платят, а свобода – в нутрии нас, внешней свободы, живя в обществе не добиться, как бы сильно этого не стараться. Мы же люди активные и контакты с обществом – неотъемлемая часть нашей жизни, без людей мы просто задыхаемся. И ради свободы мы не за что на свете не поедем на необитаемый остров. Вот такая вот математика – хотим свободы, но изолироваться не желаем – ищем компромиссы.

Но переходим к сути поста, у нас имеются творения, которые должны быть загружены на сервис Picasa. Что для этого нужно? Руки, чтобы били не до конца кривые и росли, желательно все же оттуда, откуда должны они и расти – этого, принципе достаточно, еще должен быть действующий аккаунт на Picasa, пароль от этой учетки, самом Python’е должна быть установлена библиотека от Google – но это все лирики и не столь важно. Главное – идея.

Идея проста – мы авторизируемся на сервисе, создаем новый альбом, в который выгружаем наши работы. Естественно все это мы делаем не через браузер, а перепоручаем работу змею.

Итак, наш скрипт состоит из трех частей:

· Авторизироваться на сервисе;

· Создание нового альбома

· Добавить фотографий (в данном случае – одной фотографии, что сути не меняет) в созданный альбом

Чтобы авторизироваться на сервисе, вводим переменные MyLog, password, которые понятно что, будут содержать.

Теперь сразу же переходим к написанию скрипта – а чего медлить-то.

import gdata.photos.service

import gdata.media

import gdata.geo

Следующей строчкой мы определим наши переменные, необходимые для аутификации.

MyLog = ‘ArkSmoke’

password = ‘pass’

теперь создаем клиент для работы сервисом

gd_client = gdata.photos.service.PhotosService()

Дальше выполняем процедуру аутификации

gd_client.email = MyLog # Set your Picasaweb e-mail address...

gd_client.password = password # ... and password

gd_client.source = 'api-sample-google-com'

gd_client.ProgrammaticLogin()

Все, теперь мы полноправные авторизированные хозяева на сервисе – можем создвать свой собственный альбом – чем мы без промедления и займемся.

album = gd_client.InsertAlbum(title ='Album for try', summary = 'this album for blogs')

Всего одна строчка и альбом готов. Тут все прозрачно – мы указываем два параментра: название альбома и краткое к нему пояснение. Переменная album превратилась в объект, со всеми свойствами и атрибутами объекта. В данном примере нам будет интересен лишь одни параетр – порядковый номер, созданного альбома – album.gphotot_id.text.

С добавлением фотографий дело обстоит немного сложнее: нам надо прописать расположение фотографии на носителе информации, с которого мы будем ее добавлять и альбома, в который мы будем эту фотку добавлять – вывод вводим еще две переменные: для расположения альбома, и фотографии.

album_url = '/data/feed/api/user/%s/albumid/%s' % ('Ark', album.gphotot_id.text)

filename = 'dsb.jpg'

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

Теперь создаем обект для работы с фотогрфиями – мы просо добавим новую и все.

photo = gd_client.InsertPhotoSimple(album_url, 'fistTry', 'Uploaded using the API', filename, content_type='image/jpeg')

Собственно говоря, пока все. Теперь мы можем добавлять свои творения в автоматическом режиме.

четверг, 25 февраля 2010 г.

Ко дню защитника о защите.

Хоть праздник и прошел, но самое время поговорить об защите в Blender, вообще этот разговор я заводить не хотел, но наткнулся на статью, и не отреагировать не смог.

Дело в том, что за простоту и мощность Blender’а как студии программирования приходится платить некой уязвимостью. Я говорю о том факте, что в Blender есть возможность автоматически запускать скрипты при открытии файла. Чем это грозит? А грозит это тем, что во время старта файла с расширением .blend можно запустить любой исполняемый файл. Я Вас не призываю этого делать и не несу никакой ответственности за Ваши действия, но призываю быть осторожнее при открытии файлов от неизвестного автора.

Как работает этот механизм? Пишем простенький скрипт, например такой:

import os

os.system('calc.exe')

Дальше переходим в Buttons Window переходим в Script. Там нажимаем кнопку New, выбираем имя нашего скрипта, указываем событие, при котором, скрипт срабатывает. Я указал OnLoad – при загрузке. Теперь сохраяню файл. Отрываю его – скрипт срабатывает – я могу пользоваться калькулятором! Иногда очень полезно.

И помните, что эта особенность не баг, а фича, так что будьте внимательны и осмотрительны. Никакая программная защита не спасет, если нет головы. Удачи. Защищайте себя сами – угроза можете придти с любой стороны, будьте готовы.

воскресенье, 21 февраля 2010 г.

Управление Камерой



С того времени, когда я начал рассматривать Blender не как мощный инструмент 3D моделирования, а как среду программирования, меня интересовал вопрос управления в виртуальном мире.

В предыдущих постах я показывал, как решать совершенно не стандартные для Blender задачи.

Итак, хоть я скрытый злодей, помышляющий о том, как завоевать вселенную, она мне не нужна, как и власть и деньги, хотя без денег на «железо» и интернет не обойтись, мной больше двигают исследовательские цели. Ну, скажите, какой смысл от мира, если его нельзя пощупать и поизучать? На мой взгляд – никакого. Поэтому, создав виртуальный мир, мне стало интересно, а как же все-таки в него пустить меня, исследователя?

Решение простое и одно – надо писать скрипт и запустить его в Blendr. Скрипт управления камерой. Возиться самому мне в ту пору, естественно, не хотелось. Я только представил все эти аффинные преобразования да еще в трех мерном мире, мне сразу плохо стало. Другой математической модели управления камерой тогда я не видел. И перспектива возиться с матрицами меня, прямо скажу, очень сильно, тогда еще студента, угнетала. Но ведь к тому времени на Blender уже писались игры, а, значит, управление камерой было реализовано. Значит, задача сводится к нахождению удовлетворительного и, по возможности, универсального скрипта управления камерой. Несколько вариантов с преобразованиями матриц я отмел, как меня не устраивающие, и стал искать дальше.

Все же странно устроен человек, не представляя, как это можно сделать иначе, отметает варианты и ищет, уж поистине то, не знаю что. Но, самое интересное, в людском мире то, что это «не знаю что» находится. Удовлетворивший меня скрипт находится на www.tutorialforblender3D.com, но так же файл с этим же скриптом я выкладываю здесь. В тексте ничего не меняю, считаю, что не имею на это право. А вот здесь объясню механизм его работы.

Считается одной из самых сложных задач по обучению программирования – перевод текста программы на человеческий язык, то есть словами объяснить алгоритм работы Вашей программы. Лично я не люблю взять готовый скрипт и использовать его, не разобравшись в механизмах его работы, если, что-то не понял, то изучаю этот скрипт до дыр. Но для того, чтобы понять работу скрипта управления логикой, нужно понимать логику управления логическими блоками (считайте это каламбуром, а не тавтологией). Про работу логических блоков я объяснять не стану (в обозримом будущем выйдет моя статья по созданию игр в Blender, а повторяться, я не люблю – если возникнет необходимость что-то уточнить, можно задать вопрос и посмотреть на демонстративный файл).


На рисунке продемонстрированы все необходимые настройки логических блоков:

Сенсер одни – Mouse, он настроен на событие Movement, контроллер тоже одни, в нем находится наш скрипт, управления камерой. А вот актуаторов – 2: одни, LookLeftRight, отвечает за движения камеры по горизонтали, второй, LookUpDown, - по вертикали.

Условно я делю скрипт на две части: get и set части. В первой части мы объясняем скрипку откуда он берет исходные данные и что с ними делает, во второй части присваиваем полученные результаты – все как всегда просто:

# импортируем библиотекуt Rasterizer

import Rasterizer

# для удобства чтения скрипта вводим переменную, которой присваиваем текущий

# контроллер

controller = GameLogic.getCurrentController()

# назначаем переменную, к которой этот скрипт присоединяем

player = controller.getOwner()

# присваиваем переменной сенсор с именем Mouse

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

mouse = controller.getSensor("Mouse")

# вводим переменные, которым присваиваем наши актуаторы

lookLeftRight = controller.getActuator("LookLeftRight")

lookUpDown = controller.getActuator("LookUpDown")

В этом мы связали входящие данные и выходящие, на мой взгляд, именно эта связь является самой трудной для понимания: тут происходит основная связь скрипта с логикой самого файла – если скрипт универсальный, то файл надо подстраивать под этот скрипт, вот для это на и назначаются все переменные, но идем дальше.

# назначаем переменным ширину и высоту экрана, это надо для перемещения

width = Rasterizer.getWindowWidth()

height = Rasterizer.getWindowHeight()

# определяем mouse movement функцию

def mouseMove():

# определяем расстояние, пройденное от центра экрана

x = width/2 - mouse.getXPosition()

y = height/2 - mouse.getYPosition()

# инициализируем mouse если еще не сделали этого

if hasattr(player, 'mouseInit') == False:

x = 0

y = 0

# тут баг

# и вместо True. надоиспользовать 1

player.mouseInit = 1

# возвращаем передвижение мыши

return (x, y)

# присваиваем mouse значения, полученные функцией, их два X,Y

move = mouseMove()

# задаем чувствительность

sensitivity = 0.001

# Суммируем направление и чувствительность

#на самом деле умножаем, но оставил термин из комментария к скрипту

# move[0] – это перемещение мыши по X

# move[1] – это перемещение мыши по Y

leftRight = move[0] * sensitivity

upDown = move[1] * sensitivity

# устанавливаем, полученные значения в актуаторы

lookLeftRight.setDRot( 0.0, 0.0, leftRight, False)

lookUpDown.setDRot( upDown, 0.0, 0.0, True)

# используем, уже полученные актуаторы в нашем файле

GameLogic.addActiveActuator(lookLeftRight, True)

GameLogic.addActiveActuator(lookUpDown, True)

# размещаем mouse в центре экрана

Rasterizer.setMousePosition(width/2, height/2)


Вот и все – скрипт работает, можете проверять.

Это один из лучших скриптов для управления камерой при создании игр, у меня он лежит в качестве боевого скрипта.

Желаю Вам успехов.

суббота, 6 февраля 2010 г.

О начале года

Год начался с некоторых изменений в жизни. Как всегда всякие изменения приводят к тому, что нужно подвести анализ сделанной работы. С чего, собственно говоря, я и начинаю второй месяц года. Из-за занятости на основной работе и небольшого смещения интересов (цикл статей, посвященных Blender я завершил еще в 2009 году, хотя до сих пор они не все опубликованы), но так же, чтобы было удобнее работать с материалом, который я уже здесь приводил, выкладываю файлы скриптов, использованных мною в качестве примеров.

Скачать архив со скриптами можно здесь.

Сам же я на время сменю направленность блога (надеюсь, что это изменение станет более информативно) и некоторое время буду наполнять содержимое своего блога переводами англоязычных статей (с личными комментариями к коду), иногда будет полезно выкладывать статьи из API в переводе и объяснением, как это работает.

Надеюсь на понимание.

суббота, 9 января 2010 г.

Создаем аудиобазу иностранных слов

Начался новый год, завершаются праздники и каникулы, скоро предстоят рабочие будни. Хотя у кого-то они уже начались: сессия, консультации, экзамены. Не знаю, как Вы, а я с нового года решил подтянуть свой английский язык и в очередной раз взяться за изучение японского. Слово дал, но вот что с ним делать? Надо же когда-то браться за свое образование, вот я и решил отгулять праздники, подумать и собраться.
Собрался, но подошел в этом плане по-программерски, чтобы было интересно и полезно ни только мне. Вообще, при изучении иностранного языка самое сложное – произношение (как я с ним намучался, и сколько мучений еще предстоит), но суть не в том, а в том, чтобы всегда под рукой иметь некий аудиофайл, чтобы сверить сове произношение, ну или, как в случае с английским языком, понять, как данное слов читается. Вот попробуйте с ходу прочитать pronunciation. У меня, когда я этот ужас увидел в первый раз, не получилось его прочитать, а очень бы хотелось.
Попробуем собрать собственную аудиобазу изучаемых слов – лингво нам не подходит – слишком громоздкий, да и не бесплатный, а мы Фаны свободного программного обеспеченья. Что же делать – лазить по Интернету и искать подходящий словарь с аудибзой не хочется – время дорого. Ключевое слово – искать. Кто у нас все знает? – Google. Да в добавок еще и сервисы свои бесплатно предоставляет. Вот и воспользуемся одним из его серверов - http://translate.google.com. Если не использовали этот он-лайн переводчик – обязательно попробуйте, но о его методах перевода – если время будет, поговорим отдельно.
Сильно не ругайтесь, что отошел от темы Python в Blender. Просто я все еще работаю с Blender, как средой программирования. Но вернемся к базе адиофайлов. Переводчик, предлагаемый Google’ом, может произносить слова – здорово этим и воспользуемся. Заставим диктора произнести наше pronunciation. Заставили – послушали, а дальше-то что? Надо понять, откуда диктор его читает. Запускаем сниффер и перехватываем вот такой адрес – URL = http://translate.google.com/translate_tts?q=pronunciation&tl=en. Принцип работы ясен: на url-адрес http://translate.google.com/translate_tts - передаем два параметра: q – что будем произносить, tl – язык, а результатом этого запроса будет нужный нам аудиофайл – не верите, скопируйте адрес в броузер, загрузите файл, допишите ему расширение .mp3 и прослушайте.
Алгоритм добывания слов ясен, как добыть слово руками – понятно, теперь автоматизируем это добывание, с помощью Python.

У нас будет процедура speach с двумя параметрами: язык и слово. Слово будет так же и именем аудифайла, чтобы знать, какое слово, где лежит. Формируем запрос, отправляем запрос, получаем результат, сохраняем результат – вот и все.

import sys
import urllib2
import urllib
'''
autor : ArkSmoke
url : http://arkpython.blogspot.com

'''

def speach(tl, text):
opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'My')]

live_word = opener.open(
"http://translate.google.com/translate_tts?" +
urllib.urlencode({'tl': tl}),
data = urllib.urlencode({'tl': tl,
'q': text})
)

snd = live_word.read()
open(text +'.mp3','wb').write(snd)

speach('en', 'Yes')
print 'done'


По большому счету в данном скрипте и комментировать нечего – все словами описано выше. Удачи Вам. И приятного изучения языка.

воскресенье, 27 декабря 2009 г.

Снова хулиганим

Новый год уже на носу. С каким бы настроением мы не подходили к его финалу, все равно хочется похулиганить, внести некоторое разнообразие в серые одинаковые будни.
Пускай, я снова ухожу от основной темы, не пишу сткрипт генерации какой нибудь поздравительной открытки, а собственно говоря, почему бы нет. Только представьте: нажимаешь run и вот оно – новогодние чудо – поздравление с новым годом. Интересная затея? Мне нравится. Но подходить мы к теме будем творчески. Стопудово Вас друг когда-нибудь да просил подарим ему какую-нибудь из Ваших сцен, выполненных в Blender. И вот, наконец, Вы решились это сделать, но просто файл дарить скучно.
Подарим – скрипт. Да один лишь скрипт, который нужно запускать.
Посмотрим, как это организовать, а, заодно и убедимся, что ничего нет не возможного.
Нам понадобятся два скрипта. Один, чтобы упаковать Вашу сцену в txt-файл (да я не оговорился – именно, в блокнот :р). и скрипт, который Вы подарите другу, который уже будет в себе содержать Вашу сцену. По шпионски звучит? Да мне нравятся такие заморочки. На деле это все выглядит очень просто – у меня в папке есть файл 01.blend, именно его я и собираюсь подарить другу. Весит он 1,59 МБ (приношу прощение за сленг, но уже привык так говорить). В этой папке я создаю файл inbox.py с кодом.


import StringIO
import gzip
import base64

my_file = '01.blend'

zbuf = StringIO.StringIO()
zfile = gzip.GzipFile(mode='wb', fileobj=zbuf)
zfile.write(open(my_file,'rb').read())
zfile.close()

open('tmp.txt','w').write(base64.encodestring(zbuf.getvalue()))

Получили текстовый файл tmp.txt, который весит 543 КБ, но он и хорошенько сжимается, если его попросить об этом.
Нас же интересует содержание этого файла, которое мы прочитаем в переменную, и дальше уже с переменой будем работать. Чтобы не загружать объемом скрипт.

import sys
import os
import base64
import StringIO
import gzip
import subprocess

scn =open('tmp.txt','r').read()
scn = base64.decodestring(scn)
zbuf = StringIO.StringIO(scn)


zfile = gzip.GzipFile(mode='rb',fileobj=zbuf)
file_src = sys.argv[0]
file_name = file_src.split('\\')[-1].split('.')[0]
open(file_name+'.blend','wb').write(zfile.read())
zfile.close()

subprocess.Popen(file_name+'.blend', shell=True)


Я нарочно даю этот скрипт без комментариев – здесь комментировать нечего, я же надеюсь, со строками работать Вы умеете, а вот финальная строка интересная кода заслуживает рассмотрения, но в том плане, что надо знать, что именно она запускает распакованный файл в Blnder’е.
Вот такой легкий скрипт, а сколько всего полезного он может сделать.
Одно из его применений – запуск тех документов, которые сегодня должны быть сделаны.

Удачного Вам нового года.

пятница, 18 декабря 2009 г.

еще раз о wx, но глубже

Этот пост снова посвящен работе с библиотекой wx, и неким закреплением темы рекурсии и функций – все это в одном посте, да простят мне все те, кто ждет от меня советов и трюков именно по Blender’у – Вам сюда (http://f1cd.ru/soft), а здесь я показываю азы, не столько Python’а, сколько программирования вообще – что поделать, учитель – он и в Африке учитель. Особенно приятно, что задаются вопросы именно по программированию. Поэтому, начинающие кодеры, этот пост для Вас. Тема и пример успешно обкатаны и перекочевали в Python и Blender (как среду программирования) из Pascal’я. Хотя, все, что когда-то было уже сделано, я не люблю – нет простора для воображения и творческого подхода.
В этом посте я покажу, как сделать оболочку для калькулятора, используя библиотеку wx, но сам калькулятор делать не стану. Не потому, что я такой вредный, а чтобы дать читателю простор воображения. Начнем с некоторого анализа предстоящей работы. Нам нужно будет сделать графическую оболочку, которая содержит кнопки (будем использовать термины Windows – и называть любой графический объект окном). Сами по себе кнопки на окне или фрейме интереса не представляют. Интерес представляет связь между графическим объектом и реакцией на воздействие на этот объект. Говоря проще, как кнопка будет реагировать на нажатие – вот здесь простор воображения, но Трояны писать мы не станем. Как работает библиотека, как происходит связь объектов и действий – обо всем этом я писал. Поэтому сразу переходим к обсуждению логики работы нашего имитатора калькулятора.



Он содержит поле для ввода\вывода информации и клавиши, разделить их можно на две группы:

• Клавиши для ввода данных;
• Клавиши, для выполнения операций

Операции у нас будут только унарные – нахождение факториала числа, и нахождение суммы всех положительных чисел до заданного. Работать мы будем только с целыми числами, хотя «точка» для создания дробных предусмотрена. Еще есть две кнопки для очистки текстового поля. Собственно говоря все, чтобы работать с бинарными операциями (сложение, вычитание, умножение и деление), надо просто завести еще две переменные для хранение второго операнда (чтобы знать два числа, с которыми будем работать) и переменную для хранения самой операции, которую надо будет произвести.
Клавиши ввода работают очень просто, добавляют то, что на них написано, в текстовое поле. Поэтому мы здесь пойдем на хитрость. И одну и ту же операцию назначим для ряда окон. Работают они одинаково, различие в том, что они добавляют свой Title в текстовое поле. Сгруппируем все клавиши ввода в одно событие, а потом просто, когда это событие произойдет, определим, какое окно его вызвало, и добавим Title с этого окна в поле ввода\вывода. Вроде бы все просто.
Рассмотрим весь этот алгоритм реализованным.

self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button7)

Подробнее о Bind я уже писал – смотрите мои посты. Так же Bind будет выглядеть для всех остальных окно ввода, разница только в имени окна. Теперь процедура добавления заголовка окна:

def OnDigitClick(self, event):
# Получаем список всех окно, которые содержит panel.
children = self.panel.GetChildren()
# Находим окно что, вызвало событие.
for child in children:
if child.GetId() == event.GetId():
# Знак, который нужно вывести, содержится в label'e виждета.
self.textCtrlInfo.AppendText(child.GetLabel())


Остальной код труда не составит, для понимания. Две идентичные функции у меня реализованы разными методами, чтобы показать, что получить одни и тот же результат можно получить разными путями – выбор за Вами.

# -*- coding: cp1251 -*-

import wx

class Frame_main(wx.Frame):

def __init__(self, parent):
self._init_ctrls(parent)

def _init_ctrls(self, prnt):
''' Инициализирует все видимые компоненты. '''


# Создаём главное окно, которое не может изменять размер и разворачиваться на
# весь экран.
wx.Frame.__init__(self, id=-1, parent=prnt,
pos=wx.Point(422, 270), size=wx.Size(258, 222),
style=wx.DEFAULT_FRAME_STYLE & (~(wx.MAXIMIZE_BOX | wx.RESIZE_BORDER)),
title='Calculator')
self.SetClientSize(wx.Size(250, 218))

# Созаём панель - на ней будут распологаться все остальные окна.
self.panel = wx.Panel(self)
# создаем кнопки
self.button0 = wx.Button(id=-1, label='0',
name='button_0', parent=self.panel, pos=wx.Point(8, 144),
size=wx.Size(40, 23), style=0)

self.button1 = wx.Button(id=-1, label='1',
name='button_1', parent=self.panel, pos=wx.Point(8, 112),
size=wx.Size(40, 23), style=0)

self.button2 = wx.Button(id=-1, label='2',
name='button_2', parent=self.panel, pos=wx.Point(56, 112),
size=wx.Size(40, 23), style=0)

self.button3 = wx.Button(id=-1, label='3',
name='button_3', parent=self.panel, pos=wx.Point(104, 112),
size=wx.Size(40, 23), style=0)

self.button4 = wx.Button(id=-1, label='4',
name='button_4', parent=self.panel, pos=wx.Point(8, 80),
size=wx.Size(40, 23), style=0)

self.button5 = wx.Button(id=-1, label='5',
name='button_5', parent=self.panel, pos=wx.Point(56, 80),
size=wx.Size(40, 23), style=0)

self.button6 = wx.Button(id=-1, label='6',
name='button_6', parent=self.panel, pos=wx.Point(104, 80),
size=wx.Size(40, 23), style=0)

self.button7 = wx.Button(id=-1, label='7',
name='button_7', parent=self.panel, pos=wx.Point(8, 48),
size=wx.Size(40, 23), style=0)

self.button8 = wx.Button(id=-1, label='8',
name='button_8', parent=self.panel, pos=wx.Point(56, 48),
size=wx.Size(40, 23), style=0)

self.button9 = wx.Button(id=-1, label='9',
name='button_9', parent=self.panel, pos=wx.Point(104, 48),
size=wx.Size(40, 23), style=0)

self.buttonFact = wx.Button(id=-1, label='!',
name='button_fact', parent=self.panel, pos=wx.Point(56, 144),
size=wx.Size(40, 23), style=0)

self.buttonDot = wx.Button(id=-1, label='.',
name='button_dot', parent=self.panel, pos=wx.Point(104, 144),
size=wx.Size(40, 23), style=0)

self.buttonSum = wx.Button(id=-1, label='Sum',
name='button_Sum', parent=self.panel, pos=wx.Point(152, 48),
size=wx.Size(40, 23), style=0)


self.buttonErase = wx.Button(id=-1, label='<-',
name='button_erase', parent=self.panel, pos=wx.Point(200, 48),
size=wx.Size(40, 23), style=0)

self.buttonCleanUp = wx.Button(id=-1, label='C',
name='button_clean_up', parent=self.panel, pos=wx.Point(200, 80),
size=wx.Size(40, 23), style=0)

# соам поле для ввоа\вывода результатов

self.textCtrlInfo = wx.TextCtrl(id=-1,
name='textCtrl_info', parent=self.panel, pos=wx.Point(8, 8),
size=wx.Size(232, 21), style=0, value='')

# Максимальная длина вводимой строки.
self.MaxLength = 30
self.textCtrlInfo.SetMaxLength(self.MaxLength)
self.errorStatusBar = self.CreateStatusBar()
#==========================
# Устанавливаем обработчики событий
#==========================
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button0)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button1)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button2)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button3)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button4)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button5)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button6)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button7)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button8)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.button9)
self.Bind(wx.EVT_BUTTON, self.OnDigitClick, self.buttonDot)
self.Bind(wx.EVT_BUTTON, self.OnButtonSumClick, self.buttonSum)
self.Bind(wx.EVT_BUTTON, self.OnOButtonFactClick, self.buttonFact)
self.Bind(wx.EVT_BUTTON, self.OnButtonEraseClick, self.buttonErase)
self.Bind(wx.EVT_BUTTON, self.OnButtonCleanUpClick, self.buttonCleanUp)
self.Bind(wx.EVT_TEXT, self.OnTextCtrlInfoText, self.textCtrlInfo)

def OnDigitClick(self, event):
# Получаем список всех окно, которые содержит panel.
children = self.panel.GetChildren()
# Находим окно что, который вызвал событие.
for child in children:
if child.GetId() == event.GetId():
# Знак, который нужно вывести, содержится в label'e виждета.
self.textCtrlInfo.AppendText(child.GetLabel())

def OnButtonEraseClick(self, event):
''' Стираем последний символ в строке.'''
oldValue = self.textCtrlInfo.GetValue()
self.textCtrlInfo.SetValue(oldValue[:len(oldValue) - 1])


def OnButtonCleanUpClick(self, event):
''' Очищаем все данные. '''
self.textCtrlInfo.SetValue('0')
self.errorStatusBar.SetStatusText('')

def OnTextCtrlInfoText(self, event):
''' Очищает строку сообщений об ошибках как только начинаем ввод нового
числа. '''
self.errorStatusBar.SetStatusText('')

def OnOButtonFactClick(self, event):
''' считаем факториал числа '''
try:
number = float(self.textCtrlInfo.GetValue())
# Не выводим '.', если число целое.
number = fact(number)
number = NormalizeNumber(number)
self.textCtrlInfo.SetValue(str(number))
except (TypeError, ValueError):
self.errorStatusBar.SetStatusText

def OnButtonSumClick(self, event):
''' Меняем знак числа. '''
try:
number = float(self.textCtrlInfo.GetValue())
# Не выводим '.', если число целое.
sum = 0
while number > 0:
sum = sum + number
number = number -1

number = sum
number = NormalizeNumber(number)
self.textCtrlInfo.SetValue(str(number))
except (TypeError, ValueError):
self.errorStatusBar.SetStatusText('ОШИБКА! Введите число правильно.')

def NormalizeNumber(number):
'''
Превращает float в int, если число целое.
'''
if not (number % 1):
number = int(number)
return number

def fact(n):
if n == 0:
result = 1
else:
result = n*fact(n-1)
return result

#======================================================================
#
#=======================основной блок==================================
#
#======================================================================

class CalcApp(wx.App):
def OnInit(self):
self.main = Frame_main(None)
self.main.Show()
self.SetTopWindow(self.main)
return True

def main():
application = CalcApp(0)
application.MainLoop()

if __name__ == '__main__':
main()


На скриншоте привожу самый спорный пример кода.



Обратите на него внимание. Здесь показано, как строить классы. А пока все. До новых встреч. И на прощание, в школы с 2010 год приходит Linux – очень бы хотел услышать Ваши мысли по этому поводу. Удачного плавания в мире бесплатного софта. До скорых встеч.