月別アーカイブ: 2009年6月

IronPython in Gtk #

Ubuntu 9.04 で IronPython が動かせるので Gtk# を試してみる。

Mono, Gtk# and ironpython | Kushal , kD & FOSS

まぁ他国ならこんな簡単に見つけることができるんだが。
私がよく書くコードと同様にするなら class を作って

#-*- coding:Latin-1 -*-
"""
Error
#-*- coding:utf-8 -*-
"""

import clr
clr.AddReference('gtk-sharp')

import System
import Gtk

class GtkSharpWindow(Gtk.Window):
    """
        GtkSharp Test
    """
    def __init__(self, title):
        """
            Gtk.Window.__init__(self) is No
            Constructor has been
        """
        # GtkButton
        button = Gtk.Button("Click!")
        button.Clicked += self.on_button_clicked
        # GtkTextView
        self.textview = Gtk.TextView()
        # Packing
        vbox = Gtk.VBox()
        vbox.PackStart(button, False, False, 0)
        vbox.PackStart(self.textview)
        self.Add(vbox)
        # self
        self.DeleteEvent += self.delete_event
        self.Resize(320, 100)
        self.ShowAll()

    def delete_event(self, sender, e):
        """
        	Required
        """
        Gtk.Application.Quit()

    def on_button_clicked(self, sender, e):
        """
            Button Click Signal Handrer
        """
        self.textview.Buffer.SetText("Hello World!")

if __name__ == "__main__":
    Gtk.Application.Init()
    w = GtkSharpWindow("TitleBar")
    Gtk.Application.Run()

mono_ipy1

こんな感じかな。
Gtk.Application.Init() によるライブラリ初期化は必須のようで。
__init__() にはタイトル文字列を入れないと通らない、もっと柔軟にしてくれよ。
親 class の __init__() はやっぱり不要、まぁ Windows 版と同じ exe だし。
pack_start のパラメータは一つか全部しか選べない、PyGtk ならデフォルト引数があるのに。
ShowAll() しないとウインドウを表示できませんので気をつけて。

後は…見ての通り PyGtk とほとんど変わらない。
が、どうしても気になる GtkTextView からの GtkTextBuffer 取得方法。

self.textview.GetBuffer().SetText("Hello World!")

なら解るんだがこんな関数はない。
ついでにメソッドは全部小文字に統一されている GTK+ を何故かキャメルケース化している。
DevHelp が役に立たないような GTK+ バインディングはどうなんだと思うんですけど。

ところで何故 Latin-1 ?って UTF-8 に書き換えてみてよ。

mono_ipy2

意味ワカンネ、つまり未対応ってことかな。
これじゃリテラルに日本語が使えないわな、方法模索中。

つーかやっぱり文字が見にくいのでコレ用に bash のプロファイルを作るはめになったぞと。

Enjoy!

IronEditor

IronEditor なるものを見つけた。
なんか mono でも動くらしいから試してみよう。

irb

あらら、IronPython も IronRuby も同梱なのね。
IronPython 2 系は以前 mono で試して動かなかった経験があるんだけど。

ipy

動くじゃん、ビルド方法が違うのかな?
てゆーか 1.1 もそうだけど文字色を変更するのをやめてくれないか。
まあいいや、IronEditor を起動してみる。

なんじゃこりゃ…

勝手に最大化で起動する大迷惑なことをしてくれる、何時のアプリじゃい!
mono が悪いのだろうけど一度最小化しないとウインドウ化できない。

てゆーかコレってもしかしなくても WindowsForm だよな。
せめて Gtk# にしてくれ、XP で .NET より更にレスポンスが悪いんだよ!
mono ではボタンを押してもヘコまないわ異様に待たされるわ、という現実を知ってくれよ。
少し使うと急にキーボードを受け付けなくなるし、Opera なんか可愛いレベルで。

やっぱり mono は駄目だ、JAVA と何も変わらないというか WindowsForm は Swing 以下だ。
それでもせめて Windows で使えるようなアプリなら使ってみようと思うんだが…

ironeditor

おいおい、if __name__ == “__main__”: を入れたら動かないよ!
__main__ を本体で実効しているの?これじゃ何も作れないんですけど。
Tab キーも Tab しか入れられない、日本語を打つと2つ流し込まれる。

そんな基本的な事はこれだけどエディタヲタの大好きな色分けや自動インデントはある。
なんというか…まあそんな感じであった。

でも Ubuntu 9.04 でそのまま動かせる IronPython 2.0 が手に入ったので収穫はあったぞと。
使うかどうかは今後どうなるかだが、Gtk# で可能なことは PyGtk で全部可能かつ早いしなぁ。

Enjoy!

