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

GtkNoteBook and TabControl

SeeMe for Linux では GtkNoteBook の各ページは Python の List でアクセス。

note = gtk.Notebook()
page = []
for i in range(4):
    tab = gtk.Label(tab_label[i])
    page.append(gtk.VBox())
    self.note.append_page(page[i], tab)
page[0].pack_start(self.sw1)
page[1].pack_start(self.sw2)

という方法を見つけたけど IronPython でも同じようにできるのかな?
.NET Framework では TabControl と TabItem なんていうものを使う。
まあこんなのは実際にやってみるのが早い。

note = TabControl()
self.page = []
for i in range(3):
    page = TabItem()
    page.Header = tab_label[i]
    note.AddChild(page)
    self.page.append(page)
self.page[0].Content = self.custome_listview
self.page[1].Content = self.default_listview

tab1

おぉ同じように使えるじゃないの!
XAML で作っているとこんな添え字でのアクセスは考え付きもしないだろう。
リストの添え字アクセスにメリットを感じるかどうかで人それぞれだと思うけど。

だけど…

tab2

又しても文字化けだよ。
lng ファイルは for Linux で使っている InifileReader クラスで読んでいるののだが…
もしかして一度全部読み込まないと UTF-8 を UTF-16 に自動変換できないのかな?
メニューの文字化けも解決していないしまいった、以下今日のバックアップ。

seeme_a404.zip

GetFullPath

ぱぇぽぃ2 ? Blog Archive ? Opera WMV

の最後でカレントディレクトリからでは端末で絶対パス名を取れない場合があると書いた。
待てよ? os.path が無い IronPython ではどうやるのだろう?

Path メンバ (System.IO)

System.IO.Path で普通に GetFullPath メソッドがあった。
そういえば IronPython では __file__ は使えるのだろうか?
ということで試してみる。

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

import sys
import System

print sys.argv[0]
print __file__
print System.IO.Path.GetFullPath(__file__)

abspath

あぁやはりカレントディレクトリではこうなるのか。
見落とししやすい所なので注意したほうがいいね、cmd.exe から起動しない!と言わない。

それと。

ShowDialog() メソッドで開いた Window で Value を参照しようとすると例外になる。
調べると ShowDialog() の戻り値自体が Boolean になっている、C# と違うじゃん。
何故?よく解らないけどコンパイルしないとこういう結果になるのかな。

それと。

バックアップを試せば解るけど Welcome クラスは Application インスタンスを作成していない。
それなのに Window が普通に動くんだが、メッセージループはどうなっているの?
試しに Show() メソッドで表示してみたら即終了、なるほどそういうことなのか。
Window は ShowDialog() メソッドを使うなら Application インスタンスから動かす必要は無いのね。
何のことか解らない人は Windows アプリは何故動くのかを勉強しておこう、→の本で。

ついでに Welcome のインスタンスを作ったらその中で sys.exit() できなかった。
その前に Close() しなきゃいけないのか、ふむふむ。

それと。

GtkEntry は Nautilus からファイルをドロップするとファイルのフルパスが流し込まれる。
Linux 版と動作を合わせたいので「ようこそ」のフルパス入力部で同じようにしたい。
つか「ファイルの参照ダイアログ」は使いたくないだけだが、多分使う人はいないと思うし。
「minipoli を使え」にしてもイイけどそれはやはりあんまりかと。

[WPF]ドラッグアンドドロップ

検索したら簡単に方法が見つかった、IronPython 言語への書き換えも普通どおり。
あぁ Windows の開発は楽チンだなぁ…日本語でアッサリ見つかるんだもの。
PyGtk になると日本語では実用的コードなんかまったく見つからないからね。

今日は結構勉強になった。
Ubuntu 上の VirtualBox で動かしている Windows 7 RC でやったほうが開発が楽しいなんて…
困ったら即 Ubuntu に戻れるからだろうけどさ、ということで今日のバックアップ。

