Новый год уже на носу. С каким бы настроением мы не подходили к его финалу, все равно хочется похулиганить, внести некоторое разнообразие в серые одинаковые будни.
Пускай, я снова ухожу от основной темы, не пишу сткрипт генерации какой нибудь поздравительной открытки, а собственно говоря, почему бы нет. Только представьте: нажимаешь 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’е.
Вот такой легкий скрипт, а сколько всего полезного он может сделать.
Одно из его применений – запуск тех документов, которые сегодня должны быть сделаны.
Удачного Вам нового года.
воскресенье, 27 декабря 2009 г.
пятница, 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 – очень бы хотел услышать Ваши мысли по этому поводу. Удачного плавания в мире бесплатного софта. До скорых встеч.
В этом посте я покажу, как сделать оболочку для калькулятора, используя библиотеку 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 – очень бы хотел услышать Ваши мысли по этому поводу. Удачного плавания в мире бесплатного софта. До скорых встеч.
воскресенье, 8 ноября 2009 г.
Немного рекурсии, процедур, функций и ностальгии о школе
Увы, но даже некоторые учителя информатики не знают различая между процедурой и функцией, а при слове «рекурсия» на них нападает первобытный ужас, и они начинают трястись и плеваться. Больше всего от этого страдают ученики, которые хотят понять и разобраться – инициатива рубится, что говориться, на корню. Что же в стране «полууголовной» романтики – любая инициатива наказуема.
Так же и я, обещая выложить скрипт, генерирующий молнию (смотри комментарии к прошлому посту), опять срулил в диалектическую яму и принялся заниматься своим любимым делом – ругать полуграмотных педагогов информатики, забывши, когда сам крайний раз смотрел на класс. Ругать можно долго – толку только от этого не будет. Да и ясности не прибавится. Поэтому ругать больше никого не стану – ругайте меня, за то, что взялся объяснять самые азы, но кому-то и они пригодятся как для дальнейшего восприятия уже «боевых» скриптов, так и для менее нервного чтения прошлых постов.
Позволю себе еще немного поностальгировать о тех временах, когда возил маркером по доске, рисуя загадочные заклинания на Паскале. Так вот, Паскаль к отступам нечуствительный, на нем всю программу можно писать сплошным текстом, не выделяя ничего – все одно работать будет правильно, если будет, а что в коде потом ничего не понять – так это обычно мало кого волнует, кто смотрит свои программы. Я обычно всегда «гонял» за отсутствие отступов, хотя их не делал почти никто. Python же к отступам чувствителен. Отсутствие или наличие отступов в некоторых местах вызывает критические ошибки – скрипт просто не работает, в других же местах те же самые лишние отступы могут изменить логику выполнения скрипта до неузнаваемости. Вот и получаются ситуации когда все работает, но почему-то не так, как того хочет программист. Вот и начинается баголовительство и непонятные крики – все правильно написано, а работает неправильно, «такого быть не может», «это не возможно», «код верный». Код-то верный. А вот логика не до конца.
Проше всего продемонстрировать работу отступов на уже известном примере, проще, но как тогда связать их с процедурами, функциями и рекурсией?
Итак, код программы поделен на блоки – модули. Некоторые модули импортируются из уже готовых библиотек – их мы разбирали, трогать больше не будем. Некоторые блоки пишутся в самом скрипте, используется ключевое слов def. В python def используется как для процедур так и для функций, а вот в Паскале – нет. Процедура (procedure) и функция (function) разливаются даже в объявлении. Смотрите:
Procedure MyProc(n:integer);
Begin
End;
Function MyFunc(n:integer):integer;
Begin
End;
Разница видна даже в объявлении. Процедура – часть кода что либо делающая, но при этом не возвращающая значения, то есть a := MyProc – в Паскале будет ошибочно, а вот a := MyFunc – вполне работоспособно, так как функция возвращает некоторое значении. Чтобы лучше отложилась эта разница в памяти, вспомним школьное понятие функции (это из алгебры) – некий закон, который ставит в соответствия между числами. Коряво, но понятно. Вот пример: функция – закон f(x)=3*x, вместо х подставляем любое число и получаем его соответствие – вот Вам функция в деле. Теперь посмотрим, как это сделать на python. Закон известен, переменная задана. Выполняем.
Def MyFun(n)
result = 3*n
rerurn result
Что этот код нам дает? Мы можем использовать функцию f(x)=3*x в более сложных выражениях. Например, g(x) = (f(x))^2 – можно поступить так
F = Myfunc(5)
G = f^2
Но это все школьные примеры – они простые для восприятия, поэтому мне нравится.
Теперь приведу пример процедуры. Берем тот же закон, зачем нам что-то думать, и преобразуем функцию (она у нас готова) в процедуру
Def MyFun(n)
result = 3*n
print( result)
Вычислительная работа та же самая – вот ее результат, в данном случае, мы видим в консоли. Поэтому процедуры используются для прорисовки и связи объектов, функции – для расчета каких либо величин, например, координат точек.
Сейчас мы посмотрим на предыдущий пример еще раз, а после вернемся к рекурсивному вызову функций.

