2008年4月30日水曜日

ProgressDialog(その2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
wx.ProgressDialogは、気難しい。

GTK版@ gnome on Centos 5とwin32版@winxpでためしたけど・・・
  • wx.PD_AUTO_HIDEを設定したProgressDialogでUpdateがmaximumと同じ値を引数に呼び出されると自動的に消える。

  • maximumより大きな引数でUpdateを呼びだすとassertion failになる。

  • wx.PD_AUTO_HIDEしないで、終了時にボタンを押して閉じる。→大丈夫

  • しかし、Destroyするとこける。

  • wx.PD_AUTO_HIDEでないときにDestroy()を呼ぶとこける。つまり親が閉じるかユーザが閉じるか以外では閉じられない。

どーなっているんじゃ?すくなくともDestroyを呼んじゃいけないらしいのでDialogにmaxをセットして閉じてもらうしかないね。となると必然的にmaxを100で使うかもしくは何かでwrapしてwrapしたやつにmaxを覚えさせるのが健全だ。

なんでDestroyの話が出てくるかというとSample CodeではEventHandlerの中でNewしてDestroyしているのだ。もちろん動くし、こけたりしない。

まあ、EventHandlerとの絡みでなにかおきているのだろうが。
親frameがMDIChildだった場合がどうなるかはその後調査。


import wx

app = wx.PySimpleApp()
frame = wx.Frame(None)
pd = wx.ProgressDialog(
parent=frame,
title="progress dialog",
message="waiting completion.",
maximum = 100,
style = wx.PD_APP_MODAL
| wx.PD_ELAPSED_TIME
| wx.PD_SMOOTH
| wx.PD_AUTO_HIDE
)
count = 0
def Updator():
global count
global pd
if count <= 100:
pd.Update(count)
count += 1

timer = wx.PyTimer(Updator)
timer.Start(100, wx.TIMER_CONTINUOUS)
frame.Show()
app.MainLoop()

ProgressDialog

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ProgressDialog
はDialogじゃなくてFrameを親に持つ。

ちょっと考えれば、ブロッキングしないのでそうなのだが。

2008年4月28日月曜日

非技術的技術関連話題?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
社会の中にあって何ぼの技術ですが・・・。

最新・経済地理学 @ 池田信夫 blog

起業やイノベーションの本質は、技術ではなく感度(alertness)とビジネスモデルであり、それを売り込む人脈だ。これらは個人的知識だから、大学で教わることはできない。シリコンバレーは、それを体で教える「コミュニティの学校」だが、「本籍」の企業コミュニティの延長上で生活する日本人留学生は、そのいちばん大事な勉強をしないで帰ってくるのだ。

発明学会がj-waveプラトンに招かれていたときに発明の種は「なにくそ何だこのやろう」・・不便に対する気づきだといっていた。不便の解決手段が技術。解決手段でないなにかは技術ではない?!あなたが会社の単なるパーツでしかないのは、狭い意味でのスキルの問題ではない。

2008年4月25日金曜日

Pythonでコードを書いていて思うこと。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

class xxx(Base):
def __init__(self):
Base.__init__(self)
self.hogehoge = foo()

ん~~こういうコードを書いているとなんでクラスにせにゃあかんのやと思うのですよ。

class xxx():
self.__base__ = Base()
self.__mixin__ = [MixinA, MixinB]

とかでもよい気が。.__base__とかが親っていう仕組み。・・・ただこれってprototype baseのオブジェクト指向とかかなんかでjsちっくなのよね。

.のかわりに/にするとか。object, isは予約語、.はself、/のあとの.は__xxx__と同じ扱い。

object xxx is
./.base = Base()
./.mixin = [MixinA, MixinB]

え?ああ、ファイル名のコンベンションをそのままマップしただけだよ。だってこうするとさ、便利でね?webappフレームワークとか作るとき。

2008年4月23日水曜日

OnPaint on wxWidgets/wxPython その7 M$ windows

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
これは完全におまけですが、ついでなので調べることにしました。

src/msw/windows.cpp
まあ、もはやお決まり。まず、src/[platform]/window.cppをみる、のだ。これであなたも俺様window systemにwxWidgetをportできますねw。

  • OnPaint
    WM_PAINT
    しかしまぁごてごてしているなぁ。

    // Can be called from an application's OnPaint handler
    void wxWindowMSW::OnPaint(wxPaintEvent& event)
    {
    #ifdef __WXUNIVERSAL__
    event.Skip();
    #else
    HDC hDC = (HDC) wxPaintDCImpl::FindDCInCache((wxWindow*) event.GetEventObject());
    if (hDC != 0)
    {
    MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
    }
    #endif
    }

  • EraseBackground
    一見入り組んでいるが、
    • HandleEraseBkgndがM$ windows側から呼ばれるEventHandler。

    • OnEraseBackgroundがwxのデフォルトのPaintEventHandler


    bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
    {
    wxDCTemp dc(hdc, GetClientSize());
    wxDCTempImpl *impl = (wxDCTempImpl*) dc.GetImpl();

    impl->SetHDC(hdc);
    impl->SetWindow((wxWindow *)this);

    wxEraseEvent event(m_windowId, &dc);
    event.SetEventObject(this);
    bool rc = HandleWindowEvent(event);

    // must be called manually as ~wxDC doesn't do anything for wxDCTemp
    impl->SelectOldObjects(hdc);

    return rc;
    }

    void wxWindowMSW::OnEraseBackground(wxEraseEvent& event)
    {
    // standard non top level controls (i.e. except the dialogs) always erase
    // their background themselves in HandleCtlColor() or have some control-
    // specific ways to set the colours (common controls)
    if ( IsOfStandardClass() && !IsTopLevel() )
    {
    event.Skip();
    return;
    }

    if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM )
    {
    // don't skip the event here, custom background means that the app
    // is drawing it itself in its OnPaint(), so don't draw it at all
    // now to avoid flicker
    return;
    }

    wxDC *dc = event.GetDC();
    if (!dc) return;
    wxMSWDCImpl *impl = (wxMSWDCImpl*) dc->GetImpl();

    // do default background painting
    if ( !DoEraseBackground(GetHdcOf(*impl)) )
    {
    // let the system paint the background
    event.Skip();
    }
    }

    bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
    {
    HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
    if ( !hbr )
    return false;

    wxFillRect(GetHwnd(), (HDC)hDC, hbr);

    return true;
    }

  • wxWindow::Refresh
    • RedrawWindowウィンドウのクライアント領域にある、指定された長方形またはリージョンを更新します

    • InvalidateRect指定されたウィンドウの更新リージョンに 1 個の長方形を追加します。更新リージョンとは、ウィンドウのクライアント領域のうち、再描画しなければならない部分のことです。

    う~~ん。ほかのプラットフォームは1つの関数なのに。M$は混乱しているなぁ。わけわからん。しかもフラグがすごくいっぱいあるし。こんなAPIを使わないといけないプログラマは気の毒だ。まあ歴史があるともいうが。

    void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
    {
    HWND hWnd = GetHwnd();
    if ( hWnd )
    {
    RECT mswRect;
    const RECT *pRect;
    if ( rect )
    {
    wxCopyRectToRECT(*rect, mswRect);
    pRect = &mswRect;
    }
    else
    {
    pRect = NULL;
    }

    // RedrawWindow not available on SmartPhone or eVC++ 3
    #if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
    UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN;
    if ( eraseBack )
    flags |= RDW_ERASE;

    ::RedrawWindow(hWnd, pRect, NULL, flags);
    #else
    ::InvalidateRect(hWnd, pRect, eraseBack);
    #endif
    }
    }

  • Update
    UpdateWindow
    ですね。

    void wxWindowMSW::Update()
    {
    if ( !::UpdateWindow(GetHwnd()) )
    {
    wxLogLastError(_T("UpdateWindow"));
    }

    #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
    // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
    // handler needs to be really drawn right now
    (void)::GdiFlush();
    #endif // __WIN32__
    }
  • OnPaint on wxWidgets/wxPython その6 GTK

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    その5ではCarbon on Macをみたので、次はGTKの中身です。

  • 5.3. GTK+ を使って、別スレッドでちょっとしたことをしている。
    題は違うのだが、gdk_flushの説明が出てくる。同期がとられますな。fileのflushと同じだ。

    5.3. GTK+ を使って、別スレッドでちょっとしたことをしている。 gdk_threads_enter/gdk_threads_leave() を使ってちゃんとロックしているのに、表示が正しく更新されない。 [GTK 2.x]
    GTK+ を使って、別スレッドでちょっとしたことをしている。 gdk_threads_enter/gdk_threads_leave() を使ってちゃんとロックしているのに、表示が正しく更新されない。 [GTK 2.x]

    効率を上げるため、X ウィンドウシステムでは、一つ一つコマンドをすぐに送るのではなく、コマンドをいくつか一まとめにして、X サーバーにバッチで送っています。

    マルチスレッド化されていないプログラムでは、この点に関する心配は無用です。というのは、メインループに制御が戻った時には、まず最初に、残っている X リクエストが X サーバーに送出されるからです。

    しかし、メインループ以外でスレッドから GTK+ を呼び出している場合は、バッチ化されたコマンドをいつ送出するのかは、GTK+ にはわかりません。そのため、通常は、gdk_thread_leave() を呼び出す前に、 gdk_flush() を呼んでおく方がいいです。

    実際は、gdk_flush() だと、ここで必要とする以上に高くつきます。というのは、この関数も同様に、 X サーバーで残りのコマンドが終了するのを待つからです。ですから、性能が気になる場合は、直接 XFlush() を呼び出した方がいいかも知れません。


  • Gdk の変更点
    訳が悲惨。「不正な領域」ってinvalidateされたってことね。つまりあらたに描画しなおしが必要な領域ってこと。

    GdkWindow は "不正な領域" を保守します; つまり X (または他のウィンドウシステム) からエキスポーズ・イベント (訳注: 画面の再描画イベント) を受け取ると、ウィジットに直接シグナルを発行せずに不正な領域に追加されます。ハンドラがアイドル中の場合は GTK+ が gdk_window_process_updates() を呼び出します。この関数は不正な領域を矩形の組に変換して、エキスポーズ・イベントとしてこの組をウィジットに送信します。ウィンドウの位置を再描画するために、アプリケーションは gdk_window_invalidate_rect() を呼び出す必要があります; つまり、これは指定されたウィンドウの範囲を不正な領域に追加することを意味します。アプリケーション自身がエキスポーズしたり、他の描画を最適化することが劇的に簡単になりました; つまりそれは expose_event ハンドラを書くだけで、GTK+ がその機能を担当してくれます。

  • OnPaint on wxWidgets/wxPython その5 HIView

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    The Drawing Model @ HIView Programming Guide

    ちょっと脱線。
    The Coordinate System @ HIView Programming GuideQuartzって左下隅が原点とのこと。びっくり。混乱を避けるための救済措置はあるが。

    Drawing in Views @ HIView Programming Guide

    ToolBox API徒然草(2004/01/16)



    和訳っぽいものを発見
    。出所が不明だが。


    また、Viewベースのコントロールが旧コントロールと大きく違う点は、それがウィンド
    ウと関連付けず単独で定義できることです。当然、この場合に表示はなされていません
    が、カット&ペースト処理などで、単独オブジェクトとして別ウィンドウに移動させるよ
    うな処理が簡単にできます。

    へ~~。ControlにParent Windowがないってこと??nonownedwnd.cppってそのためにあるのか?

    Composite WIndowではEventWindowUpdateやkEventWIndowDrawがこないらしい。
    今回用があるのは次の箇所。前出のThe Drawing Modelの和訳に相当するようです。反が違うので内容が違う部分もありますが、大筋では同じです。

    ウィンドウ上にHIViewベースでのコントロールを描画する場合には、そのウィンドウが
    コンポジット(合成)モードである必要があります。そうでないと、すべてのコントロー
    ルに対して旧Control Managerベースの描画が採用されます。コンポジットウィンドウ
    でのViewの描画順序は、同じ階層での順序情報により決まり、描画時のα値(透明度)
    も正しく認識されます。その結果として、描画におけるコントロールの重なり具合も美し
    く再現されます。コンポジットウィンドウにおけるViewの再描画については、Carbon
    Event Handlerを用意し、イベントクラスがkEventClassControlで、そのイベント種類
    がkEventControlDrawのCarbon Eventを受け取った時に実行するようにします。

    旧WaitNextEvent()ループによるアップデートイベント時の再描画や、Carbon Eventの
    EventWindowUpdateやkEventWindowDrawを受け取ったことを認知しての再描画は
    行えませんので注意してください。なぜなら、コンポジットウィンドウでは、そうしたイ
    ベントは発生しないからです。もし直ちにViewの再描画を行いたい場合には、目的に応
    じたAPIを用いて「再描画領域」を記録させます。例えば、HIViewSetNeedsDisplay()や
    HIViewSetNeedsDisplayInRegion()などです。また、Mac OS X 10.4以降では
    HIViewSetNeedsDisplayInRect()やHIViewSetNeedsDisplayInShape()なども利用する
    ことができます。この時の再描画は、RunApplicationEventLoop()やWaitNextEvent()
    で実行されているイベントループの処理タイミングに依存します。もし、イベントループ
    に依存せず、直ちにViewの再描画を行いたい場合には、Mac OS X 10.3以降で利用でき
    るHIViewRender()を用います。

    OnPaint on wxWidgets/wxPython その4

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    from gtk src/gtk/window.cpp
    こっちはGTKのRefreshとUpdate。あまりひねりはなさそう。

    void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground),
    const wxRect *rect)
    {
    if (!m_widget)
    return;
    if (!m_widget->window)
    return;

    if (m_wxwindow)
    {
    if (m_wxwindow->window == NULL) return;

    GdkRectangle gdk_rect,
    *p;
    if (rect)
    {
    gdk_rect.x = rect->x;
    gdk_rect.y = rect->y;
    gdk_rect.width = rect->width;
    gdk_rect.height = rect->height;
    if (GetLayoutDirection() == wxLayout_RightToLeft)
    gdk_rect.x = GetClientSize().x - gdk_rect.x - gdk_rect.width;

    p = &gdk_rect;
    }
    else // invalidate everything
    {
    p = NULL;
    }

    gdk_window_invalidate_rect(m_wxwindow->window, p, true);
    }
    }

    void wxWindowGTK::Update()
    {
    GtkUpdate();

    // when we call Update() we really want to update the window immediately on
    // screen, even if it means flushing the entire queue and hence slowing down
    // everything -- but it should still be done, it's just that Update() should
    // be called very rarely
    gdk_flush();
    }

    void wxWindowGTK::GtkUpdate()
    {
    if (m_wxwindow && m_wxwindow->window)
    gdk_window_process_updates(m_wxwindow->window, false);
    if (m_widget && m_widget->window && (m_wxwindow != m_widget))
    gdk_window_process_updates( m_widget->window, FALSE );

    // for consistency with other platforms (and also because it's convenient
    // to be able to update an entire TLW by calling Update() only once), we
    // should also update all our children here
    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
    node;
    node = node->GetNext() )
    {
    node->GetData()->GtkUpdate();
    }
    }


    んで、macはどうかというと、ちょっと?なかんじ。HIXXってなんぞや?
    src/mac/window.cpp

    /*
    * Rect is given in client coordinates, for further reading, read wxTopLevelWindowMac::InvalidateRect
    * we always intersect with the entire window, not only with the client area
    */

    void wxWindowMac::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
    {
    if ( m_peer == NULL )
    return ;

    if ( !IsShownOnScreen() )
    return ;

    if ( rect )
    {
    Rect r ;

    wxMacRectToNative( rect , &r ) ;
    m_peer->SetNeedsDisplay( &r ) ;
    }
    else
    {
    m_peer->SetNeedsDisplay() ;
    }
    }

    SetNeedsDisplayはなにものかというと、src/mac/carbon/utils.cppのなかにいらっしゃって、

    void wxMacControl::SetNeedsDisplay( RgnHandle where )
    {
    if ( !IsVisible() )
    return;

    HIViewSetNeedsDisplayInRegion( m_controlRef , where , true );
    }


    ふたたびsrc/mac/window.cppのなかにもどってUpdateがどうなっているかというと、

    void wxWindowMac::Update()
    {
    wxNonOwnedWindow* top = MacGetTopLevelWindow();
    if (top)
    top->MacPerformUpdates() ;
    }



    src/mac/carbon/nonownedwnd.cpp

    void wxNonOwnedWindow::MacPerformUpdates()
    {
    // for composited windows this also triggers a redraw of all
    // invalid views in the window
    HIWindowFlush((WindowRef) m_macWindow) ;
    }

    OnPaint on wxWidgets/wxPython その3 GTK編

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    その2ではwxMacを扱ったが、こんどはGTK.
    macでの調査結果をそのまま応用できるので瞬殺ですな。

  • void wxWindowGTK::GtkSendPaintEvents() @ src/gtk/window.cpp

  • で、上記のコードを呼んでいるのは

    extern "C" {
    static gboolean
    gtk_window_expose_callback( GtkWidget*,
    GdkEventExpose *gdk_event,
    wxWindow *win )

    あとはGdkEventExposeが何であるかを調べればよさげ。

  • struct GdkEventExpose

    ウィンドウ全体またはその一部が表示状態 (visible) になり再描画の必要性が発生した際に生成されます。

    GdkEventType type イベントの種類 (GDK_EXPOSE)
    GdkWindow *window イベントを受け取るウィンドウ
    gint8 send_event イベントが正しく (例えば XSendEvent などを利用して) 送信された場合は TRUE
    GdkRectangle area 再描画の必要がある領域
    gint count 連続して GDK_EXPOSE イベントが発生した際の回数で、これは "exposure compression" のためだけに使用する (つまり全ての連続した GDK_EXPOSE イベントを一回で取り扱う場合に GDK がいくつかの exposure compression を実行するので、通常は必要ない)

    だとさ。
  • 2008年4月22日火曜日

    OnPaint on wxWidgets/wxPython その2

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    適当なページを見つけることに失敗したので、sourceを読むことにした。
    ぜんぜんとり終わらないw。

    documentのなかにあるページでは足りないのですよ。

    あ、ちなみに環境はこうです。

    wxMac on Mac OS X 10.5.2

    wx.PlatfromInfo =
    ('__WXMAC__',
    'wxMac',
    'unicode',
    'wx-assertions-on',
    'SWIG-1.3.29',
    'mac-cg',
    'mac-native-tb')
    Yakumo:~ nori$ uname -a
    Darwin Yakumo 9.2.2 Darwin Kernel Version 9.2.2: Tue Mar 4 21:17:34 PST 2008; root:xnu-1228.4.31~1/RELEASE_I386 i386


    wxGTK on Centos5.1

    wx.PlatfromInfo
    ('__WXGTK__', 'wxGTK', 'unicode', 'gtk2', 'wx-assertions-on', 'SWIG-1.3.29')
    [nori@Asama]~% uname -a
    Linux Asama 2.6.18-53.1.4-eth-3w-dvd #5 SMP Fri Dec 21 19:15:40 JST 2007 x86_64 x86_64 x86_64 GNU/Linux


    どう調べたか?
  • wxEventが interface/event.hで宣言定義されている。
  • wxPaintEvent, wxEraseEventが/src/common/event.cppで出現
  • src/mac/event.cppでmacのevent loopがwxのevent loopにmapされている。
    appleのドキュメント、Carbonのevent loopがRunApplicationEventLoopをgoogleすると引っかかる。

    で、CarbonのAPIを呼ぶこととwxEventLoopActivatorをスタック上に生成する以外はwxGUIEventLoop::Run()の中でやっていないので、wxEventLoopActivatorを探してみたがいまいち役に立たず。

  • void wxWindowMac::OnEraseBackground(wxEraseEvent& event) @ src/mac/carbon/window.cppを見るとMacのwindowとwxのwindowでeventのmappingをしているように読める。気づいてしまえばどうということはない。

  • bool wxWindowMac::MacDoRedraw( void* updatergnr , long time ) @ src/mac/carbon/window.cpp
    たぶんこれが本質。MacのDoRedrawはなにものか?

  • void wxWindowMac::OnPaint( wxPaintEvent & WXUNUSED(event) ) @ src/mac/carbon/window.cpp
    PlatformのPaintHanderを呼び出すコード。OnPaintがOverrideされなかった場合に実行される。あまり重要でない。

  • static pascal OSStatus wxMacWindowControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) @ src/mac/carbon/window.cpp
    mappingをしている本体。case kEventControlDrawの部分を読み解けばCarbon Macのdraw要求がwxのPaintにどう変換されるわかるはず。この関数はDoRedrawをgrepして発見。
    あとはCarbonのAPIリファレンスかなんかを拾ってきてkEventControlDrawが飛んでくる条件がわかればよさげ。

    Carbon Event Manager Reference @ developer.apple.com、これですな。


    kEventControlDraw

    Sent when your control should draw itself. The event can optionally contain parameters indicating which port to draw into and which part to constrain drawing to. (Mac OS X only)

    Available in Mac OS X v10.0 and later.

    Declared in CarbonEvents.h

    だそうだ。
    HIViewも理解しないといけない。まあタスクレベルに落ちたのでハッピーですね。GTKでも同じ作業すれば終わり。まあソースでの位置を探すのは簡単だが。
  • 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さん。



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

    2008年4月21日月曜日

    wx.Image on Mac OS X

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    先日書いたとおり、PILの使用を避けたかったのでwx.Imageを使うようにしたが、なぜか画像が表示されない。splashは表示されているのでScaleもしくはmirrorが動いていない可能性が高い。

    とりあえずバージョンをチェック。
    on Mac OS X
    wx.__version__
    2.8.4.0

    on CentOS 5.1
    wx.__version__
    2.8.7.1

    う~~む、これが原因か?
    wxPythonのサイトを見ると2.8.7.1のMacOSX向けのバイナリが存在したのでインストールしてみた。
    あれ?元から入っているwxPythonに上書きインストールできない・・・・。

    よくないことだと知りつつもmacportsから入れてみる。あーあ。

    コーヒー豆を挽きながらrecent changeをチェック。ぱっと見、該当はなさそうだ。

    2008年4月19日土曜日

    PIL on MacOSX 10.5

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    いろいろしらべたがうまい方法がない。
    10.4ならbinary(dmg)が存在するのだが。

    macosの上にcentos 5上でかいたコードで、wxPythonじゃなくてPILでイメージをいじってからwxPythonのwindowにjpeg imageを貼ろうとしたら何も表示されない。Centos 5の上だと動くコードなのに。・・・PILがうごいてないじゃんということでこのような調べモノになっているのですよ。

    え~~と話をまとめると
  • PILはijg jpegに依存している。
  • ijgのサイトで手に入るパッケージはパッケージングが古い!
  • 解決策
  • srcからがんばる。参考ページ。。。めんどうなので後回し・・・。
  • finkする。→fink install libjepgでインストールはされるように見えるが・・・。build後のselftestが通らない。
  • macportsする。→同上。ports install jpegでいいはずだが・・・。
    finkもmacportsもPILからみえないらしい。

    あ~~これをpackageして配布するとなると骨折りだなぁ・・・。PILに依存しないように書き直そうかしら。

    だれかMacOSXのディレクトリ構成について解説してください。マジわかりません。
  • FIBS Client

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク


    2008年4月16日水曜日

    おもったこと。

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    関数プログラミングのアプローチ @ lethevert is a programmer

    配列・STMのくだりを見ているときに思ったがSQLが配列・アドレスを追放しようとしたことを思い出した。なんだろう、並の言語が、後から解決しようとしている問題を先に解決する代わりに、並みの言語が最初にする課題を、よい言語は制限された手段で解決することで、自由を手に入れようとするトレードオフが見える。言語を設計するっていうときのトレードオフ。

    guidoがpythonでした、「indentが文法の一部」というcoding styleに関する判断はすばらしかった。使えるコーディングスタイルは制限されたが、破滅的なコーディングスタイルを撃滅できたし、コーディングスタイルに関する宗教論争にさかれるエネルギーを節約できて、ライブラリは誰でも読めるものになったことで、創造的に時間を使う自由を得た。

    ***

    phpヤバス
  • 素晴らしき自動的な世界~或いは「型のない」世界~ - がるの健忘録
  • 桁あふれに伴う仕様 - がるの健忘録
    全力で逃げよう。phpをつかった何かは使わないようにしよう。危険性は、読みにくいコードをかけるperlの比ではない。しかしなんであとからあとから人を陥れるための言語が出てくるのかね?

    真新しい紙を触っていると手を切ることがあるが、ここまでくると割れたガラスの破片の上で裸でのた打ち回っているような感じだな。

    おそらく社会における知識の「劣化コピー現象」だな。わけもわからずまねしたが、わけわからず不完全にまねしたので、出来上がったものはひどいものだ。

    ****

    コードは短いほどいい。Forthがいいといってるのではない。そういう議論じゃなくて

    svgfigの開発史をみてみると

    Realizing that simplicity is key, I re-wrote everything again, relying on SVG to encode the graphics (4000 lines). In the process of development, this SVG-based version became a little messy and overstructured, so I purified it, maintaining functionality. The present version, renamed SVGFig, is only 2300 lines.

    とのこと。

    シンプルに短くかくためには、同じことを2書くようなことはできない。字面での圧縮ではなく概念での圧縮が必要になる。概念での圧縮を無理なくするためには、概念の階層が必要で、階層は仕様(抽象化)・実装のペアの積み重ねになる。また操作自体への操作が必要になる。
    用途に適したミニ言語をつくる作業だな。すくなくとも特定のジャンルではそれ専用の「語彙」がとくに発達している。たとえば刀鍛冶は加熱された鉄の色を表現する語彙が豊富だ。ということは、プログラミング言語にはプログラマが抽象度の高い記述に必要な語彙を作り出す作業をうまく助けることができる必要がある。言い換えると「頭のいい人は、難しい概念も簡単に説明できるはずだ」というようなことになってくる。よい実装は、必然的に平明になるはずだ。

    これを何とかするには、lispのマクロが特にそうだろうが、一般に言うと名前空間のようなものとと関数を引数に取れる関数の機構が必要なのではないかと思う。

    変数名は、計算の立場からは自由に置き換えられる。(α-変換)人間は名前に現実的世界の意味を見出す。(Obfuscated code、記憶という環境にbindされるともいえる。記憶にないと、外のスコープであるgoogleに聞きに行く、ちなみに情報理論じゃなくて計算論ね。)

    プログラムとは機能をもった文章なので、作成過程で推敲が必須で、それを機能面でテストしながら進めていきましょうよってのがunittestありのtest drivenで、そのような推敲をリファクタリングと呼んでいると思っているのだが。

    常に一般化される方向に書き直されるかというとそうでもなくて、いいたいことがあって文章を書くわけだから、必要以上の一般論に触れる必要もないわけで、これはコードに関しても同じで、必要以上の一般化も不要である。(YAGNI(You Aren't Going to Need It=それは将来必要にならない)の原則)

    RibyOnRails(もう古いか?)でconventionのほうがconfigurationにまさるといっていたが、conventionとかconfigurationって外部の値をプログラムに取り込む、プログラムの変数に値(意味)を束縛することにほかならないからなぁ。
  • 2008年4月8日火曜日

    Splash

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    Splash is not frame window. It needs parent frame, and IT CLOSES PARENT WINDOW on close.


    import wx

    app = wx.PySimpleApp()
    frame = wx.Frame(None, size=(1200, 1600))

    image = wx.Bitmap('splash.jpg', wx.BITMAP_TYPE_JPEG)
    splash_frame = wx.Frame(None,
    size=image.GetSize(),
    style=wx.NO_BORDER
    )
    splash = wx.SplashScreenWindow(parent=splash_frame,
    bitmap=image, id=-1,
    size=image.GetSize(),
    pos=wx.DefaultPosition)
    frame.Show()
    splash_frame.Show()
    splash_frame.Centre()
    app.MainLoop()

    2008年4月7日月曜日

    wxPython GetMDIParentFrame

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    Continued from Previous Post:

    class MyChildFrame(wx.aui.AuiMDIChildFrame):
    def __init__(self, parent, count):
    wx.aui.AuiMDIChildFrame.__init__(self, parent, -1, title='Child %d'%count)
    def GetMDIParentFrame(self):
    # FIXME
    # wx.aui.AuiMDIChildFrame::GetParent returns
    # AuiMDIChildFrame not MyChildFrame
    return self.GetParent().GetParent()

    I don't like this fix though, I do not have an alternative idea.

    If it is in C++, I cast a MyChildFrame instance into an AuiMDIChildFrame instance in the GetMDIParentFrame method.

    MDI in wxPython

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    やってしまった。

    ChildFrameでGetParentしてもParentFrameが返ってこない(AuiMDIClientWindowが返ってくる)。GetMDIParentFrameを使う必要がある。冷静になれば確かにそうだ。だっていろいろ装飾品がついているじゃない。GetParent().GetParent()してもParentFrameが手に入るが、このやり方は明らかに正しくないだろう。

    追記:
    がーーー。親window継承すると、子windowのGetMDIParentFrameで返るwindowが、継承して作ったwinodowではなくBase Classのwindow AuiMDIParentWindowだ。


    EVT_CLOSEのなかでVeto可能な場合は、progress dialogを表示して処理の完了を待つ。


    Vetoの仕方。



    なにしようとしていたかって?MDIのclient frameをcloseするときにちょっとすることがあってそのためにユーザを待たせたいのだ。

    2008年4月1日火曜日

    2K over

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    2000行を超えたようだ。2/27開始で今日までだから5週間?週400行か・・・たいそう不満だ。まあ、wxPythonを勉強しながらとはいえ・・・。

    体感的には1つのファイルが200Line以上になってくると見通しが悪くなってくるようだ。vimで4つ同時にfileあけて作業しているがなんだか足りない気がする。VNCのせいで制限されてるし。VNCのサーバをもうひとつ立ち上げてしまうか?かなり駄目な解決策なきがする。。。

    手元のディスプレイ2枚を有効に使いたいだけなのだが・・・。一方にアプリの実行画面、他方にエディタでも可。


    [nori@Asama]~/Desktop/work/wxpygammon% find . | grep .py$ | xargs wc
    243 549 5805 ./src/model.py
    58 109 1624 ./src/adhoc.py
    88 191 2433 ./src/main.py
    55 144 1456 ./src/tricks.py
    177 399 5637 ./src/lobby.py
    142 324 3714 ./src/table.py
    83 199 2644 ./src/passworddlg.py
    41 75 889 ./src/test_model.py
    67 154 1838 ./src/injection.py
    152 328 4143 ./src/chat.py
    32 90 1012 ./src/debugging.py
    61 141 1791 ./src/streamviewer.py
    73 175 1534 ./src/bglib/model.py
    274 572 6975 ./src/bglib/protocol/session.py
    26 54 495 ./src/bglib/protocol/fibshelper.py
    6 18 133 ./src/bglib/protocol/__init__.py
    107 257 2450 ./src/bglib/image.py
    137 328 3549 ./src/bglib/encoding/FIBS.py
    108 246 2422 ./src/bglib/encoding/gnubg.py
    345 951 7730 ./src/bglib/encoding/base.py
    8 18 135 ./src/bglib/encoding/__init__.py
    50 120 1108 ./src/bglib/encoding/urlsafe.py
    6 18 133 ./src/bglib/__init__.py
    28 55 721 ./src/bglib/helper.py
    4 7 62 ./src/test.py
    77 210 2386 ./src/command.py
    30 61 664 ./setup.py
    2478 5793 63483 total

    maradns

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    maradnsを使っているが、しばらくversion upされず放置していたので入れ替え。yum経由じゃないやつは定期的にversion upする方法を考えておかないとなぁ。

    rpmbuildしてうまくいかない。
    オリジナルでは%configがかけているようだ

    [nori@Asama]~/Desktop/work/packaging/maradns/maradns-1.3.07.08/build% diff -u maradns-1.3.07.08.spec.orig maradns-1.3.07.08.spec
    --- maradns-1.3.07.08.spec.orig 2008-04-01 09:56:55.000000000 +0900
    +++ maradns-1.3.07.08.spec 2008-04-01 09:58:04.000000000 +0900
    @@ -74,6 +74,9 @@
    %config /etc/maradns/db.example.net
    %config /etc/rc.d/init.d/maradns
    %config /etc/rc.d/init.d/maradns.zoneserver
    +%config /etc/rc.d/rc3.d/K60maradns.zoneserver
    +%config /etc/rc.d/rc5.d/K60maradns.zoneserver
    +

    %post
    CHKCONFIGPARM="--add maradns"


    私のpackageっしたものがほしいという御奇特なかたはこちらから。