welcomedlg

seeme_a403.zip

とりあえず「ようこそ」だけ移植完了、先はまだ長い。

SeeMe is to IronPython

C# で SeeMe for Windows を作るのはヤメにしたい。
Python ばかりやっているとやはり巷の噂どおり行末セミコロンを忘れるんだなぁこれが。
既定の型がバカみたく多い .NET Framework で型指定なんてもうやってられない。
何よりコンパイルしなきゃいけない、今では何故コンパイルする必要があるのかも疑問。

それより Visual Studio に嫌気が。
一昨日 Visual Studio の自動アップデートが掛かって一時間以上マシンが使えなかった。
サイズがデカ過ぎるんだよ!だから仮想の OS には入れたくないし又待たされるのはゴメンだ。
結果 Ubuntu と Vista の HDD を入れ替える回数が多くなる、いいかげんにコネクタが不安。
Ubuntu 上の仮想な Windows 7 上で気楽にサクッと小物アプリを作れるのが理想…
そうなるとやはり IronPython が一番の選択肢になる。

ところで IronPython で検索するとコンパイル方法とかよく見つかるんだが…
動的言語を何故コンパイルなんてしたい人がいるのか私にはまったく理解できない…
メリットをわざわざ自分で潰すなんて、コンパイルするなら C# で作ればいいんだし…
それよりなにより Windows 7 では exe にするとインストーラが必要に…
更にオープンソースにするもなにも配布は一つのアーカイブのみでオケになるのに…
Linux の /usr/bin 以下を見てそれでもコンパイルしたいのか?という感じ。

ということで SeeMe はとっとと IronPython で作り替える。

面倒くさいので XAML は C# のをそのまま使…えなかった、ハンドラ指定の部分で。
それと Python らしく Name 属性に大文字を入れたくないし Linux 版との整合性も整えたい。
エディタ部の腐った配置も書き換えたい、使う人には解らないだろうけど我ながらコードが酷い。
System.Windows.Window の継承クラスをトップレベルウインドウにしたいというのもあるけど。
のでやはり書き換えることに。

細かいパーツは XAML を三重クォートでまとめたのをいくつかコピペですませる。
XAML でやったほうが良いものは XAML で、コードのほうが都合がよいものはコードで。
inifile8.py は os モジュールが無いから Linux 版をそのままは使えなかった。
とりあえずツールバーまでは再現した。
とやっていたのでありますが。

seeme_ipy2

何故文字化けするの?
どうでもいいが IronPython は pyc キャッシュを作成しないことに今頃気がついた、遅!

原因が解らないけど、とりあえずココまでのバックアップ。
明日明後日はとある事情で田舎に帰りますのでまた来週。

seeme_a402.zip

realize signal

Y901x はステータスバーを GtkVBox で自作しているわけなんだが…

今まで GtkWidget 上のマウスカーソルを変更するのに expose-event シグナルを利用していた。
Widget 表示後に変更しないと例外でスローされてしまうからである。
でもそれって realize シグナルでイケたのね…

class CStatusBar(gtk.VBox):
    """
        Instead GtkStatusbar
    """
    def __init__(self, num, window, arg=None):
        #
        # etc...
        #
        ##self._first_show = False
        ##grip.connect("expose-event", self.__on_expose)
        grip.connect("realize", self.__on_realize)
        #
        # etc...
        #

    def __on_realize(self, widget, event=None):
        """
            cursor change
        """
        cur_grip = gtk.gdk.Cursor(gtk.gdk.BOTTOM_RIGHT_CORNER)
        widget.window.set_cursor(cur_grip)

    """def __on_expose(self, widget, event):
        if not self._first_show:
            cur_grip = gtk.gdk.Cursor(gtk.gdk.BOTTOM_RIGHT_CORNER)
            self._im.window.set_cursor(cur_grip)
            self._first_show = True"""

余計な自前フラグも不要だし圧倒的に簡単じゃないですか。
realize はマウスカーソルを変更したい Widget 自体のシグナルを利用しませう。

