IronPython」タグアーカイブ

more WPF

Planet Python

私の blog はおもくそ日本語なのにまた見つけられちゃった。
IronPython でこんなことをやっているのは世界中で私しかいないからだろうけど。
本当はスパム対策で日本から以外のアクセスは遮断したいんですけど。

mojibake

しかし日本からのアクセスだと utf-8 でも化けてリンク先にアクセスできないんですね。
Error 404 – Not Found になってしまう、多分英語圏でないところは全部ダメだと思う。

今後タイトルくらいは英語にしておいたほうがよさそう、日本人が到達できないのでは困る。
ロクな語学力が無いけどソースコードのコメントもなるべく英語にするべぇ、それで十分だろう。
今回から練習、ありがちな Enjoy! というサフィックスも無意味に入れて。

しかし世界中探しても WindowsForm ばかり…

次期Visual Studio 2010と.NET Framework 4.0の新機能 ? @IT

Visual Studio 2010 は UI が WPF 製になるんだ、もはや完全なる .NET Framework の世界。
開発環境本体が WPF で WindowsForm を使う人はまずいないだろう。
WindowsForm って Windows SDK の単なるラッパーですよ、既に過去の遺物。
みんな早々に WPF に移行しませう、IronPython で(それはもしや私だけ…

WPF = 豪華なグラフィックス

な偏見はそろそろヤメようよ、この記事を書いた人もそれっぽいし。
PyGtk みたく普通の GUI 部品として使ってはいけないなんて MS も言っていないわけで。
GTK+ なり Swing なりを知っている人ならもっと WPF のレイアウトに興味を持とう、楽しいよ。

だいいち VirtualBox のゲストで動かす人もいるんだからエフェクトに凝られても困る。
グラフィック関係は味付け程度に考えればいいと思う。

でも Windows 7 に .NET Framework 4.0 が入り DLR が標準ならもう VS は不要のような…
IronPython 等が流行するならだけど、フリーな XAML デザイナが今後出てくるような気が。
MS は VS より .NET Framework を広めたいはずだから自社で出す戦略もアリ。

既に VC++ は API の追加によるヘッダの提供くらいしかやることが無いだろう。
WPF の開発が可能になった VS 2008 の時と比べてかなーり製品として魅力が薄い感じ。
IDE の親切機能自体は強化されているだろうし C# 4.0 がやりたい人にはいいかも。

*****

ついでに、 Ubuntu の PrintScreen でマウスカーソルは全部矢印になると解った。
書くまでもなく上の画像を撮影した時はリンクを示す手のカーソルになっていたのにこうなった。
マウスカーソルは本当は画像化できないので書き足しているというのがよく理解できます。

Windows のネタなのに全部ホストの Ubuntu + gedit でネタを作っている私であった。

Enjoy!

.NET framework ゴミ箱

ファイルをごみ箱に削除する – IronPython

こんな方法があったのか。
てかそれって static なんだからインスタンスは作成しなくてもいいんだけど。

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

import clr

clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")
# namespace Microsoft は PresentationCore にあるけど…
clr.AddReference("Microsoft.VisualBasic")

from System import *
from System.Windows import *
from Microsoft.VisualBasic.FileIO import *

class SendToRecycleBin(Window):
    """
        ファイルをドロップするとゴミ箱へ移動させる WPF Window
    """
    def __init__(self):
        self.Width = 320
        self.Height = 240
        self.Title = "SendToRecycleBin"
        self.AllowDrop = True
        self.Drop += self.on_drop

    def on_drop(self, sender, e):
        files = e.Data.GetData(DataFormats.FileDrop)
        for file in files:
            FileSystem.DeleteFile(  file,
                                    UIOption.OnlyErrorDialogs,
                                    RecycleOption.SendToRecycleBin )

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

つまりこれでいい。
しかし何故その名前空間なんだ?意味不明だし今までみつからないわけだ。
普通なら

.NET framework ゴミ箱

なんてなキーワードで探すもん。
他の言語ではできないしみたいじゃん。
○B 屋って必ず「○B で」って書くからね。

しかし Microsoft 名前空間といえば

import Microsoft

def on_open(sender, e):
    dlg = Microsoft.Win32.OpenFileDialog()
    if dlg.ShowDialog(self):
        MessageBox.Show("push ok")

openfiledlg7

と、せっかく用意した機能なのに… PresentationFramework.dll 内にあるというのに…
フックがあるので仕様により古いダイアログになるという Microsoft 側の大失敗があるし。
しかもフックを排除する方法が無い、Windows 7 でコレはないだろう。
のイメージがあって利用する気にもならんかった。

.NET Framework クラス ライブラリ

○B だけやたら豊富に揃っているね、どうしてもこの言語を残したいらしい。
ま、利用できるモンは利用すればいいだけさ。

参考までに以前書いた Linux (GNOME 限定)でのやりかた
ぱぇぽぃ2 ? Blog Archive ? g_file_trash ってのがあった

DLR は Silverlight に同梱でした

IronPython が Windows 7 RC で使っていて妙に遅い原因が判明した。
Silverlight をインストールしていなかったからだ。
というか Silverlight に含まれている DLR がインストールされていなかったというわけ。

Windows 7 RC には初期状態で DLR が入っていると思い込んでいたよ。
.NET Framework 4.0 の目玉の一つなはずだから多分正式版には存在…
Silverlight はいらないんだけど単体な DLR をインストールするのも…ついでに。

仮想で動かしている Windows で Silverlight を動かすなんて厳しすぎ。
それより Opera では動かないので今までダイアログが出ても拒否していたわけです。

マイクロソフト – ホーム

に IE で行くと下記ダイアログがでる、もちろん Opera じゃ無理。
「インストール」ボタンを押してただひたすら指示に従う、再起動は不要。

silver

それだけで今までの激遅 ipy.exe がウソみたく快適に、バカみたいに早い!
でも初期化はやっぱり遅い、これだけはあきらめるしかない。

IronPython ではインタラクティブシェルはあんまり使わないわけですが。
Linux で Python は dir() と pydoc を使いまくるので bash は必須ですけど。
IronPython じゃ pydoc は無いし、それより MSDN を見たほうがわかり安い。

Windows 7 で IronPython そのよん

珍しく昼間に更新、単に休みでヒマなだけ。
やっぱり今日も IronPython で WPF を製作者の意図に反する利用方法をしようと四苦八苦。
とにかく GtkUIManager のように一部パーツだけを XML にして綺麗なコードにしたい。

こんなことがしたいのは私だけなのだろうか?検索しても全然…
MediaElement とかで検索するとみんな Microsoft の要求どおりに XAML で書いているし。
その時点でフル XAML は使い物に(略)、だから WPF アプリが全然表に出てこない。

XamlReader にはよく見たら Parse という文字列から読み込む静的メソッドがあった。
これでソースコード中にメニューのみの XAML を埋め込むという技が使える。

それとやはり Name プロパティからスマートにハンドラ指定する方法があった。
Menu は ItemControl 派生クラスなので FindName メソッドが利用できるようだ。
メニュー全部に Name プロパティを指定する必要があるけど。

ついでにステータスバーも追加して…
何故 System.Windows.Controls.Primitives って名前空間を分けているの?
Python の場合は完全名を書けばいいというわけじゃないので import が無駄に増えてしまう。

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

import clr

clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")
# OpenFileDialog を使うため
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
# 名前衝突が起こるので必ず選択 import させる
from System.Windows.Forms import OpenFileDialog, DialogResult

ui_str = """<Menu
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <MenuItem Header="ファイル(_F)">
        <MenuItem Header="開く(_O)" InputGestureText="Ctrl+O" Name="menu_open" />
        <Separator/>
        <MenuItem Header="終了(_Q)" InputGestureText="Ctrl+Q" Name="menu_close" />
    </MenuItem>
</Menu>"""

class MoviePlayer(Window):
    """
        IronPython と WPF で作る Windows 7 向け動画プレイヤー
        H.264 や MOV も Windows 7 はデフォルトで再生できます
        まだ再生だけしかできないスケルトンですけど
    """
    def __init__(self):
        """
            PyGtk の GtkUIManager 風にメニューを読み込む
            XAML ファイルを別に用意せずに全部ソースコードに詰め込む
            残念ながらイベントハンドラは自前コネクトしかできないようだ
        """
        menu = XamlReader.Parse(ui_str)
        menu.FindName("menu_open").Click += self.on_open
        menu.FindName("menu_close").Click += self.on_close
        DockPanel.SetDock(menu, Dock.Top)
        # Player
        self.player = MediaElement()
        self.player.MediaOpened += self.on_player_mediaopened
        # StatusBar
        statusbar = StatusBar()
        DockPanel.SetDock(statusbar, Dock.Bottom)
        self.statusbar_item = StatusBarItem()
        self.statusbar_item.Content = "準備完了"
        statusbar.Items.Add(self.statusbar_item)
        # DockPanel
        dpanel = DockPanel()
        dpanel.Children.Add(menu)
        dpanel.Children.Add(statusbar)
        dpanel.Children.Add(self.player)
        # self
        self.Content = dpanel
        self.Width = 320
        self.Height = 240
        self.Title = "Y901w"
        self.AllowDrop = True
        # event
        self.KeyDown += self.on_keydown
        self.Drop += self.on_drop

    def set_uri(self, filename):
        self.player.Source = Uri(filename)

    def on_open(self, sender, e):
        """
            この処理の為だけに WindowsForm を使うはめに
        """
        openDlg = OpenFileDialog()
        openDlg.Title = "ファイルの選択"
        if openDlg.ShowDialog() == DialogResult.OK:
            self.set_uri(openDlg.FileName)

    def on_close(self, sender, e):
        """
            Close() を呼ぶだけで終了します
        """
        self.Close()

    def on_keydown(self, sender, e):
        """
            InputGestureText は表示だけなので自分で処理
            e は System.Windows.Input.KeyEventArgs
            WindowsForm とは別モノなので注意ね
        """
        if Keyboard.Modifiers == ModifierKeys.Control:
            if e.Key == Key.O:
                self.on_open(self, e)
            if e.Key == Key.Q:
                self.on_close(self, e)

    def on_drop(self, sender, e):
        """
            filenames は System.Array なので str に変換
        """
        filenames = e.Data.GetData(DataFormats.FileDrop)
        filename = str(filenames[0])
        if filename != None and filename.Length != 0:
            self.set_uri(filename)

    def on_player_mediaopened(self, sender, e):
        self.statusbar_item.Content = "再生中"

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

コメントを省くと百行に満たないコードなのに参照多すぎ!
もう少し名前空間をまとめられなかったのかと問い詰めたい。
まあ Youtube から &fmt=18 で得た H.264 もこいつで再生だけならできた。
既にダイアログでもドラッグアンドドロップでも開けますよ。

howe

これでメニューのみ XAML にするとコンパクトに収まるのが証明できた。
こういうふうに作れると気持ちがイイと思うのに WPF 自体はそれが目的じゃないんだよなぁ。

ま、IronPython はこんなこともできますよということで。
C# で作っていると多分こんなことをやろうなんて思いつきさえしないと思う。

Windows 7 で IronPython そのさん

WPF にてコードでメニューを作る方法がイマイチ解らない。
というか作れたとしてどう考えてもベタ打ちな方法しかできないだろう。

ここは GtkUIManager のように XML で綺麗に作りたい。
そのための XAML じゃないか!
でもメニューとか個別パーツのみを XAML にするってできるのかな?

ということでやってみた。

いくら探しても文字列から XAML を読み込む方法が見つからない。
CLR にはデルヒャァの TStringStream みたいなのは無いの?
しかたがないので XAML ファイルを別に用意する。

<Menu
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <MenuItem Header="ファイル(_F)">
        <MenuItem Header="開く(_O)" InputGestureText="Ctrl+O" Name="menu_open" />
        <Separator/>
        <MenuItem Header="終了(_Q)" InputGestureText="Ctrl+Q" x:Name="menu_close" />
    </MenuItem>
</Menu>

というメニューのみの XAML を仮に作ってみた。
一番の親に CLR 名前空間定義は必須のようです。

IronPython はコンパイルしないので InitializeComponent() できない。
ので XAML 内でハンドラ指定はできないようだ、いくら試してもエラーばかり。
とりあえず上記に ui.xaml という名前を付けて。

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

import sys
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.IO import *
from System.Windows.Markup import XamlReader

class MoviePlayer(Window):
    def __init__(self):
        self.Title = "メニューだよ"
        # Menu を GtkUIManager 風に読み込む
        # ようにしたいけど今はこれが精一杯
        i = sys.argv[0].rindex("\\")
        xaml_path = sys.argv[0][:i] + "\\ui.xaml"
        f = FileStream(xaml_path, FileMode.Open, FileAccess.Read)
        _menu = XamlReader.Load(f)
        DockPanel.SetDock(_menu, Dock.Top)
        _menu.Items[0].Items[0].Click += self.on_open
        _menu.Items[0].Items[2].Click += self.on_close
        # DockPanel
        dpanel = DockPanel()
        dpanel.LastChildFill = False
        dpanel.Children.Add(_menu)
        # self
        self.Content = dpanel
        self.Width = 320
        self.Height = 240

    def on_open(self, sender, e):
        MessageBox.Show("わーい")

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

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

menu_first

何をやっているかはなんとなく解ると思う。
とりあえずパーツのみの XAML は可能だと解った。
少しだけ GtkUIManager 風に作れたが Items の順番でハンドラ指定では…

ウインドを作る( PyGtk+Glade )

の最後みたいな処理を作るしかないかな?それはそれで難しくは無いけど。
もっと Name プロパティからスマートに指定できそうなんだけど…続くかも。