Я себе позволил немного порисовать на картинке с кодом, чтобы немного яснее стала структура кода из предыдущего поста. Но поясню теперь по картинке – надеюсь ошибки из-за отсутствия форматирования в листингах сократятся.
Итак, всю работу осуществляет одна функция – main. Дальше, по красной линии переходим в class CalcApp(wx.App), который состоит из одной функции (она помечена цветом) OnInit(self), эта функция отсылает нас к еще одному классу - MyWindow(wx.Frame), который состоит уже из двух функций – их я тоже выделил цветом. Вообще, следовало бы отдельно поговорить о понятии класса и объекта, но к этому при необходимости еще вернемся, а пока продолжим.
Рекурсивный вызов функции означает, что функция вызывает сама себя. И, если не оговорить условия выхода из рекурсии, то возникнет переполнение памяти, а какие проблемы возникнут в этом случае, я Вам сказать не берусь.
Рассмотрим рекурсивный вызов функции на примере подсчета факториала. Помните, что это такое? Это произведение всех чисел, которые идут до заданного, включая заданное. И не улыбайтесь, факториал 5 не равен нулю, так как факториал нуля равен единице. Вот у нас есть все для написания этой не хитрой рекурсивной функции и даже условие выхода. Функция будет работать так:
• Получает некое число – аргумент функции
• Сравнивает его с нулем
o Если число – ноль, то возвращаем значение функции – 1
o В противном случае умножаем это число на результат вызова этой же функции, но с аргументом на единицу меньшим
def fact(n):
if n == 0:
result = 1
else:
result = n*fact(n-1)
return result
Вот все, что мы описывали сделано на языке Python – вызываем функции функцию, хотя бы от пяти:
g = fact(5)
print(g)
Проверяем консоль и видим – 120, а не 1, как можно подумать. Почему так получается? Из-за вызова функции самой себя. Я нарисовал картинку, как функция работает.

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

Так что будьте внимательны, не забывайте о духе исследования. А где эта функция может пригодиться в Blender – генерация точек. Удачи Вам.
Так же и я, обещая выложить скрипт, генерирующий молнию (смотри комментарии к прошлому посту), опять срулил в диалектическую яму и принялся заниматься своим любимым делом – ругать полуграмотных педагогов информатики, забывши, когда сам крайний раз смотрел на класс. Ругать можно долго – толку только от этого не будет. Да и ясности не прибавится. Поэтому ругать больше никого не стану – ругайте меня, за то, что взялся объяснять самые азы, но кому-то и они пригодятся как для дальнейшего восприятия уже «боевых» скриптов, так и для менее нервного чтения прошлых постов.
Позволю себе еще немного поностальгировать о тех временах, когда возил маркером по доске, рисуя загадочные заклинания на Паскале. Так вот, Паскаль к отступам нечуствительный, на нем всю программу можно писать сплошным текстом, не выделяя ничего – все одно работать будет правильно, если будет, а что в коде потом ничего не понять – так это обычно мало кого волнует, кто смотрит свои программы. Я обычно всегда «гонял» за отсутствие отступов, хотя их не делал почти никто. Python же к отступам чувствителен. Отсутствие или наличие отступов в некоторых местах вызывает критические ошибки – скрипт просто не работает, в других же местах те же самые лишние отступы могут изменить логику выполнения скрипта до неузнаваемости. Вот и получаются ситуации когда все работает, но почему-то не так, как того хочет программист. Вот и начинается баголовительство и непонятные крики – все правильно написано, а работает неправильно, «такого быть не может», «это не возможно», «код верный». Код-то верный. А вот логика не до конца.
Проше всего продемонстрировать работу отступов на уже известном примере, проще, но как тогда связать их с процедурами, функциями и рекурсией?
Итак, код программы поделен на блоки – модули. Некоторые модули импортируются из уже готовых библиотек – их мы разбирали, трогать больше не будем. Некоторые блоки пишутся в самом скрипте, используется ключевое слов def. В python def используется как для процедур так и для функций, а вот в Паскале – нет. Процедура (procedure) и функция (function) разливаются даже в объявлении. Смотрите:
Procedure MyProc(n:integer);
Begin
End;
Function MyFunc(n:integer):integer;
Begin
End;
Разница видна даже в объявлении. Процедура – часть кода что либо делающая, но при этом не возвращающая значения, то есть a := MyProc – в Паскале будет ошибочно, а вот a := MyFunc – вполне работоспособно, так как функция возвращает некоторое значении. Чтобы лучше отложилась эта разница в памяти, вспомним школьное понятие функции (это из алгебры) – некий закон, который ставит в соответствия между числами. Коряво, но понятно. Вот пример: функция – закон f(x)=3*x, вместо х подставляем любое число и получаем его соответствие – вот Вам функция в деле. Теперь посмотрим, как это сделать на python. Закон известен, переменная задана. Выполняем.
Def MyFun(n)
result = 3*n
rerurn result
Что этот код нам дает? Мы можем использовать функцию f(x)=3*x в более сложных выражениях. Например, g(x) = (f(x))^2 – можно поступить так
F = Myfunc(5)
G = f^2
Но это все школьные примеры – они простые для восприятия, поэтому мне нравится.
Теперь приведу пример процедуры. Берем тот же закон, зачем нам что-то думать, и преобразуем функцию (она у нас готова) в процедуру
Def MyFun(n)
result = 3*n
print( result)
Вычислительная работа та же самая – вот ее результат, в данном случае, мы видим в консоли. Поэтому процедуры используются для прорисовки и связи объектов, функции – для расчета каких либо величин, например, координат точек.
Сейчас мы посмотрим на предыдущий пример еще раз, а после вернемся к рекурсивному вызову функций.