もう一つ実は気にしていてほったらかしていた部分。
Resize Grip を画像で表示していたこと、結構違和感がある。
せめてデフォルトの Grip Image を表示できないものか。

gtk.Style

色々探して GtkStyle に paint_resize_grip というメソッドを発見。
コレだとよく解らないので Devhelp から gtk_paint_resize_grip を検索。

paint_resize_grip

しかし思うんだが C 言語が解らないで PyGtk アプリを作るなんて不可能だ。
最低 Devhelp が理解できないと誰かが書いたコードのコピペしかやれない。

まあそれはよくて、ということは下記でイケそうだ。

class CStatusBar(gtk.VBox):
    """
        Instead GtkStatusbar
    """
    def __init__(self, num, window, arg=None):
        #
        # etc...
        #
        """self._im = gtk.Image()
        path = os.path.dirname( __file__ ) + "/img/grip.xpm"
        self._im.set_from_file(path)
        grip = gtk.EventBox()
        grip.add(self._im)"""
        grip = gtk.DrawingArea()
        grip.set_size_request(16, 16)
        grip.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.BUTTON_PRESS_MASK)
        grip.connect("expose-event", self.__on_grip_expose)
        #
        # etc...
        #

    def __on_grip_expose(self, widget, event):
        """
            Draw Resize Grip
        """
        widget.style.paint_resize_grip( widget.window,
                                        gtk.STATE_NORMAL,
                                        None,
                                        None,
                                        None,
                                        gtk.gdk.WINDOW_EDGE_SOUTH_EAST,
                                        event.area.width - 16,
                                        event.area.height - 16,
                                        16,
                                        16)

nomal_statusbar

GtkDrawingArea では GtkEventBox とは違い set_events する必要がある。
grip のサイズを 16×16 に限定しているけどコレでいい?

というかこれだけだと Dust とかのテーマでは Grip Image が追従しない。
と思ったけど Firefox も同じじゃん、それならコレでいいやという感じ。
素直に GtkStatusbar を使えば Gtk+ が勝手にやってくれる。
けど Gedit のように境界線が途切れてしまうし、Gtk+ も困ったものだ。

最後に何だかよく解らなかったので *.pyc のキャッシュは毎回同梱していた。
けど無駄にも程があるので今回から省いて配布するようにした。

ということで Y901x 0.1.8 の公開です。
単なるお知らせだけじゃツマランのでコードも貼ってみました。

Y901x 0.1.7

結局スクロール関連はそのまま公開。
別にイイや、問題があったら後で直せばよいのだし。

ついでに Windows Y901 はリストの次や手前をゴミ箱移動できる機能があるのを思い出した。
ので適当に機能追加、GtkTreeView の手前イテレータ取得は前にやったので簡単だった。

ところで Shift + Delete とかをアクセラレータで処理する方法だが

self.accelgroup0.connect_group(gtk.keysyms.Delete, 0, gtk.ACCEL_VISIBLE, self.on_keydown)
self.accelgroup0.connect_group(gtk.keysyms.Delete, gtk.gdk.SHIFT_MASK, gtk.ACCEL_VISIBLE, self.on_keydown)
self.accelgroup0.connect_group(gtk.keysyms.Delete, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.on_keydown)

という感じで GtkAccelGroup を作って

def on_keydown(self, accelGroup, window, keyval, modifier):
    # メニューに無いキーボード操作まとめて
    if keyval == gtk.keysyms.Delete:
        if modifier == gtk.gdk.SHIFT_MASK:
            self.delete_prev()
        elif modifier == gtk.gdk.CONTROL_MASK:
            self.delete_next()
        else:
            self.delete()

とすれば modifier で振り分けできるようです。
GtkAccelGroup でイチイチ modifier も指定しなきゃいけないのね。
これくらいは勝手にやってもらいたいと思うけど意図があるんだろうな。