wxPythonのDEMOはあてにならない


wxPythonのサンプルのwx.lib.editor.Editorはwx.ScrolledWindowを継承して作られている。

wx.ScrolledWindowは、wx.Panelのサブクラスで、

右と下にスクロールバーが表示されるので、子コンポーネントをスクロール出来る。

(wx.Panelもスクロールバーを表示できるが、wx.ScrollBarの方がやりやすい)


自作のテキストエディタもwx.ScrolledWindowを継承することにする。

wx.ScrolledWindowは一見単独では使わなそうなので、

これを継承してテキスト入力欄を作るのは気持ち悪いが。

wx.lib.editor.Editorのソースから、行のスクロールの部分だけを抜き出すことにする。

小1時間ほど格闘。

理解できなかった。



wx.lib.editor.Editorでは、EVT_SCROLLWIN_LINEUP、EVT_SCROLLWIN_LINEDOWN、
EVT_SCROLLWIN_PAGEDOWN等で場合わけをしたり、何かゴチャゴチャやっているが、
下のように、とにかくスクロールバーが変化したら再描画すれば良い様に思える。

import wx
from itertools import islice
import string
class EditCtrl(wx.ScrolledWindow):
    def __init__(self, parent):
        wx.ScrolledWindow.__init__(self, parent, -1)
        self.lines = [c.join(str(i) for i in xrange(100)) for c in string.ascii_lowercase]
        self.font = wx.Font(pointSize=25, 
            family=wx.FONTFAMILY_TELETYPE,
            style =wx.NORMAL,
            weight=wx.FONTWEIGHT_NORMAL,
            faceName=u"MSゴシック"
        )
        dc = wx.ClientDC(self)
        dc.SetFont(self.font)
        self.lineHeight = dc.GetCharHeight()
        
        self.SetScrollbars(0, self.lineHeight, 0, len(self.lines))
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
    
    def OnScroll(self, evt):
        self.Refresh()
        evt.Skip()
    
    def OnPaint(self, event):
        cw, ch = self.GetClientSize()
        
        buf = wx.EmptyBitmap(cw, ch)
        dc = wx.BufferedPaintDC(self, buf)
        dc.SetFont(self.font)
        dc.SetBackgroundMode(wx.SOLID)
        dc.Clear()
        
        ypos = self.GetScrollPos(wx.VERTICAL)
        nlines = ch // self.lineHeight
        if ch % self.lineHeight:
            nlines += 1
        for i, line in islice(enumerate(self.lines), ypos, ypos + nlines):
            dc.DrawText(line, 0, (i - ypos)*self.lineHeight)

def main():
    app = wx.PySimpleApp()
    f = wx.Frame(None, -1)
    e = EditCtrl(f)
    f.Show()
    app.MainLoop()
    
if __name__ == "__main__":
    main()
広告を非表示にする