Python」タグアーカイブ

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 も指定しなきゃいけないのね。
これくらいは勝手にやってもらいたいと思うけど意図があるんだろうな。

GtkTreeView Scroll

何を今頃だが昨日旧 Blog の「ぱぇぽぃ」を削除した。
月単位で逆アクセスがまだ百を越えていたので意図的な放置だったんですが…
流石に三年前の「あの頃の私」が書いた記事は情報が古すぎると思ったもので。

なんたってバリバリな「 Windows 以外の OS なんて知らないよ!」なデルヒャァ屋だったし。
今になって考えればキャーリックスが大失敗に終わったのは当然過ぎて笑える結果。
mono で WindowsForm よりはマシだったがせめて GTK+ にすればよかったのに。

他にサイトの一部を整理したり、伴って外部リンクしていたコードの Blog 起こしとか。
さぼっていたわけじゃないんですけど Blog で書くようなネタが作れなかった。

ということで久々にコードを。

Y901x のリストが再生開始時に選択行が見えない場合がある。
ということでリストアップしたら表示配位内にスクロールさせようと考えた。

何故この時期に Y901x をやっているんだと言わないでくれい。
自分が作ったアプリの中ではやはり一番コイツを使うんだよということで。

Windows 版 Y901 ではやっていたんですけどね、Cinema は忘れた。
一つ上と一つ下を残すようにしないと次をクリックしにくいんで結構考える。
正直メンドイ、WPF ListView の ScrollIntoView メソッドみたいなのは無いかな?

Gtk::ScrolledWindow – Ruby-GNOME2 Project Website

Ruby だが value は upper – page_size 以下にしなければいけないとか見つかるんだが
そうすると何故かうまくいかないので無視こいて

def selection_scroll(self):
    """
        def __on_selection_changed(self, selection):
        を利用だと上手くいかない
    """
    # Get GtkAdjustment
    adjustment = self.view.get_vadjustment()
    # calc
    n = self.__get_select_num()
    if n == -1:
        return
    page_size = adjustment.get_property("page_size")
    column_height = self.column1.cell_get_size(gtk.gdk.Rectangle())[4]
    # 計算値
    sc = column_height * n
    # 現在の表示範囲に入っているか検証
    v = adjustment.get_value()
    h = page_size + v - (column_height * 2)
    if sc == 0.0:
        adjustment.set_value(sc)
    elif sc < v:
        adjustment.set_value(sc - column_height)
    elif sc >= h:
        adjustment.set_value(sc - page_size + (column_height * 2))

def __get_select_num(self):
    model, it = self.selection.get_selected()
    if it:
        path = model.get_path(it)
        return path[0]
    return -1

def __on_size_request(self, widget, event=None):
    self.selection_scroll()

てな感じでリストアップしたらこのメソッドを呼んでやる。
というところまでできた、まだ検証が甘いので今日はここまで。

Align left

今日の SeeMe for Linux バックアップ。
はもうヤメにしてトップページにベータとして公開することにした。

しかし Windows 版の About をタブにしたのは失敗だったかな…
なるべく見た目を共通にも GTK+ では GtkAboutDialog を使うのが普通だ。
Windows はこういうのを提供しないのか?知らないだけで有るのだろうか?

それと最初は国際化を狙って日本語部分を strs.py に分けて作っていたんだけど…
面倒だし英語サイトを作る語学力は無いし需要は微妙このうえないし。
Windows 版と表記が違うというのは避けたいのでやはりリテラルで済ませるかと。

それにしてもコードでウィジェット配置は面倒だ。
GtkLabel を GtkTable 内で左寄せするにはどうすればいいのか?

label2 = gtk.Label("標準のサーチエンジン UNIQUEID")
label3 = gtk.Label("Speed Dial サーチエンジン UNIQUEID")
label2.set_alignment(0.0, 0.5)
label3.set_alignment(0.0, 0.5)
table.attach(label2, 0, 1, 0, 1, gtk.FILL)
table.attach(label3, 0, 1, 1, 2, gtk.FILL)

今試したら上記みたくすればイケそう、あまり試していないので問題あるかも。
HTML の table タグは左寄せがデフォルトなのに何故中央配置がデフォルトなんだろう?

それとラヂオボタングループをインデントさせたいのだがどうすれば?
GtkBox の set_spacing では上下左右全部の指定しかできないんだよね。
mono で作った時は GtkHBox を挟んで左側に空文字を置くというアホな方法を使ったけど。
左だけにマージンを指定するにはやはりそういう方法しか無いのかな?意外と難しい。

GtkTreeView in Get front Iterator

今日の SeeMe for Linux バックアップ。
バックアップ機能とか細かいものはまだ作っていないけど編集は可能になったよ。
wnck を使った Opera 起動チェックも行っている、しかし私以外に使う人がいるのだろうか?。
見た目は前回と変わらない、いや、セパレータのラインなんかは表示するようにしたけど。

seeme4_t6

seeme4_t6.tar

ところで Gtk# をやっていた頃にもリンクしたけど

PyGTK FAQ Entry

GtkListStore で手前の GtkTreeIter を得て順番を入れ替える方法なんですけど。
PyGtk における GtkTreePath は単なるタプルなので

def on_item_up(self, widget, event=None):
    selection = self.custome_treeview.get_selection()
    model, it = selection.get_selected()
    if it:
        path = model.get_path(it)
        if path[0] > 0:
            path2 = (path[0]-1, )
            itprev = model.get_iter(path2)
            if itprev:
                model.swap(it, itprev)

def on_item_down(self, widget, event=None):
    selection = self.custome_treeview.get_selection()
    model, it = selection.get_selected()
    if it:
        itnext = model.iter_next(it)
        if itnext:
            model.swap(it, itnext)

とまあコレでイケちゃうんですね、無駄に型に厳しい Gtk# でやるより楽。
WPF の ListView はデータの加減算だけでイケるけど GTK+ はチト面倒なのが本音。
それでも GtkTreeView から得られる情報のみで賄えるのが嬉しい。
データと表示が繋がっているってやはり素晴らしい、Windows SDK じゃありえない。