Я себе позволил немного порисовать на картинке с кодом, чтобы немного яснее стала структура кода из предыдущего поста. Но поясню теперь по картинке – надеюсь ошибки из-за отсутствия форматирования в листингах сократятся.
Итак, всю работу осуществляет одна функция – main. Дальше, по красной линии переходим в class CalcApp(wx.App), который состоит из одной функции (она помечена цветом) OnInit(self), эта функция отсылает нас к еще одному классу - MyWindow(wx.Frame), который состоит уже из двух функций – их я тоже выделил цветом. Вообще, следовало бы отдельно поговорить о понятии класса и объекта, но к этому при необходимости еще вернемся, а пока продолжим.
Рекурсивный вызов функции означает, что функция вызывает сама себя. И, если не оговорить условия выхода из рекурсии, то возникнет переполнение памяти, а какие проблемы возникнут в этом случае, я Вам сказать не берусь.
Рассмотрим рекурсивный вызов функции на примере подсчета факториала. Помните, что это такое? Это произведение всех чисел, которые идут до заданного, включая заданное. И не улыбайтесь, факториал 5 не равен нулю, так как факториал нуля равен единице. Вот у нас есть все для написания этой не хитрой рекурсивной функции и даже условие выхода. Функция будет работать так:
• Получает некое число – аргумент функции
• Сравнивает его с нулем
o Если число – ноль, то возвращаем значение функции – 1
o В противном случае умножаем это число на результат вызова этой же функции, но с аргументом на единицу меньшим
def fact(n):
if n == 0:
result = 1
else:
result = n*fact(n-1)
return result
Вот все, что мы описывали сделано на языке Python – вызываем функции функцию, хотя бы от пяти:
g = fact(5)
print(g)
Проверяем консоль и видим – 120, а не 1, как можно подумать. Почему так получается? Из-за вызова функции самой себя. Я нарисовал картинку, как функция работает.

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

Так что будьте внимательны, не забывайте о духе исследования. А где эта функция может пригодиться в Blender – генерация точек. Удачи Вам.
воскресенье, 11 октября 2009 г.
О совершенно посторонних библиотеках
Несколько постов подряд я пытаюсь показать, как можно использовать Blender не по назначению. Я стараюсь показать, что Blender так же является мощной средой программирования. Получилось мне это показать? Может, и да. Но лично я бы не поверил в то, что Blender можно использовать как независимую студию программирования, пусть даже на динамично развивающемся языке Python, если каждый рабочий скрипт начинается с такой строчки: import Blender. Подозрительно как-то, Вы не находите? Вот нашел. Итак, мы имеем скрипт, переворачивающий число – записывающий последовательность цифр в обратном порядке, если хотите. Вообще, любую самую тривиальную задачу можно сформулировать очень и очень красиво, но суть данного поста вот в чем – ответить на вопрос, возможно ли использовать Blender, как полноценная студия программирования, но при этом не использовать библиотеку Blender. Все это надо, чтобы в корне отсечь, возможности оппонента говорить, что без библиотеке Blender (import Blender) Blender (уже редактор) как студию программирования использовать нечего.
А за одно попробуем уйти от интерфейса командной строки и Blender’a – будет еще один повод поговорить о независимости Blender’а. Вы думаете невозможно? Возможно все, главное хотеть.

