ラベル Python の投稿を表示しています。 すべての投稿を表示
ラベル Python の投稿を表示しています。 すべての投稿を表示

木曜日, 1月 21, 2010

ClutterのチュートリアルをPyClutterに翻訳 その2

ClutterのチュートリアルをPyClutterに翻訳するその2

Scoreを使って複数のタイムラインを流すところの前半まで。後半のところはPyClutterの問題なのか、うまく出来ないので、原因を調査中。
追記:原因解明。何が問題だったのかは後で書く。

複数タイムラインの次は画像の読み込みのチュートリアルだけど、画像を用意するのが面倒なのでやらない。

大きさの変更やオブジェクトの選択


まわして、かくだい
#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
import mathhacks

global rotation
global scale
rotation = 0
scale = 0


def on_timeline_new_frame(timeline, frame_num, rect_list):
global rotation
global scale

rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)

scale += 0.01
if scale > 1.0:
scale = 0

scale_amount = mathhacks.smooth_step2(1.0, 2.0, scale)
for rect in rect_list:
rect.set_scale(scale_amount, scale_amount)


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('hide', quit)
stage.show()

for r in rect_list:
stage.add(r)

timeline = clutter.Timeline(60)
timeline.connect('new-frame', on_timeline_new_frame, rect_list)
timeline.set_loop(True)
timeline.start()

clutter.main()


まわして、かくだいして、おしたらきえる
#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
import mathhacks

global rotation
global scale
rotation = 0
scale = 0


def on_timeline_rotation_new_frame(timeline, frame_num, rect_list):
global rotation

rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)

def on_timeline_scale_new_frame(timeline, frame_num, rect_list):
global scale
scale += 0.01
if scale > 1.0:
scale = 0

scale_amount = mathhacks.smooth_step2(1.0, 2.0, scale)
for rect in rect_list:
rect.set_scale(scale_amount, scale_amount)

def on_stage_button_press(stage, event, *arg):
x = 0
y = 0
x, y = event.x, event.y
clicked = stage.get_actor_at_pos(clutter.PICK_ALL, x, y)
if clicked == stage:
return
clicked.hide()

def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect("button-press-event", on_stage_button_press)
stage.connect('hide', quit)
stage.show()

for r in rect_list:
stage.add(r)

timeline = clutter.Timeline(60)
timeline.connect('new-frame', on_timeline_new_frame, rect_list)
timeline.set_loop(True)
timeline.start()

clutter.main()

スコアを記録する


#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
import mathhacks

global rotation
global scale
rotation = 0
scale = 0


def on_timeline_rotation_new_frame(timeline, frame_num, rect_list):
global rotation

rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)


def on_timeline_scale_new_frame(timeline, frame_num, rect_list):
global scale
scale += 0.01
if scale > 1.0:
scale = 0

scale_amount = mathhacks.smooth_step2(1.0, 2.0, scale)
for rect in rect_list:
rect.set_scale(scale_amount, scale_amount)


def on_stage_button_press(stage, event, *arg):
x = 0
y = 0
(x, y) = (event.x, event.y)
clicked = stage.get_actor_at_pos(clutter.PICK_ALL, x, y)
if clicked == stage:
return
clicked.hide()


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('button-press-event', on_stage_button_press)
stage.connect('hide', quit)

for r in rect_list:
stage.add(r)

score = clutter.Score()
score.set_loop(True)

timeline_rotation = clutter.Timeline(500)
timeline_rotation.connect('new-frame', on_timeline_rotation_new_frame,
rect_list)
score.append(timeline_rotation)

timeline_scale = clutter.Timeline(500)
timeline_scale.connect('new-frame', on_timeline_scale_new_frame,
rect_list)
score.append(timeline_scale)
score.start()

stage.show()
clutter.main()


2つのTimelineを接続する


pyclutterのREADMEを読むと書いてあるが、Score#appendの引数の順番は、CのAPIと違っている。昨日はこれに気づかなかった。ちゃんとREADMEは読めという話ですね。
これはよりPythonicな書き方をするためらしい。こういうのは今後もあると思われ。
#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
import mathhacks

# 回転情報
global rotation
global scale
rotation = 0
scale = 0


def on_timeline_rotation_new_frame(timeline, frame_num, rect_list):
global rotation

rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)


def on_timeline_scale_new_frame(timeline, frame_num, rect_list):
global scale
scale += 0.01
if scale > 1.0:
scale = 0

scale_amount = mathhacks.smooth_step2(1.0, 2.0, scale)
for rect in rect_list:
rect.set_scale(scale_amount, scale_amount)


def on_stage_button_press(stage, event, *arg):
x = 0
y = 0
(x, y) = (event.x, event.y)
clicked = stage.get_actor_at_pos(clutter.PICK_ALL, x, y)
if clicked == stage:
return
clicked.hide()


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('button-press-event', on_stage_button_press)
stage.connect('hide', quit)

for r in rect_list:
stage.add(r)

score = clutter.Score()
score.set_loop(True)

timeline_rotation = clutter.Timeline(500)
timeline_rotation.connect('new-frame', on_timeline_rotation_new_frame,
rect_list)
score.append(timeline_rotation)

timeline_scale = clutter.Timeline(500)
timeline_scale.connect('new-frame', on_timeline_scale_new_frame,
rect_list)
score.append(timeline_scale, timeline_rotation)
score.start()

stage.show()
clutter.main()

火曜日, 1月 19, 2010

ClutterのチュートリアルをPyClutterに翻訳 その1

Mikeforce::HomePageのClutterチュートリアルの和訳をPyClutterでやってみる。

覚えておいてほしいこととして、あくまでのこの記事は Clutter のドキュメントで今現在不足している箇所を補うための「臨時措置」みたいなものだということです。私たちは、もっと広い視野でみた Python を中心とする Clutter のチュートリアルを作成中ですが、それを完成するには2,3ヶ月必要であるとみています。その間は、ここで紹介するチュートリアルで我慢していただき、 Clutter を使ったプログラミングを楽しんで欲しいと考えています。

と書いてあるので、そのうち本気措置が取られる事を期待しつつ、とりあえず前半戦

初めの一歩


黒い枠が出来るだけ。
import clutter

clutter.init()
color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(color)
stage.show()

clutter.main()


四角を追加
import clutter

clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

actor_color = clutter.Color(0, 255, 0, 128)
rect = clutter.Rectangle(actor_color)
rect.set_size(100, 100)
rect.set_position(100, 100)

stage.add(rect)
stage.show()
clutter.main()


必要に応じて長方形を描画する


元ネタでは、長方形の描画とstageへの登録を同じ関数内でやっているのだけど、個人的にそれが嫌なので、四角を作るだけにした。
あと、PyClutterの場合、メインのウィンドウを閉じてもプロセスが生き続けてしまうので、それを避けるために、stageのhideシグナルに終了処理をくっつけた。
import clutter

"""ウィンドウを閉じたときに終了するためのclosure"""
def quit(actor, *args):
clutter.main_quit()

