2008年4月22日火曜日

OnPaint on wxWidgets/wxPython

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
結局、メソッドの呼び出しとイベントの関係をプラットフォームごとに整理しないと始まらない。もちろんプラットフォーム/下回りに使われているAPIごとの理解も必須。gonzoつまりアドホックに試していたら寿命が尽きてしまう。

というわけで、wxが何で実装されていて何にmapされているのか調べることした。まずは足回りはなんであるかを知ることからかな。高林哲氏のページに触れられているように、ネイティブなwindow描画システムをラップしてプラットフォーム非依存なAPIを提供するモノなので。

たなの中に寝ていたCross Platform Programming With wxWidgets を引っ張り出してきてパラパラしてみる。
同書の電子版、重め(7MB)。

cross~~のp8から引用。wxWidgetsは、portレイヤーを持っていて、そこで指定されるプリミティブな機能を各プラットフォームごとに実装している。


EVT_PAINT
前出のCross platform ~~はflickerをなくすにはという観点に言及した上でpaintについて述べている(Chap5)

で、window systemによらずに汎用的に使われているテクニックを列挙する。

  • doublebuffer : 小さいrectを複数回かけて画面に書くとちらつくのでいったんでかいbufferに書いてから画面に書き出す。

  • invalidation rect : 全部を書き直すと無駄なので、書き直しが必要になった領域をrectで管理する。書き直しを要求するとき(wxではwxWindow::Refreshを呼び出すとき)に指定する。



ここから先はwx依存の話

  • wxWindow::RefreshとwxWindow::Updateの意味。
    wxWindow::Refreshを呼ぶとPaint Eventが発生する(その前にwxEVT_ERASE_BACKGROUNDが発生する、後述)。呼ばないといつPaintされるかわからない。自身のsizeに依存して表示内容が変わるようなwidgetをSizeしたときにはrefreshしてやらないとPaintが呼ばれないので、再描画のルーチンが走らない。

    さらにwxWindow::UpdateをよんであげないとBufferの中身が画面に反映されない。どういうわけだか手元のLinux環境(Centos5.1 gnome)では、Updateがなくても大丈夫、本当はよくないのだろうけど。

  • wxFULL_REPAINT_ON_RESIZE:
    今回問題となったwidgetでは指定必須。
    なぜならサイズが変わると中身が全部無効になるので、すべての書き直しが必要。縮尺の違う画像パーツをwindow上にのこされても意味なし。
    で、最初はこの指定をしていなかったのだが、Linux/GTK+だったので現れなかった模様。Mac OS Xで動かしたときに、resize時windowに「ゴミ」が残るという形で発覚。

  • wxEVT_ERASE_BACKGROUND:(p134)
    wxWidgetsでいうところのwxEraseEvent。目的はプラットフォーム側がおこなうbackgroundのclearの方法を指定することにある。たとえばpaintが全面書き換えならclearしなくてもごみがwindowに表示されることはない。それどころかclearされるとちらつく。極端な場合だと「べろんべろんべろん」とclear->paintのサイクルが見えてしまう。
    wxWindow::SetBackgourndColorはこのイベントのデフォルトのhandlerがwindowのrectをfillする際の色を指定している。だからpaintのhanderでwx.Brushをつかってbackgroundをfillするのとは意味が違う。結果としてできる外見がおなじになるかもしれないが。

    残念ながらこのeventの話はwxPython in Actionの中には出てこない。とはいってもこの本の価値がさがることはまったくない。cross ~~とは方向性が違う本ですから。

    さらにwxBG_STYLE_CUSTOMなるものをwxWindow::SetBackgroundStyleをつかって設定できるようだ。実装報告のスレッド in wx dev ML
    この子は、もっとローレベルの書き換え、プラットフォームのwindow systemがfillすることを抑制できるようになる。SetBackgourndColorはwxWidget側がやっていたがそれとは別にwindow systemがやっているfillも存在するのだ。これをコントロールできる。なにが起こるかはプラットフォーム依存なはず。そしてちょっと見た限りではドキュメントが存在しない。orz

    L9397 @ google code seach
    これと同じようにほかのプラットフォームでSetBackgroundStyleしているところが見つかればよいのだが。


    画面に画像ファイルを貼り付ける @ Megnumi221 , d.hatena

    OnEraseBackgroundメソッドで背景をクリアするらしいが、なぜ必要なのかよく分からん...。

    そういうことなんですよ。Megnumi221さん。



文章がだいぶ長くなってしまったのでプラットフォームごとの調査はまた別のページで。

0 件のコメント: