Programming」カテゴリーアーカイブ

IronPython IDisposable and Python Context Management

What is the equivalent of the C# “using” block in IronPython? – Stack Overflow

IronPython で using てか IDisposable が利用できたんだ。
知らなかった、てゆーか with, as って何だ?
私が買った Python の本にはこんなの書いていなかった気がするんだが。

with – odz buffer

Python 2.5 以降で使えるらしい、IronPython だけというわけでは無いようで。
やっぱり知っている人は少ないのか、もう少し調べてみよう。

3.10 コンテキストマネージャ型

__ext__ 指定だけだと例外になった、__enter__ と常に対にする必要あり。
試しに何か書いてみよう、と思ったけど IronPython で思いつかなかった(ぉい!

で、PyGtk の gtk.MessageDialog は destroy() メソッドを呼ぶ必要があるので

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

import gtk

class MessageBox(gtk.MessageDialog):
    def __init__(self, parent=None, flags=0, type=gtk.MESSAGE_INFO, 
                  buttons=gtk.BUTTONS_NONE, message_format=None):
        gtk.MessageDialog.__init__(self, parent, flags, type, buttons, message_format)
    def __enter__(self):
        #print 'enter' # debug
        return self
    def __exit__(self, *excinfo):
        #print 'exit %s' % repr(excinfo) # debug
        self.destroy()

def messagebox(text):
    with MessageBox(buttons=gtk.BUTTONS_OK, message_format=text) as dlg:
        dlg.run()  

messagebox("Test !")

おぉ!確かにこれで解放処理を書かずに関数が使える。
でも try, finally のほうが解りやすいと思うんですけど…
組込みなら使うけど自分で書くかは少し微妙。

DataBinding Compare Code and XAML

IronPython にて WPF の DataBinding をコードで行う方法が解らなかった。
ElementName をコードで書き込んでも反映されないし。
ということで毎度のように検索、C# コードなら日本語で見つかるから便利だね。

[WPF][C#]Bindingでくっつけてみよう その1

コードで行うには Source Property か DataContext を利用すればいいのか。
XAML を含めて IronPython でやってみよう。

Source Version

# -*- 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 *

class DataBindingTest(Window):
    """
        Source Version
    """
    def __init__(self):
        # Create Controls
        textbox = TextBox()
        textblock = TextBlock()
        # Append
        stackpanel = StackPanel()
        stackpanel.Children.Add(textbox)
        stackpanel.Children.Add(textblock)
        self.Content = stackpanel
        self.SizeToContent = SizeToContent.WidthAndHeight
        # Binding
        binding = Data.Binding("Text")
        binding.Source = textbox
        textblock.SetBinding(TextBlock.TextProperty, binding)

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

DataContext Version

# -*- 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 *

class DataBindingTest(Window):
    """
        DataContext Version
    """
    def __init__(self):
        # Create Controls
        textbox = TextBox()
        textblock = TextBlock()
        # Append
        stackpanel = StackPanel()
        stackpanel.Children.Add(textbox)
        stackpanel.Children.Add(textblock)
        self.Content = stackpanel
        self.SizeToContent = SizeToContent.WidthAndHeight
        # Set DataContext
        self.DataContext = textbox
        # Binding
        binding = Data.Binding("Text")
        textblock.SetBinding(TextBlock.TextProperty, binding)

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

XAML Version

# -*- coding: UTF-8 -*-

import clr

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

from System.Windows import Application
from System.Windows.Markup import XamlReader

xaml = """<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    SizeToContent = "WidthAndHeight">
    <StackPanel>
        <TextBox Name="_tname" />
        <TextBlock Text="{Binding ElementName=_tname, Path=Text}" />
    </StackPanel>
</Window>"""

w = XamlReader.Parse(xaml)
Application().Run(w)

どれでも結果は同じ、TextBox に書き込んだ文字列がそのまま TextBlock に。
DataContext はバインディング元データが一つなら問題無いだろうけどチト怖いかな。

というより、やはりこういうのは XAML が一番解りやすく書けますね。
用途によってコードにするか XAML にするかで選べばいいことだけど。

Windows 7 の csc.exe で遊んでみる

最近の Linux で GNOME ならばデフォルトで C# のコンパイルが可能。
Mono が入っている環境であれば必ず gmcs があるからである。

と以前書いたけど実は Windows 7 も可能だったりします。

C:\Windows\Microsoft.NET\Framework64\v2.0.50727

を Explorer で開いてみて、32bit の人は 64 を外してください。

csc.exe という C# コンパイラがあるのが解ります。
つまりコンパイルするファイルが一つであればこうやればいいわけです。
C# コードは BOM 付き UTF-8 で保存してくださいね。

フルパスを打ち込むのが面倒であればパスを通しておきましょう。
これで csc と打ち込むだけでパス指定しなくてもコンパイルが可能になる。

コマンドラインオプションのサンプルは MSDN にあります。
csc.exe を使用したコマンド ラインからのビルド

又、MSBuild を利用したコンパイルも普通に可能です。
幸い私は SeeMe をオープンソースにしているのでコイツで実験してみます。

SeeMe は現在 .NET Framework 3.5 でビルドしているので v3.5 の MSBuild.exe を使う。
コレに SeeMe4.sln というファイルを渡します。

なんかエラー?が出るけどしばらく待っていると SeeMe4.exe が出来上がってしまった。
SDK なんかインストールしないでもビルドできちゃうんですね、自分で驚いたよマジで。

MSDN に細かい解説が日本語であるけど手書きは少々辛いかも。
MSBuild

無償版 VC# が存在する今だけどこんな方法で何もインストールしないで遊べるよ。
開発環境をインストールだけやってプログラマー気取りの人を笑ってあげましょう。

実は .NET Framework 3.5 導入済みなら Windows 7 である必要は無いんですけど…
Vista より前てか XP では .NET が遅すぎて使わないだろうしやはり 7 を進めておくよ。
たった 1.2GB の CULV ノートでも快適に .NET が動きますので。

IronPython Concatenation

IronPython の文字列は str でもあり System.String でもある。
つまり += で文字列結合ができる。

+ と += って結合速度に違いがあるのかな?
そう思って StringBuilder も含めてテストしてみた。

# -*- coding: UTF-8 -*-

"""
    Benchmark Decorators
"""
from System import *
from System.Diagnostics import Stopwatch
from System.Text import StringBuilder

def bench(func):
    def wrapper(count):
        sw = Stopwatch.StartNew()
        for i in range(count):
            func(count)
        print sw.Elapsed
    return wrapper

s = ""
t = ""
sb = StringBuilder()

@bench
def plfunc(count):
    global s
    s = s + "a"

@bench
def eqfunc(count):
    global t
    t += "a"

@bench
def sbfunc(count):
    sb.Append("a")

plfunc(100000)
eqfunc(100000)
sbfunc(100000)

ちょっと強引なコードだけどデコレータを使ってみたかっただけ。
結果、もちろん 1.2GHz CULV マシンでの結果ですので性能チェックにもどうぞ。

00:00:40.2863338
00:00:39.7391895
00:00:00.1128512

ほとんど誤差の範囲です、処理は += も + とどうやら同じようです。
てゆーかやはり StringBuilder を利用しろという結論でした。

WPF Simple TextEditor example

あけおめことよろ、遅い?
さて今年もプログラミングてゆーかソフトウエア作るぞと。

ところで前回の IronPython でタスクトレイは結構人が来ている、実際自分で利用しているし。
やっぱり Windows でのネタでないとアクセスが稼げないなと実感しまくる。
そういえば以前こんなのを書いたけど

ぱぇぽぃ2 ? Blog Archive ? IronPython は親クラスの __init__() がいらない

IronPython での open は StreamReader と同じなのかな?
なんて思ったので実験コードを書いて試してみた。

結果だけではつまらないのでシンプルなテキストエディタを作ってみる。
海外から結構見に来るので全部英語で書くけど日本語向けコードだと解るように。
ちなみに Google 翻訳を駆使しているだけなので翻訳が合っているかどうか解らない。

# -*- coding: UTF-8 -*-

"""
    This Code is Suitable for Japanese
    XAML [xml:lang] Own Rewrite
    Read and Write encoding is UTF-8 Non BOM Text
"""

import clr

clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")
# Open,SaveFileDialog
clr.AddReferenceByPartialName("System.Windows.Forms")

from System import *
from System.IO import *
from System.Windows import *
from System.Windows.Controls import *
from System.Windows.Input import *
from System.Windows.Controls.Primitives import *
from System.Windows.Markup import XamlReader
# avoid namespace conflict
from System.Windows.Forms import OpenFileDialog, SaveFileDialog, DialogResult

menu_str = """<Menu
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xml:lang="ja-JP">
    <MenuItem Header="_File">
        <MenuItem Header="_Open" InputGestureText="Ctrl+O" Name="menu_open" />
        <MenuItem Header="_Save" InputGestureText="Ctrl+S" Name="menu_save" />
        <MenuItem Header="Save _As" Name="menu_save_as" />
        <Separator/>
        <MenuItem Header="_Quit" InputGestureText="Ctrl+Q" Name="menu_close" />
    </MenuItem>
</Menu>"""

class WPF_TextEditor(Window):
    """
        Simple TextEditor
    """
    def __init__(self):
        """
            Initialization
        """
        self.openfile = ""
        # Menu
        menu = XamlReader.Parse(menu_str)
        menu.FindName("menu_open").Click += self.on_open
        menu.FindName("menu_save").Click += self.on_save
        menu.FindName("menu_save_as").Click += self.on_save_as
        menu.FindName("menu_close").Click += self.on_close
        DockPanel.SetDock(menu, Dock.Top)
        # TextBox
        self.textbox = TextBox()
        self.textbox.TextWrapping = TextWrapping.NoWrap
        self.textbox.AcceptsReturn = True
        self.textbox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
        self.textbox.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto
        # StatusBar
        statusbar = StatusBar()
        DockPanel.SetDock(statusbar, Dock.Bottom)
        self.statusbar_item = StatusBarItem()
        self.statusbar_item.Content = "no open"
        statusbar.Items.Add(self.statusbar_item)
        # DockPanel
        dpanel = DockPanel()
        dpanel.Children.Add(menu)
        dpanel.Children.Add(statusbar)
        dpanel.Children.Add(self.textbox)
        # self
        self.Content = dpanel
        self.Title = "WPF_TextEditor"
        # event
        self.KeyDown += self.on_keydown
        # Drag and drop
        self.AllowDrop = True
        self.PreviewDragOver += self.on_predrop
        self.Drop += self.on_drop

    def on_open(self, sender, e):
        """
            namespace Microsoft Dialog is Old
        """
        dlg = OpenFileDialog()
        dlg.Title = "OpenFile"
        if dlg.ShowDialog() == DialogResult.OK:
            self.read_file(dlg.FileName)

    def on_save(self, sender, e):
        """
            is Open ?
        """
        if self.openfile == "":
            self.on_save_as(sender, e)
        else:
            self.save_file(self.openfile)

    def on_save_as(self, sender, e):
        """
            namespace Microsoft Dialog is Old
        """
        dlg = SaveFileDialog()
        dlg.Title = "SaveFile"
        if dlg.ShowDialog() == DialogResult.OK:
            self.save_file(dlg.FileName)

    def on_close(self, sender, e):
        """
            Bye
        """
        self.Close()

    def on_keydown(self, sender, e):
        """
            InputGestureText is Show only
            e is System.Windows.Input.KeyEventArgs
        """
        if Keyboard.Modifiers == ModifierKeys.Control:
            if e.Key == Key.O:
                self.on_open(self, e)
            elif e.Key == Key.S:
                self.on_save(self, e)
            elif e.Key == Key.Q:
                self.on_close(self, e)

    def on_predrop(self, sender, e):
        """
            PreviewDragOver Event
        """
        e.Handled = e.Data.GetData(DataFormats.FileDrop) != None

    def on_drop(self, sender, e):
        """
            File Dropped
        """
        filenames = e.Data.GetData(DataFormats.FileDrop)
        filename = filenames[0].ToString()
        if filename != None and filename.Length != 0:
            self.read_file(filename)

    def read_file(self, filename):
        """
            f = open(filename)
            try:
                s = f.read()
                self.textbox.Text = unicode(s, "utf8")
            except Exception, ex:
                MessageBox.Show(ex.Message)
            finally:
                f.close()
        """
        sw = StreamReader(filename) 
        try:
            self.textbox.Text = sw.ReadToEnd()
            self.statusbar_item.Content = Path.GetFileName(filename)
            self.openfile = filename
        except Exception, ex:
            MessageBox.Show(ex.Message)
        finally:
            sw.Close()

    def save_file(self, filename):
        """
            f = open(filename, "w")
            try:
                f.write(self.textbox.Text.encode("utf8"))
            except Exception, ex:
                MessageBox.Show(ex.Message)
            finally:
                f.close()
        """
        sw = StreamWriter(filename) 
        try:
            buf = self.textbox.Text
            sw.Write(buf)
            self.statusbar_item.Content = Path.GetFileName(filename)
            self.openfile = filename
        except Exception, ex:
            MessageBox.Show(ex.Message)
        finally:
            sw.Close()

if __name__ == "__main__":
    Application().Run(WPF_TextEditor())

StreamReader で encode 無指定だと BOM 無し UTF-8 で読み書きになる。
けど open() では変換が必要なんだね、標準 Python に合わせたのだろうけど。
面倒くさいや、StreamReader を使ったほうが何かと便利そうだ。

メニューだけ XAML な所とか細かい所はこの Blog 過去ログを見て書いた。
結構色々やっていたんだな我ながら、まとめを兼ねて書いたようなものだ。

気が付いたけどこれだけで Ctrl+Z でのやり直しやテキストの D&D 編集ができる。
GtkSourceView ほど高機能ではないけど以外に使えるんでないかい TextBox って。