"""関数内でaddするのが嫌だったのでrectを作るだけ"
def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)

return rect


stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

actor_color = clutter.Color(0, 255, 0, 128)
rect = create_rect(actor_color)
stage.add(rect)
# 終了関数を設定
stage.connect('hide', quit)
stage.show()
clutter.main()


アニメーション一歩手前


#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect1 = create_rect(red)
rect2 = create_rect(green)
rect3 = create_rect(blue)
rect4 = create_rect(yellow)
rect5 = create_rect(cyan)
rect6 = create_rect(purple)

stage.add(rect1)
stage.add(rect2)
stage.add(rect3)
stage.add(rect4)
stage.add(rect5)
stage.add(rect6)

stage.connect('hide', quit)
stage.show()
clutter.main()


アニメーション


処理をシンプルにするために、四角形をリストに入れて運ぶようにしている。
on_timeline_new_frameの中がかっこ悪いのが気になる。
#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter

# 回転情報
global rotation
rotation = 0


def on_timeline_new_frame(timeline, frame_num, rect_list):
global rotation
rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('hide', quit)
stage.show()

for r in rect_list:
stage.add(r)

timeline = clutter.Timeline(60)
timeline.connect('new-frame', on_timeline_new_frame, rect_list)
timeline.set_loop(True)
timeline.start()

clutter.main()


アニメーション アンカーポイントを変更


#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter

# 回転情報
global rotation
rotation = 0


def on_timeline_new_frame(timeline, frame_num, rect_list):
global rotation
rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('hide', quit)
stage.show()

for r in rect_list:
stage.add(r)

timeline = clutter.Timeline(60)
timeline.connect('new-frame', on_timeline_new_frame, rect_list)
timeline.set_loop(True)
timeline.start()

clutter.main()


続きはまた今度。

日曜日, 1月 17, 2010

PyClutter 33行のHello, World的なコード

PyClutterはClutterのPythonバインド。
基本的な使い方はベースとなっているGtkとあまり変わらない。
import clutter

def main():
stage = clutter.Stage()
stage.set_color(clutter.Color(0xaa, 0xbb, 0xcc, 0xff))
stage.set_size(200, 200)

label = clutter.Text()
label.set_text('clutter')

button = clutter.Rectangle()
button.set_color(clutter.Color(0xcc, 0xbb, 0xaa, 0xff))
button.set_width(100)
button.set_height(100)
button.set_x(50)
button.set_y(50)
button.set_reactive(True)

stage.add(label)
stage.add(button)
stage.connect('button-press-event', change, label)
stage.connect('hide', quit)
stage.show_all()

def change(actor, event, label):
label.set_text('press button')

def quit(actor):
clutter.main_quit()

if __name__ == '__main__':
main()
clutter.main()

日曜日, 1月 03, 2010

スクリプト書き初め2010

「年末年始はスクリプト書く!」という人に触発されて、スクリプト書き初めをやってみました。
実行結果はこのようになります。



以下コード。
pygameでも出来ただろうけど、あえてPyClutterを使っています。
下敷きにしたのは、PyClutterサンプルのflower.py。
先に言い訳を書いておくと、コメントとか一切無いのは書き初めなので一気に書いたから、改行に見苦しい点があるのはpythontidyのせいです。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
from clutter import CairoTexture
import cairo
import gobject

import sys
import random

BACKGROUND_COLOR = (0xee, 0xee, 0xee, 0xff)


class Snow(CairoTexture):

colors = (
(0.6, 0.7, 0.9, 0.5),
(0.6, 0.7, 1.0, 0.5),
(0.7, 0.9, 0.9, 0.5),
(0.7, 0.7, 1.0, 0.5),
(0.8, 0.7, 0.9, 0.5),
(0.8, 0.9, 1.0, 0.5),
)

def __init__(
self,
x,
y,
translation_velocity,
rotation_velocity,
ground,
):

self.x = x
self.y = y
self.rot = 0
self.v = translation_velocity
self.rv = rotation_velocity
self.ground = ground

CairoTexture.__init__(self, 20, 20)
cr = self.cairo_create()
cr.move_to(0, 0)
cr.rectangle(2, 2, 16, 16)
random_color = Snow.colors[random.randint(0, 5)]
cr.set_source_rgba(*random_color)
cr.paint()

def tick(self, max_width, max_height):
if self.ground - 10 < self.get_y():
return
self.y += self.v
self.rot += self.rv

if self.y > max_height:
self.y = -self.get_height()

self.set_position(self.x, self.y)
self.set_rotation(clutter.Z_AXIS, self.rot, self.get_width()
/ 2, self.get_height() / 2, 0)


class Kakizome(CairoTexture):

def __init__(self):
self.stage = clutter.Stage()
self.stage.set_color(clutter.Color(*BACKGROUND_COLOR))
self.stage.set_size(640, 480)
self.stage.set_title('Kakizome 2010')
self.started = False
self.ground = self.stage.get_height()

self.label = self.create_label('Hello, New Year.')
self.label.set_depth(1.0)
self.stage.add(self.label)

self.snows = list()

self.timeline = clutter.Timeline(500)
self.timeline.set_loop(True)
self.stage.connect('key-press-event', self.on_key_press)

gobject.timeout_add(50, self.tick, self.snows,
self.get_width(), self.stage.get_height())

def create_label(self, message):
label_color = clutter.Color(*BACKGROUND_COLOR)
label = clutter.Text()
label.set_text(message)
label.set_font_name('Mono 32')
label.set_color(label_color)
label_x = (self.stage.get_width() - label.get_width()) - 50
label.set_position(label_x, (self.stage.get_height() / 3) * 2)
return label

def tick(self, snows, height, width):
for snow in snows:
snow.tick(height, width)
if self.ground < 0:
return True

if random.randint(0, 1000) % 125 == 0:
self.ground -= 5

self.fall_snow()

return True

def fall_snow(self):
snow = Snow(random.randint(-10, self.stage.get_width()), -20,
random.randint(1, 5), random.randint(3, 5),
self.ground)
self.stage.add(snow)
snow.set_position(snow.x, snow.y)
self.snows.append(snow)

def run(self):
self.stage.show_all()
self.timeline.start()
clutter.main()

def on_key_press(self, actor, event):
key = event.get_key_symbol()
if key == clutter.keysyms.q:
clutter.main_quit()


if __name__ == '__main__':
app = Kakizome()
app.run()
sys.exit(0)

木曜日, 12月 24, 2009

pythontidyをvimで使うためのスクリプト

Pythonのコードフォーマッタといえば、pythontidy。
普通にコマンドとしても使えるわけですが、今書いているものに対して使用したいわけです。
で、私のメインエディタはvimなので、vimで使うにはどうすればいいか。

ただ使うだけならpythontidyにパスを通して:%! pythontidyでよい。普通はこれを適当なキーにマッピングしてやることになるはず。

ただpythontidyはsyntax errorのあるコードを受け付けないらしく、この方法ではsyntax errorが含まれているときに実行すると、エラーメッセージというかtracebackがバッファに書き込まれてしまう。uすれば戻るけど、うっかり:wqとかすると大変な事になる。

正常に動作した場合でもカーソルが一番上の行に移動してしまう。これはマークを設定してやれば回避できるけど面倒すぎる。

というわけで、pythontidyを使うためだけのvimスクリプトを書いてみた。
前提としてPYTHONPATHにpythontidyが入るようにしておくこと。
function! Pythontidy()
python << EOF
import tempfile
import vim
import pythontidy

cb = vim.current.buffer[:]
b = tempfile.TemporaryFile(mode="rb+")
out = tempfile.TemporaryFile(mode="rb+")
for l in cb[:]:
b.write(l + '\n')
b.seek(0)
pythontidy.tidy_up(b, out)
out.seek(0)
vim.current.buffer[:] = out.readlines()
EOF
endfunction

これをpython_tidy.vimという名前でもつけてあげて、ftpluginの下に置いてやる。
で、python.vimにmap <f5> :call Pythontidy()と書く。<f5>のところは任意のキーでいい。
これでsyntax errorを含むコードを食べさせても、インフォメーションメッセージにエラーが出てくる。ちゃんと動作したときも行の位置が変化しない。

これで安心してダラダラコーディングできる。

木曜日, 8月 27, 2009

PythonでNotifyOSD

眠いので簡単に。後で追記するかも。

角ウサギからUbuntuの通知欄が格好良くなったのだけど、それをPythonから使うための簡単なコード。
import pynotify

pynotify.init("notify-example")
n = pynotify.Notification(
"notify-example",
"Hello, NotifyOSD",
"notification-message-IM")
n.show()

日曜日, 8月 02, 2009

UbuntuでWiiリモコンアプリ開発

ちょっと前からUbuntuでWiiリモコンを使ったアプリケーションを作る方法を調べていて、基本的な事がやっと分かったのでメモ。
事後的に書いているので、足りないところがあるかも。

用意するもの


Ubuntuの入ったパソコン(バージョンは9.04を使っています)
Wiiリモコン
センサーバー(自作してもいいけど)

インストール


まずは何はなくとも関連するライブラリのインストール。
cwiidというモジュールと、それのpythonバインドを使います。今回Pythonは2.6でやりました。3.0で出来るかは未調査です。
apt-get install python-cwiid

これで基本的なところは入るはず。
WiiリモコンとUbuntuの疎通確認にはwmguiが便利。
apt-get install wmgui

これについては説明を省きます。

基本のコード



import cwiid
import time

#Wiimoteクラスをインスタンス化する
#press 1 + 2 button
wiimote = cwiid.Wiimote()

#レポートモードを設定
wiimote.rpt_mode = cwiid.RPT_ACC

#こういう指定もできる
#wiimote.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC

#レポートモード一覧
#cwiid.RPT_ACC
#cwiid.RPT_CLASSIC
#cwiid.RPT_IR
#cwiid.RPT_STATUS
#cwiid.RPT_BTN
#cwiid.RPT_EXT
#cwiid.RPT_NUNCHUK

#そして状態取得
while True:
print wiimote.state
time.sleep(1)


基本のコード解説


importは見ての通り。timeはウェイトを仕込むためなので必須ではないです。念のため。
注意すべきはwiimote = cwiid.Wiimote()のところ。このWiimoteのインスタンス化のタイミングで、Wiiリモコンの1ボタンと2ボタンを同時押ししないと、インスタンス化してくれず、RuntimeErrorが投げられてしまう。
これではちょっと不便なので回避方法が無いかは調べているところ。

無事インスタンス化されたら、次は状態取得。wiimoteインスタンスのrpt_modeというフィールドに、WiiMote.RPT_で始まるフラグを入れると、それに応じた値がwiimote.stateに入るようになります。このフラグは論理和で複数取得が可能なので、ボタン状態と傾きの2つが知りたかったら、wiimote.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACCとやればOK。
どこを指しているかを知るにはRPT_IRを使います。この時、センサーバーかその代わりが無いと、何の値も取得できません。

ここから先は、Cwiidのサイトとかを参考にして下さい。とはいえ、Cwiidのサイトは分かり辛いのですが。
今回最も、役に立ったのは、このページ(リンク切れ中 2009/10/27時点)です。言葉は分からないけど、画像とサンプルコードのおかげで、どうすればいいのか非常に分かりやすいです。
というか、上に書いたことのほとんどは、このページの前部分の要約みたいなものだったりします。
後ろの方には、キャリブレーションのやり方も出ているので参考にどうぞ。
(cwiidのサイトにもキャリブレーションのやり方は書いてあります)



雑談

昨日、本屋に行ったら、WiiRemoteプログラミングという本が出ていたのだけど、

内容はWindowsでの開発だったので、残念ながら私の役には立ちそうになかった。センサーバーの自作とかも載っていたけど、そのために1冊買うのはちょっとなあ。将来買うかもしれないけど、少なくとも今はそういう本があることだけ覚えておくことにしよう。

金曜日, 3月 27, 2009

癒し系ソフト2

ライブラリリファレンスを見ていたら、標準ライブラリだけでもプログレスバーを作れることに気付いたので、作ってみた。
Tkinterの拡張であるTixを使えばよいらしい。

Python3.0とPython2.6で動作を確認済。
try:
from tkinter import DISABLED
from tkinter import Frame
from tkinter import Button
from tkinter import tix
except ImportError:
from Tkinter import DISABLED
from Tkinter import Frame
from Tkinter import Button
import Tix as tix

class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self._p = 0
self._stopFlg = False

self.pack()
self.createWidgets()
self.progress()

def createWidgets(self):
self.stopButton = Button(text='now progress', command=self.stopToggle)
self.stopButton.pack({'side': 'bottom'})

self.meter = tix.Meter(value=self._p)
self.meter.pack({'side': 'bottom'})

def stopToggle(self):
self._stopFlg = not self._stopFlg
if self._stopFlg:
self.stopButton.configure(text='now pause')
else:
self.stopButton.configure(text='now progress')

self.progress()

def progress(self):
if self._p < 1:
if not self._stopFlg:
self._p = self._p + 0.001
self.meter['value'] = self._p
self.after(10, self.progress)
else:
self._p = 1
self.stopButton.configure(text='finished', state=DISABLED)

if __name__ == '__main__':
root = tix.Tk()
app = Window(master = root)
app.mainloop()


Tkinterの使い方は紫藤のページさんの記事を参考にしました。

日曜日, 3月 08, 2009

癒し系ソフト

最近ずっとPerlに触っていて、ちょっと疲れたのでPythonで息抜き。


プログレスバーがだんだん伸びていくのを見ると、とても落ち着くので、そのためだけのアプリを作ってみました。
実行イメージはこんなかんじ。



一時停止も出来る。



面倒なので画面はGladeで適当に。プログレスバーの終了処理は適当過ぎるかもしれないけど、ネタでしかないので気にしない。
一応3分で完了するはずだけど、あまり厳密ではない。そもそも、癒されているときにそんなことを考えないので、実用(?)上問題ない。


基本的な機能は20分ほどで完成。プログレスバーの使い方を調べるのにちょっと時間がかかった。で、ダラダラしたり、Perlについて調べたりする合間に、適当にやっているうちに出来あがり。やはり慣れている言語だと速い。調べたこともライブラリの使い方であって、Pythonそのものについて調べるなんてことはまったく無し。
Perlでもこれくらいさくさく書けるようになるだろうか。


以下、コード。ui.gladeは適当に。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import gtk
import gtk.glade
import gobject


class Progress(object):

def __init__(self):
self.gladefile = 'ui.glade'
self.wTree = gtk.glade.XML(self.gladefile)

self.window = self.wTree.get_widget('window')
self.progress = self.wTree.get_widget('progressbar1')
self.button = self.wTree.get_widget('togglebutton1')
self.flag = True

self.window.connect('destroy', gtk.main_quit)
self.button.connect('toggled', self.on_toggled)

self.timer = gobject.timeout_add(100, self.update_progressbar)

def show_all(self):
self.window.show_all()

def update_progressbar(self):
if self.flag:
current_fraction = self.progress.get_fraction()
if current_fraction < 1:
self.progress.set_fraction(current_fraction + 0.000556)
return True

def on_toggled(self, *args):
self.flag = not self.flag
if self.flag:
self.button.set_label('ぷろぐれすちゅう')
else:
self.button.set_label('ていしちゅう')


if __name__ == '__main__':
prog = Progress()
prog.show_all()
gtk.main()


99%でなかなか終わらないとか、60%ぐらいで0%に戻る機能も考えたけど、癒し効果が無くなりそうなので、やめました。

木曜日, 1月 08, 2009

Pygameでボタンスイッチを作る方法

現状のメモ。

spriteでボタンを作って、それを押したら「何か」が実行されるというのが作りたかったのです。
で、Pygameのドキュメントを眺めてみた。spriteオブジェクトに、自分が押されたかどうか知る仕組みがあることを期待したけど、見つけられず。

なので、
  1. マウスの座標にぴったりくっつくsprite(=cursor)を用意
  2. クリックイベントが発生したらcursorとボタンのスプライトが衝突しているか判定
  3. 衝突していたら「何か」を実行!

という、原始的な方法をとってみた。
ボタンが少なければこれでいいけど、増えてきたら大変になることは確実。
イベントリスナ的仕掛けがあっても良さそうなんだけど(自分で作れってこと?)。
もう少しドキュメントを読まないと。

日曜日, 12月 21, 2008

Sugarでアニメーション

Pygameだけで画面を作れとの教え通りにしたら、Sugar上で簡単なアニメーションをさせることも楽に出来ました。
見栄えがGtkと離れるから気持ち悪いけど、Gtkと組み合わせるのは将来の課題にしよう。

次に知りたい情報は次の2つ
・XO(Sugar?)のストレージの扱い方
・カメラの使い方

ストレージの方はPyCon2008のOLPC Tutorial資料にあるみたい。このチュートリアルは夏ぐらいに序盤だけをやって、放置していたので、今年中に全部やってみよう。

水曜日, 12月 17, 2008

Gtk with Pygameを調査してみた

思い出したかのようにXOとかSugarで遊んでいますが、Gtkの中にPygameの画面を出したいなあと考えて調べてみた。
割とメジャーな要望らしく、いろいろ解決策を発見。でもサンプルコードが動かない。
要するにDrawingAreaを用意して、それをPygame用とすれば良いらしいのだけど。

時間があれば、自力でなんとかなりそうだけど、Pygame本家でGUIs with pygameという文書を発見。

要約すると「GtkとかQtとかWxの中にPygame入れようなんて思うな。時間の無駄だ」だそうで。
言ってることは分からなくもないけど。
代替として、Pygame(Sprite)で実装したGUIライブラリ(というよりウィジェットといった方が正確?)を提示してるけど、それもどうだろう。

日曜日, 12月 07, 2008

Python3000とバックスペースキー

昨日、Python3000のインタラクティブシェルでバックスペースが効かないという話を聞いたけど、そんなことないよなーと思いつつ確信がなかったので特に「そーなんだー」と流していた。

今、Ubuntu8.10上のGnomeコンソールで確認したところ、ASCII DELなら普通にバックスペースが効く。Contorol-Hは駄目。
ビルド&インストール時、configureはprefix以外何もつけておらず、makeも特別な事はしていない。

Vistaではコマンドプロンプトも、Power Shellも両方OK。
そして、終了のショートカットがControl-Dではなく、Control-Zに変更されていることに気付く。ちゃんとドキュメント読めよという話ですが。

Macは確認がめんどいので、後回しにしよう。

木曜日, 12月 04, 2008

Python3000出たよ

とりあえず確認。

Python2.6の場合

>>> class Hoge:
... pass
...
>>> Hoge.__base__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: class Hoge has no attribute '__base__'
>>>


Python3.0の場合

>>> class Hoge:
... pass
...
>>> Hoge.__base__
<class 'object'>
>>>

月曜日, 11月 10, 2008

[Python]設定ファイルを使ったログ記録

普段はprintで十分だけど、たまにしっかりとしたログを取りたくなる。そういうときに限って忘れているので、未来の自分へメモ。

設定ファイルの読み込みにはlogging.config.fileConfig(filename)を使うので、import loggingだけでなく、import logging.configもしなきゃダメ。

以下サンプル

設定ファイル
[loggers]
keys=root,logger01

[handlers]
keys=stdout01,file01

[formatters]
keys=form01

[logger_root]
level=NOTSET
handlers=stdout01

[logger_logger01]
lebel=DEBUG
handlers=stdout01,file01
propagate=0
qualname=top.mid

[handler_stdout01]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)

[handler_file01]
class=FileHandler
level=WARNING
formatter=form01
args=("app.log",'w')

[formatter_form01]
format=%(name)s: %(asctime)s %(levelname)s %(message)s
datefmt=
class=logging.Formatter


サンプルコード
#-*- coding: utf-8 -*-
import logging
import logging.config

logging.config.fileConfig('./logging.conf')

#logger_root
logger = logging.getLogger()
logger.debug(logger.name)
logger.debug('DEBUGログ')
logger.warn('WARNINGログ')

#logger_logger01(top.mid)
logger = logging.getLogger('top.mid')
logger.debug(logger.name)
logger.info('infoログ')
logger.warn('warnログ')


以下、実行結果

標準出力
root: 2008-11-10 22:50:00,038 DEBUG root
root: 2008-11-10 22:50:00,042 DEBUG DEBUGログ
root: 2008-11-10 22:50:00,042 WARNING WARNINGログ
top.mid: 2008-11-10 22:50:00,042 DEBUG top.mid
top.mid: 2008-11-10 22:50:00,043 INFO infoログ
top.mid: 2008-11-10 22:50:00,043 WARNING warnログ


app.logへの出力
top.mid: 2008-11-10 22:50:00,043 WARNING warnログ


だいたい見れば分かるはず。
propagateってのは自分が受け取ったものを、上位のloggerにも通知するかの設定(通知する=1,しない=0)。何でもかんでも通知するとログが大爆発するので、記録方法によっては注意したほうが良いかも。
level=NOTSETってのはroot loggerの場合、全てを記録。その他のloggerの場合は、親のloggerの設定に従ってログります。
FileHandlerが使用するファイルは無い場合、fileConfigを呼んだ時点で勝手に作られる。
あと、サンプルだからFileHandlerを使ったけど、実際にはRotatingFileHandlerを使うケースのがほとんどのはず。

これ以上知りたいなら、ドキュメントを読みましょう。

木曜日, 10月 23, 2008

HAMSTER DB

HAMSTER DBという組み込み型DBを知りました。
Webサイトがかわいいです。

Cで書かれているようですが、Pythonで使うためのwrapperもあるようです。
ニシキヘビとハムスターということで、相性も良さげ。

金曜日, 10月 03, 2008

Python2.6

出ましたね。

10/1に出たと書いてあるけど、昨日見たときWebには出てなかった。
リリースは10/1で、Webに載せたのがさっきなのかな?
ml入ろうかな。

3000の方もあと少し。

日曜日, 9月 07, 2008

WindowsでPyGtkを使うには 2008年9月版(Vista)

Gtkのインストーラが優しくなってくれたので、環境変数のあたりの作業が減った。
4月版を書いた後に、優しくなったようで、前の記事を書いたのは非常に間が悪い時期だったみたい。
対象OSは比較的まっさらなVista SP1。
XPや2kでどうなるかは分からんけど、多分同じようにすれば良いはず。

1.GtkとGladeを入れる


Glade/Gtk+ for Windowsのdownloadから、gtk+-win32-runtime(develでもよいはず)とglade-win32を落として、この順番で入れる。
gtk+-win32-runtimeにgladeも入っていると書いてあるような気がするけど、gladeがgtk+より新しかったので、念のため入れておいた。runtime入れた後にそれだけで十分か確認すれば良かった。まあいいや。

PyGtkを入れる


PyGtkのダウンロードページからPyCairo、PyGObject、PyGtkを落としていれる。この時、管理者権限でやらないと、一部フォルダが作られない。

確認


Python起動して、import gtkとかやってエラーが出てなければOKでしょう。
Gladeはexeを叩いて起こす。
細かく突っついていないから、実は安定していない可能性は無きにしもあらず。


前の記事:WindowsでPyGtkを使うには 2008年4月版
なんとなく、当時も簡単に出来る方法があったように思えてきた。

日曜日, 8月 10, 2008

Pythonにおけるインスタンス変数の宣言

久々にPython。

Pythonのインスタンス変数 という記事を見つける。
ようするに、変なタイミングでインスタンス変数が作られるのは気持ち悪いから、ちゃんと宣言したいという話らしい。
でも、その対策案であるサンプルコードは何か変。
あれだと、クラス変数nameが追加されるだけで、インスタンス変数self.nameは何の変化もしていない。
インスタンス変数を宣言したいなら、__init__内でやればいいわけで、つまり対策前コードでも用件は十分満たしていると。
つまり、サンプルコードがよくないのかも。もっと正しく(?)汚らしいコードでないと、問題点も明らかにならないんじゃないかな。
というわけで、対策案が何か変なことを示す例を出してみる。

>>> class Hoge():
... name = None
... age = None
... def __init__(self, name):
... self.name = name
... def print_profile(self):
... print self.name, self.age
... def set_age(self, age):
... self.age = age
...
>>> a = Hoge("a1")
>>> a.print_profile()
a1 None
>>> print Hoge.name, Hoge.age
None None
>>> Hoge.name = "b1"
>>> Hoge.age = 20
>>> a.set_age(30)
>>> a.print_profile()
a1 30
>>> print Hoge.name, Hoge.age
b1 20
>>> a.age = 40
>>> a.print_profile()
a1 40
>>> print Hoge.name, Hoge.age
b1 20
>>>


こういう動作を期待しているとは思わないんだけど、どうなんでしょ。
コメント欄もないし、トラックバックも、はてな内ででしか出来ないみたいだから、コンタクト出来ないのが残念。

日曜日, 5月 04, 2008

PyCon2008 OLPC Tutorial Step000

要約(訳)は後回しで、とりあえず進めてみる。

とりあえずスクリプトの001を実行すると、チュートリアル全体で使うスケルトンスクリプトがダウンロードされてきた。
中身は後で確認するとして、002を実行。なんかエラーになったんですが。
スクリプトに間違いがあったのかな?それとも環境依存の問題?
とりあえず文書を読む限り、buildskel.pyという起動スクリプトのオプションをここで説明したいようだ。
さて、次はActivityをデプロイするらしい。
チュートリアルに従い、cdしてデプロイ。そしてActivitiyディレクトリのシンボリックリンクを作るらしい。
なぜ?

で、ここで間違いに気づく。
どうやら今読んでいるのは、002スクリプトが何をやったかの説明であって、自分でやる必要はないらしい。
つまり002はデプロイして、Activitiyディレクトリのシンボリックリンクを~/Activities以下に作るまでが仕事だったらしい。
というか、スクリプトの内容を把握せずに実行するというなかなか怖いことをやってたわけですね。
何か問題があったらwikiに載ってないはずだけど、ちょっと迂闊だった。

気を取り直して、デプロイされたActivitiesをsugarエミュで動かしてみる。青い画面が出るだけ。
どうやらこれでいいらしい。
その後、ぐだぐだ書いてあるのはActivityの基礎みたいな内容みたい。適当に流し読み。だいたいは他のチュートリアルにも載ってる情報。pygameまわりの話がちょっとあるが、内容を掴めず。

さて003を実行。その前に中身を簡単に確認。Pythonコードの置き換えと、002までのコードとのdiffが目的のようだ。大丈夫そうなので、実行。そしてエミュで確認。
今度は青背景に白文字が出てきた。文書によるとpygameのスプライト機能で書いたらしい。
003スクリプトで作られたdiff結果を読んでみると、たしかに何行か増えている。

というわけで0番台のスクリプトは概要の説明が目的のようだ。
次くらいから、具体的なコードの説明に入るのかな?