Как Вам интерфейс для нашей программки-переворотчика чисел? Симпатичный, правда?
Написан он с помощью библиотеки wx. Скачать эту библиотеку можно отсюда http://wxPython.org. Я использую вариант этой библиотеки для Windows, но на сайте можно найти варианты библиотеки и для других систем.
Часть кода можно увидеть не на скриншоте, но все же лучше продублирую код целиком:
import wx
'''
autor : ArkSmoke
url : http://arkpython.blogspot.com
date : 10.09
data : work with wx in Blender
'''
class MyWindow(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, id = -1, parent = None, pos = wx.Point(0,0), size = wx.Size(250,150), title = 'My first Window with Blender')
self.panel = wx.Panel(self)
self.buttonResult = wx.Button(id=-1, label='Work',name='button_work', parent=self.panel, pos=wx.Point(100, 70), size=wx.Size(50, 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='1234567')
self.Bind(wx.EVT_BUTTON, self.OnOperationClick, self.buttonResult)
def OnOperationClick(self,event):
try:
number = int(self.textCtrlInfo.GetValue())
except (TypeError, ValueError):
print('error')
return
dt = number
td = 0
while dt > 0:
td = td * 10 +(dt % 10)
dt = dt // 10
self.textCtrlInfo.SetValue(str(td))
class CalcApp(wx.App):
def OnInit(self):
self.main = MyWindow()
self.main.Show()
self.SetTopWindow(self.main)
return True
def main():
application = CalcApp()
application.MainLoop()
main()
Ну как Вам – скрипт в 46 строк уже более или менее серьезная вещь. Но давайте посмотрим, как он работает. Главная функция в нем – main(). Вы же помните логику работы всех приложений с окнами?
Пока существует окно, отслеживаются и обрабатываются все события, связанные с этим окном. К слову сказать, закрытие окна тоже событие, которое, впрочем, может не останавливать работу программы, но об этом говорить мы не станем.
Цикл обработки событий в Delphi осуществляется следующим образом:
While GetMessage(Msg,0,0,0) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
простите не сумел удержаться, что не вставить кусок из этого языка – часто еще думаю именно на Pascal’е. Но это цикл для работы с GUI, если же Вы используете интерфейс командной строки, то для этой цели можно использовать бесконечный цикл while. Оговорив условия выхода – например, команда Quit, или номер пункта меню, соответствующий выходу из цикла – простор воображения.
Но все это я рассказал для того, чтобы Вы вспомнили принцип работы программ – работать до тех пор, пока не получена команда прекратить работу. Отсутствие события – тоже событие, которое обрабатывается определенным образом, например, переход в программу скринсайвер. Логично? Логично. Едем дальше.
Нечто подобное происходит и в Python при использовании библиотеки wx – этим занимается MainLoop(), но, для начала, нужно указать с каким именно окном мы работаем. Первая строчка функции main()
application = CalcApp()
CalcApp() – это уже наш собственный класс, в котором мы создаем окно и все события, связанные с ним. Собственно говоря, у нас есть всего одно событие – нажатие на кнопку. А вот само окно и все объекты, находящиеся на окне создавать придется соответствующими функциями: wx.Button – для кнопки и wx.TextCtrl – для текстового поля.
В классе CalcApp() основой является окно - MyWindow(). Тоже самодельный класс, именно в нем и описано все, что касается окна.
class CalcApp(wx.App):
def OnInit(self):
self.main = MyWindow()
self.main.Show()
self.SetTopWindow(self.main)
return True
Остальное нужно отображения нашего окошка, чтобы оно было видимым или нет. Вы только вдумайтесь невидимые окна! Но о хулиганстве писать не буду.
Переходим к классу MyWindow(). Он состоит из описания главного окна и всех компонентов, которые располагаются на главном окне.
wx.Frame.__init__(self, id = -1, parent = None, pos = wx.Point(0,0), size = wx.Size(250,150), title = 'My first Window with Blender')
self.panel = wx.Panel(self)
self.buttonResult = wx.Button(id=-1, label='Work',name='button_work', parent=self.panel, pos=wx.Point(100, 70), size=wx.Size(50, 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='1234567')
Самое главное в этом классе – связь между событием – нажатием кнопки и самой этой кнопки.
self.Bind(wx.EVT_BUTTON, self.OnOperationClick, self.buttonResult)
Функция Bind() осуществляет эту связь. Первый параметр показывает от какого объекта приходит событие, второй параметр – какое именно событие, тритий – уточнят имя побеспокоенного объекта.
Соответственно реакция объекта располагается во втором параметре.
def OnOperationClick(self,event):
try:
number = int(self.textCtrlInfo.GetValue())
except (TypeError, ValueError):
print('error')
return
dt = number
td = 0
while dt > 0:
td = td * 10 +(dt % 10)
dt = dt // 10
self.textCtrlInfo.SetValue(str(td))
В самом перевороте числа произвел небольшие изменения, все же число мы получаем из текстового поля и результат возвращаем в это же самое поле.
Вот вроде бы и все. Blender может прекрасно работать и с библиотеками, которые не входят в поставку как самого Blender’a, так и самого Python. Хотя, может быть, с библиотекой wx работать удобнее, используя некие студии, позволяющие делать интерфейсы будущих программ визуально, но любая такая студия, берущая на себя рутинную работу, добавляет свой код, который может увеличить, как объем скрипта, так и сказаться на скорости его работы. В общем, приобретая что-то, что-то обязательно теряешь. Всегда все можно прописать руками, тогда уже знаешь каждую строчку и ориентироваться легче, хотя на первый взгляд это кажется и дольше сложнее. Но, где сложнее, там достойнее.
А за одно попробуем уйти от интерфейса командной строки и Blender’a – будет еще один повод поговорить о независимости Blender’а. Вы думаете невозможно? Возможно все, главное хотеть.

Как Вам интерфейс для нашей программки-переворотчика чисел? Симпатичный, правда?
Написан он с помощью библиотеки wx. Скачать эту библиотеку можно отсюда http://wxPython.org. Я использую вариант этой библиотеки для Windows, но на сайте можно найти варианты библиотеки и для других систем.
Часть кода можно увидеть не на скриншоте, но все же лучше продублирую код целиком:
import wx
'''
autor : ArkSmoke
url : http://arkpython.blogspot.com
date : 10.09
data : work with wx in Blender
'''
class MyWindow(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, id = -1, parent = None, pos = wx.Point(0,0), size = wx.Size(250,150), title = 'My first Window with Blender')
self.panel = wx.Panel(self)
self.buttonResult = wx.Button(id=-1, label='Work',name='button_work', parent=self.panel, pos=wx.Point(100, 70), size=wx.Size(50, 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='1234567')
self.Bind(wx.EVT_BUTTON, self.OnOperationClick, self.buttonResult)
def OnOperationClick(self,event):
try:
number = int(self.textCtrlInfo.GetValue())
except (TypeError, ValueError):
print('error')
return
dt = number
td = 0
while dt > 0:
td = td * 10 +(dt % 10)
dt = dt // 10
self.textCtrlInfo.SetValue(str(td))
class CalcApp(wx.App):
def OnInit(self):
self.main = MyWindow()
self.main.Show()
self.SetTopWindow(self.main)
return True
def main():
application = CalcApp()
application.MainLoop()
main()
Ну как Вам – скрипт в 46 строк уже более или менее серьезная вещь. Но давайте посмотрим, как он работает. Главная функция в нем – main(). Вы же помните логику работы всех приложений с окнами?
Пока существует окно, отслеживаются и обрабатываются все события, связанные с этим окном. К слову сказать, закрытие окна тоже событие, которое, впрочем, может не останавливать работу программы, но об этом говорить мы не станем.
Цикл обработки событий в Delphi осуществляется следующим образом:
While GetMessage(Msg,0,0,0) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
простите не сумел удержаться, что не вставить кусок из этого языка – часто еще думаю именно на Pascal’е. Но это цикл для работы с GUI, если же Вы используете интерфейс командной строки, то для этой цели можно использовать бесконечный цикл while. Оговорив условия выхода – например, команда Quit, или номер пункта меню, соответствующий выходу из цикла – простор воображения.
Но все это я рассказал для того, чтобы Вы вспомнили принцип работы программ – работать до тех пор, пока не получена команда прекратить работу. Отсутствие события – тоже событие, которое обрабатывается определенным образом, например, переход в программу скринсайвер. Логично? Логично. Едем дальше.
Нечто подобное происходит и в Python при использовании библиотеки wx – этим занимается MainLoop(), но, для начала, нужно указать с каким именно окном мы работаем. Первая строчка функции main()
application = CalcApp()
CalcApp() – это уже наш собственный класс, в котором мы создаем окно и все события, связанные с ним. Собственно говоря, у нас есть всего одно событие – нажатие на кнопку. А вот само окно и все объекты, находящиеся на окне создавать придется соответствующими функциями: wx.Button – для кнопки и wx.TextCtrl – для текстового поля.
В классе CalcApp() основой является окно - MyWindow(). Тоже самодельный класс, именно в нем и описано все, что касается окна.
class CalcApp(wx.App):
def OnInit(self):
self.main = MyWindow()
self.main.Show()
self.SetTopWindow(self.main)
return True
Остальное нужно отображения нашего окошка, чтобы оно было видимым или нет. Вы только вдумайтесь невидимые окна! Но о хулиганстве писать не буду.
Переходим к классу MyWindow(). Он состоит из описания главного окна и всех компонентов, которые располагаются на главном окне.
wx.Frame.__init__(self, id = -1, parent = None, pos = wx.Point(0,0), size = wx.Size(250,150), title = 'My first Window with Blender')
self.panel = wx.Panel(self)
self.buttonResult = wx.Button(id=-1, label='Work',name='button_work', parent=self.panel, pos=wx.Point(100, 70), size=wx.Size(50, 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='1234567')
Самое главное в этом классе – связь между событием – нажатием кнопки и самой этой кнопки.
self.Bind(wx.EVT_BUTTON, self.OnOperationClick, self.buttonResult)
Функция Bind() осуществляет эту связь. Первый параметр показывает от какого объекта приходит событие, второй параметр – какое именно событие, тритий – уточнят имя побеспокоенного объекта.
Соответственно реакция объекта располагается во втором параметре.
def OnOperationClick(self,event):
try:
number = int(self.textCtrlInfo.GetValue())
except (TypeError, ValueError):
print('error')
return
dt = number
td = 0
while dt > 0:
td = td * 10 +(dt % 10)
dt = dt // 10
self.textCtrlInfo.SetValue(str(td))
В самом перевороте числа произвел небольшие изменения, все же число мы получаем из текстового поля и результат возвращаем в это же самое поле.
Вот вроде бы и все. Blender может прекрасно работать и с библиотеками, которые не входят в поставку как самого Blender’a, так и самого Python. Хотя, может быть, с библиотекой wx работать удобнее, используя некие студии, позволяющие делать интерфейсы будущих программ визуально, но любая такая студия, берущая на себя рутинную работу, добавляет свой код, который может увеличить, как объем скрипта, так и сказаться на скорости его работы. В общем, приобретая что-то, что-то обязательно теряешь. Всегда все можно прописать руками, тогда уже знаешь каждую строчку и ориентироваться легче, хотя на первый взгляд это кажется и дольше сложнее. Но, где сложнее, там достойнее.
четверг, 8 октября 2009 г.
О многообразии нахождения команд Змеем
Не знаю, как Вам, а мне всегда было интересно, как осуществляется связь между различными частями одной программы. Стоит оговориться, что здесь под программой я имел ввиду, именно код, а не исполняемый файл, или слепок памяти. А вообще с терминологий надо быть предельно аккуратными и тщательно подбирать каждое слово, претендующие на термин. Увы, аккуратностью я страдаю, особенно, когда работа нацелена на результат.
Не будем вдаваться в подробности организации пространства имен в Python. Откуда и как наш змей берет имена. Давайте лучше посмотрим, как мы можем ему показать, откуда эти имена взять. Этим занимается инструкция – import. Ну Вы с ней знакомы. А теперь давайте попробуем вызвать команду Register(), с параметром None, вместо всех запрашиваемых параметров.
Функция Register позволяет использовать None вместо ее параметров, но злоупотреблять этой возможностью мы не станем. В дальнейшем. В этом же посте мы передадим три параметра None, чтобы не возникло ошибок при работе скрипта, но при этом он ничего не сделал бы.
Итак. в прошлом посте мы просто вызвали Register с нужными параметрами. Попробуйте в том скрипте (см. предыдущий пост) заменить все в Register параметром None. Ошибки не возникло, но и работы тоже. Хотя скрипт корректно выполнил свою работу. Чтобы в этом убедиться, допишите после Register(None, None, None) инструкцию print(‘done’). Теперь просто проверим консоль и убедимся – скрипт работает верно.
Создаем новый скрипт. И пытаемся в нем вызвать Register(None, None, None). ЄAaолучилось? У меня влезла ошибка. Ну как так Register is not defined? В прошлый раз же он был вполне defined. Ну в прошлый раз у нас и билиотека Blender была imported =) импортирована. Импортируем.
import Blender
Register(None,None,None)
И снова наша функция не определена. Но она же точно есть – прошлый скрипт тому пример. Стираем наш Register(), от которого толку нет и так – он все еще не определен. И работаем с Boender. Просто попробуем найти в нем эту функцию.
Blender.Draw.Register(None,None,None)
Нашли. Заработала наша функция.
Продолжаем исследовать дальше. Сотрем Blender перед первой точной. Что за чудеса? На этот раз не определен Draw. Попробуем определить его.
import Blender
from Blender import Draw
Draw.Register(None,None,None)
Скрипт работает снова. Теперь попытаемся вызывать наш Register без всяких там точек. Для этого модифицируем 2ю строку.
import Blender
from Blender.Draw import *
Register(None,None,None)
Вот и вся любовь. Register стал определенным.
А теперь посчитайте, сколькими различными способами, мы вызвали одну функцию? Вот сколько путей сделать одно и тоже действие, и соответственно, при каждом действии код будет выглядеть иначе, хотя делать будет одно и тоже. Что выбирать, зависит только от Ваших предпочтений. Удачи Вам и до скорых встреч.
Не будем вдаваться в подробности организации пространства имен в Python. Откуда и как наш змей берет имена. Давайте лучше посмотрим, как мы можем ему показать, откуда эти имена взять. Этим занимается инструкция – import. Ну Вы с ней знакомы. А теперь давайте попробуем вызвать команду Register(), с параметром None, вместо всех запрашиваемых параметров.
Функция Register позволяет использовать None вместо ее параметров, но злоупотреблять этой возможностью мы не станем. В дальнейшем. В этом же посте мы передадим три параметра None, чтобы не возникло ошибок при работе скрипта, но при этом он ничего не сделал бы.
Итак. в прошлом посте мы просто вызвали Register с нужными параметрами. Попробуйте в том скрипте (см. предыдущий пост) заменить все в Register параметром None. Ошибки не возникло, но и работы тоже. Хотя скрипт корректно выполнил свою работу. Чтобы в этом убедиться, допишите после Register(None, None, None) инструкцию print(‘done’). Теперь просто проверим консоль и убедимся – скрипт работает верно.
Создаем новый скрипт. И пытаемся в нем вызвать Register(None, None, None). ЄAaолучилось? У меня влезла ошибка. Ну как так Register is not defined? В прошлый раз же он был вполне defined. Ну в прошлый раз у нас и билиотека Blender была imported =) импортирована. Импортируем.
import Blender
Register(None,None,None)
И снова наша функция не определена. Но она же точно есть – прошлый скрипт тому пример. Стираем наш Register(), от которого толку нет и так – он все еще не определен. И работаем с Boender. Просто попробуем найти в нем эту функцию.
Blender.Draw.Register(None,None,None)
Нашли. Заработала наша функция.
Продолжаем исследовать дальше. Сотрем Blender перед первой точной. Что за чудеса? На этот раз не определен Draw. Попробуем определить его.
import Blender
from Blender import Draw
Draw.Register(None,None,None)
Скрипт работает снова. Теперь попытаемся вызывать наш Register без всяких там точек. Для этого модифицируем 2ю строку.
import Blender
from Blender.Draw import *
Register(None,None,None)
Вот и вся любовь. Register стал определенным.
А теперь посчитайте, сколькими различными способами, мы вызвали одну функцию? Вот сколько путей сделать одно и тоже действие, и соответственно, при каждом действии код будет выглядеть иначе, хотя делать будет одно и тоже. Что выбирать, зависит только от Ваших предпочтений. Удачи Вам и до скорых встреч.
воскресенье, 4 октября 2009 г.
Необычная среда для обычных задач
Я давно перестал верить глазам своим: одну причину я уже демонстрировал, теперь хочу поговорить о еще одной. Так мне кто-нибудь сможет ответить: Blender – это редактор трехмерной графики с возможностью программирования или – среда разработки на Python с мощными графическими возможностями. До недавнего времени, я считал, что первый вариант. Однако, программирование графики – сама по себе, задача не из простых. В некоторых средах программирования разработка графики – дело, требующие хорошей подготовки. Меня поймут те, кому доводилось писать графику, используя библиотеки DirectX или OpenGL. Bender не знаком с Direct’ом, но зато очень близко знает OpenGL. Если в Blender можно программно рисовать, то с задачами на расчеты он должен справляться вполне успешно. Проверим это предположение. Напишем в Blender следующий скрипт:
dt = 1234567
td = 0
while dt > 0:
td = td * 10 +(dt % 10)
dt = dt // 10
print (td)
Как видно, простая школьная задача по программированию решена: данное число записано задам наперед. Этот скрипт продемонстрировал нам возможность решать в Blender целый класс школьных задач по программированию. В частности, мы можем узнать, является ли данное число числом-перевертышем или же является данное число счастливым числом (естественно, сделав необходимые проверки).
В этом скрипте мне не нравится один момент: всегда ли нужно, проверяя новое число, вводить его в скрипт или же есть какая другая возможность? Она есть – и не одна. Можно соорудить свой собственный интерфейс для комфортной работы со скриптом. Правда в большинстве школьных задач, даже олимпиадного уровня, не требуется создания GUI, а ввод и вывод данных осуществляется в текстовые или типизированные файлы. Так как, я уже не школьник, а Blender обладает мощными графическими возможностями, то сооружать я буду именно GUI. Придется мудрить со скриптом, создавая оболочку для контроля его выполнения. А когда нас пугала работа с API – функциями? Никогда. Даже всегда интересовала.

Довольно достойно получилось. Как Вы считаете? Скрипт выкладываю полностью – основная его ценность, конечно, не в решении задачи, которую решать в Blender’е мало кому придет голову, а в том, что основная нагрузка данного скрипта состоит именно в создании GUI.
import Blender
from Blender.BGL import *
from Blender.Draw import *
'''
autor : ArkSmoke
url : http://arkpython.blogspot.com
date : 10.09
'''
DATA = Create(1234567)
ATAD = Create(0)
EVENT_NOEVENT = 1
EVENT_EXIT = 2
EVENT_DRAW = 3
def draw():
global DATA
global EVENT_NOEVENT,EVENT_EXIT,EVENT_DRAW
glClear(GL_COLOR_BUFFER_BIT)
DATA = Number("No. of sides: ", EVENT_NOEVENT, 10, 55, 210, 18, DATA.val, 10, 99999999, "Number of sides of out polygon");
Button("Draw",EVENT_DRAW, 10, 10, 80, 18)
Button("Exit",EVENT_EXIT, 140, 10, 80, 18)
def event(evt, val):
if (evt == QKEY and not val):
Exit()
def bevent(evt):
global DATA
global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT
if (evt == EVENT_EXIT):
Exit()
elif (evt== EVENT_DRAW):
ref(DATA.val)
def ref(dt):
td = 0
while dt > 0:
td = td * 10 +(dt % 10)
dt = dt // 10
print('done ',td)
Register(draw, event, bevent)
К вопросу о GUI в Blender я еще вернусь, как и к вопросу о решении олимпиадных задач в нем. Но всему - свое время. От простого к сложному.
dt = 1234567
td = 0
while dt > 0:
td = td * 10 +(dt % 10)
dt = dt // 10
print (td)
Как видно, простая школьная задача по программированию решена: данное число записано задам наперед. Этот скрипт продемонстрировал нам возможность решать в Blender целый класс школьных задач по программированию. В частности, мы можем узнать, является ли данное число числом-перевертышем или же является данное число счастливым числом (естественно, сделав необходимые проверки).
В этом скрипте мне не нравится один момент: всегда ли нужно, проверяя новое число, вводить его в скрипт или же есть какая другая возможность? Она есть – и не одна. Можно соорудить свой собственный интерфейс для комфортной работы со скриптом. Правда в большинстве школьных задач, даже олимпиадного уровня, не требуется создания GUI, а ввод и вывод данных осуществляется в текстовые или типизированные файлы. Так как, я уже не школьник, а Blender обладает мощными графическими возможностями, то сооружать я буду именно GUI. Придется мудрить со скриптом, создавая оболочку для контроля его выполнения. А когда нас пугала работа с API – функциями? Никогда. Даже всегда интересовала.

Довольно достойно получилось. Как Вы считаете? Скрипт выкладываю полностью – основная его ценность, конечно, не в решении задачи, которую решать в Blender’е мало кому придет голову, а в том, что основная нагрузка данного скрипта состоит именно в создании GUI.
import Blender
from Blender.BGL import *
from Blender.Draw import *
'''
autor : ArkSmoke
url : http://arkpython.blogspot.com
date : 10.09
'''
DATA = Create(1234567)
ATAD = Create(0)
EVENT_NOEVENT = 1
EVENT_EXIT = 2
EVENT_DRAW = 3
def draw():
global DATA
global EVENT_NOEVENT,EVENT_EXIT,EVENT_DRAW
glClear(GL_COLOR_BUFFER_BIT)
DATA = Number("No. of sides: ", EVENT_NOEVENT, 10, 55, 210, 18, DATA.val, 10, 99999999, "Number of sides of out polygon");
Button("Draw",EVENT_DRAW, 10, 10, 80, 18)
Button("Exit",EVENT_EXIT, 140, 10, 80, 18)
def event(evt, val):
if (evt == QKEY and not val):
Exit()
def bevent(evt):
global DATA
global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT
if (evt == EVENT_EXIT):
Exit()
elif (evt== EVENT_DRAW):
ref(DATA.val)
def ref(dt):
td = 0
while dt > 0:
td = td * 10 +(dt % 10)
dt = dt // 10
print('done ',td)
Register(draw, event, bevent)
К вопросу о GUI в Blender я еще вернусь, как и к вопросу о решении олимпиадных задач в нем. Но всему - свое время. От простого к сложному.
среда, 30 сентября 2009 г.
Не верь глазам своим
То, что мы не верим глазам своим, стало нормой нашей жизни. Мы перестали верить всему на этом свете: глазам, ушам, чувствам, соседям, друзьям, ученым болтунам и ученым молчунам, книги фантастов, не знаю, как Вам мне, стали скучны, единственное, что греет душу – классика.
Здесь я хочу показать как можно с помощью одного скрипта на Python обмануть всех. Вот смотрите, что Вы видите на этой картинке:

Правильно, светящийся шар. Как Вы думаете, я сделал его? Использовал ли я сферу для этих целей или нет? Конечно же, да. А вот тут и ошибка не использовал я никаких сфер. Не верите? Смотрите сами.

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

Применяем скрипм, делаем рендер и наслаждаемся солнцем. Вот текст скрипта.
import Blender
from Blender import *
import bpy
'''
autor: ArkSmoke
url : arkpython.blogspot.com/
'''
mat = Blender.Material.New('my')
mat.rgbCol = [0,1,1]
mat.emit = 1
mat.setMode('Halo')
mat.setHaloSize(5)
mat.setAdd(7)
mat.setFlareSize(12)
obj = Blender.Object.GetSelected()[0]
msh = Blender.Mesh.Get(obj.data.name)
msh.materials = [mat]
for fc in msh.faces:
fc.mat = 0
Window.RedrawAll()
print mat.rgbCol
листинг 1
Так что понятие формы вопрос очень сложный и неоднозначный. И даже если перед Вами явная сфера стоит задуматься, а сфера ли это?
Не доверяйте глазам своим и не попадайте в неприятные ситуации, не позволяйте обманывать себя, особенно на вокзалах.
Удачи во всем и всегда.
Здесь я хочу показать как можно с помощью одного скрипта на Python обмануть всех. Вот смотрите, что Вы видите на этой картинке:

Правильно, светящийся шар. Как Вы думаете, я сделал его? Использовал ли я сферу для этих целей или нет? Конечно же, да. А вот тут и ошибка не использовал я никаких сфер. Не верите? Смотрите сами.

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

Применяем скрипм, делаем рендер и наслаждаемся солнцем. Вот текст скрипта.
import Blender
from Blender import *
import bpy
'''
autor: ArkSmoke
url : arkpython.blogspot.com/
'''
mat = Blender.Material.New('my')
mat.rgbCol = [0,1,1]
mat.emit = 1
mat.setMode('Halo')
mat.setHaloSize(5)
mat.setAdd(7)
mat.setFlareSize(12)
obj = Blender.Object.GetSelected()[0]
msh = Blender.Mesh.Get(obj.data.name)
msh.materials = [mat]
for fc in msh.faces:
fc.mat = 0
Window.RedrawAll()
print mat.rgbCol
листинг 1
Так что понятие формы вопрос очень сложный и неоднозначный. И даже если перед Вами явная сфера стоит задуматься, а сфера ли это?
Не доверяйте глазам своим и не попадайте в неприятные ситуации, не позволяйте обманывать себя, особенно на вокзалах.
Удачи во всем и всегда.
Подписаться на:
Комментарии (Atom)