WPF ListView DataBinding for IronPython

ぱぇぽぃ2 ? Blog Archive ? Python getter, setter
の続き、上手くいったので覚書に。
ObservableCollection を作って ListView で DataBinding させる。

Silverlight Dynamic Languages SDK – Discussions

ほう、こうすればいいんだ。
コレを IronPython 2.6 から使える property setter でやってみる。

{ironpythondir}/Tutorial/pyevent.py
をソースコードと同じ場所にコピー

追記と小変更

pyevent.py の import はこうすればコピー不要

import sys
tutorial_path = IO.Path.GetDirectoryName(sys.executable) + "\\Tutorial"
sys.path.insert(0, tutorial_path)
from pyevent import *

データトリガーなんかをコードで行う方法が解らないので XAML で。
以下ソースコード

#-*- coding:utf-8 -*-

import clr

clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")

from System import *
from System.Windows import *
from System.Windows.Controls import *
from System.Collections.ObjectModel import *
from System.ComponentModel import *
from System.Windows.Markup import XamlReader

# Search pyevent.py
import sys
tutorial_path = IO.Path.GetDirectoryName(sys.executable) + "\\Tutorial"
sys.path.insert(0, tutorial_path)
from pyevent import *

listview_str = """<ListView
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ListView.Resources>
        <Style x:Key="sensitive" TargetType="TextBlock">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=show}" Value="False">
                    <Setter Property="Foreground" Value="Silver" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
        <DataTemplate x:Key="tpl_show">
            <CheckBox IsChecked="{Binding Path=show}" />
        </DataTemplate>
        <DataTemplate x:Key="tpl_name">
            <TextBlock Text="{Binding Path=name}" TextTrimming="CharacterEllipsis"
                Style="{StaticResource sensitive}" />
        </DataTemplate>
    </ListView.Resources>
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Show" CellTemplate="{StaticResource tpl_show}" />
            <GridViewColumn Header="Name" CellTemplate="{DynamicResource tpl_name}" />
        </GridView>
    </ListView.View>
</ListView>"""

class NotifyPropertyChangedBase(INotifyPropertyChanged):
    """
        http://sdlsdk.codeplex.com/Thread/View.aspx?ThreadId=30322
    """
    PropertyChanged = None
    def __init__(self):
        (self.PropertyChanged, self._propertyChangedCaller) = make_event()

    def add_PropertyChanged(self, value):
        self.PropertyChanged += value

    def remove_PropertyChanged(self, value):
        self.PropertyChanged -= value
    
    def OnPropertyChanged(self, propertyName):
        self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))


class MyData(NotifyPropertyChangedBase):
    """
        use setter getter.
        IronPython 2.6 or later.
    """
    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value
        self.OnPropertyChanged("name")

    @property
    def show(self):
        return self._show

    @show.setter
    def show(self, value):
        self._show = value
        self.OnPropertyChanged("show")

class DataBindingTest(Window):
    """
        ListView DataBinding Test class
    """
    def __init__(self):
        self.data = ObservableCollection[MyData]()
        self.Resources["data"] = self.data
        self.listview = XamlReader.Parse(listview_str)
        self.listview.ItemsSource = self.data
        # Temporary Data
        datadict = {"IronPython": True,
                    "C#": False,
                    "F#": True,
                    "Python": True,
                    "Ruby": False,
                    "Perl": False,
                    "C/C++": True }
        for key in datadict.keys():
            en = MyData()
            en.name = key
            en.show = datadict[key]
            self.data.Add(en)
        self.Content = self.listview
        self.Title = "DataBindingTest"
        self.Width = 300
        self.Height = 300
        # Data Check
        self.Closed += self.on_closed

    def on_closed(self, sender, e):
        """
            Checking self.data
        """
        s = ""
        for data in self.data:
            s += "%s: %s\r\n" % (data.name, data.show)
        MessageBox.Show(s)

if __name__ == "__main__":
    a = Application()
    a.Run(DataBindingTest())

data_binding_test

見事にデータ内容と表示が一致するようになりました。
CheckBox On Off で TextBlock の色が即座に変更されます。
Ruby だけ Off に変更してみた例

ruby_off

終了時に ObservableCollection の内容を確認。

off_result

CheckBox の値がそのままデータとなっていることが解ります。
IronPython でもコレが可能なんですね、2.6 正式版が待ちどおしい。

Enjoy!

Get MIME Type and Description

ファイル情報取得で MIME Type を取得したい、その2。

GnomeVFS – Wikipedia
[mew-dist 24325] Re: Content-typeの取り扱いについて

なんだ、gnomevfs ってのを使えばいいのか。

gnome-vfs python – Google Search
Python gnomevfs Reference Manual

簡単に見つかった、メリケンの google が便利すぐる。

Finding the MIME type of a file – Community Ubuntu Documentation

方法まであっさり、しかし他国でこの手を探すと Python コードがすぐ見つかる。
日本ってこんなことでもガラパゴス状態なんだよなぁと。
しかしファイルの種類は日本語での取得ができるのかな?試してみよう。

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

import gtk
import gnomevfs

class MimeWin2(gtk.Window):
    """
        Showing MIME Type and Description of Dropped file
    """
    def __init__(self):
        gtk.Window.__init__(self)
        dnd_list = [("text/uri-list", 0, 0)]
        self.drag_dest_set( gtk.DEST_DEFAULT_MOTION |
                            gtk.DEST_DEFAULT_HIGHLIGHT |
                            gtk.DEST_DEFAULT_DROP,
                            dnd_list, gtk.gdk.ACTION_MOVE )
        self.connect("drag_data_received", self.on_drop)
        self.label = gtk.Label("Drop")
        self.add(self.label)
        self.connect("delete-event", gtk.main_quit)
        self.resize(320, 150)
        self.show_all()

    def on_drop(self, widget, context, x, y, selection_data, info, time):
        drops = selection_data.data.split("\n")
        for drop in drops:
            if not drop == "":
                name = drop[:-1]
                mime = gnomevfs.get_mime_type(name)
                desc = gnomevfs.mime_get_description(mime)
                self.label.set_text("MIME Type = %s\nDescription = %s" % (mime, desc))

if __name__ == "__main__":
    w = MimeWin2()
    gtk.main()

mime_win2

うん、これなら拡張子無しでもなんでも完璧に Nautilus と同じだ。

dir(gnomevfs)

で見ると更にオイシソウなメソッドが見つかりますね。
ファイル情報取得はこれだけでイケそうです。
ただ GNOME 限定になるのはしかたがない。

Enjoy!

Get MIME Type

ファイル情報取得で MIME Type を取得したい。
mimetypes モジュールでは拡張子判別しかできないみたいですけど。
Nautilus は拡張子が優先だけど無くても取得できているじゃないか。
ということで地味に方法を探してみる。

ファイルの MIME タイプの検出 (GNOME 2.2 システム管理 (Linux 版)) – Sun Microsystems

/etc/gnome-vfs-mime-magic
/etc/mime.types

のファイルが元ということになっているみたいなんだが Ubuntu では

ubuntuで対応しているMIME Typeを調べるには:Linux つれづれ日記:So-net blog

/usr/share/mime 以下なのか。
xdg-mime は MIME Types のインストール関連に使うものだがどっちに登録するのかな?

つーか Nautilus が取得できているんだから絶対にシェルから取得できるはずだ。
色々調べていたらこんなのを見つけた。

Nautilus File Manager Scripts: File Information Querying Scripts

file コマンドだけでこんなことができるのか。

$ file --help

で調べると –mime-type オプションがあるらしい、それならこうしてみよう。

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

import gtk
import urllib
import os.path
import commands

class MimeWin(gtk.Window):
    """
        Showing MIME Type of Dropped file
    """
    def __init__(self):
        gtk.Window.__init__(self)
        dnd_list = [("text/uri-list", 0, 0)]
        self.drag_dest_set( gtk.DEST_DEFAULT_MOTION |
                            gtk.DEST_DEFAULT_HIGHLIGHT |
                            gtk.DEST_DEFAULT_DROP,
                            dnd_list, gtk.gdk.ACTION_MOVE )
        self.connect("drag_data_received", self.on_drop)
        self.label = gtk.Label("Drop")
        self.add(self.label)
        self.connect("delete-event", gtk.main_quit)
        self.resize(320, 150)
        self.show_all()

    def on_drop(self, widget, context, x, y, selection_data, info, time):
        drops = selection_data.data.split("\n")
        for drop in drops:
            name = urllib.unquote(drop)[7:-1]
            if os.path.isfile(name):
                # Get MIME Type
                mime = commands.getoutput("file --mime-type %s" % name)
                self.label.set_text(mime)

if __name__ == "__main__":
    w = MimeWin()
    gtk.main()

ext_non

おお、しっかり取得してくれているじゃないか。
しかし Python Script では

ext_py

text/x-java …
text/x-python のはずなのに、ダメだこりゃ。

mime = mimetypes.guess_type(name)[0]
if mime:
    self.label.set_text(mime)
else:
    self.label.set_text("Non Extension")

ならキチンと text/x-python になる、しかし拡張子が無いなら None になる。
んーどっちも使えない、もうちょっと調べます。

Enjoy!