wxPython wx.Timerを使ってグラフィック描画してみる

wx.Timerを使ってカウントアップタイマーを表示し、カウントアップに応じてグラフィックの棒グラフを描画してみる。どこかに埋もれて無くなってしまう前にメモしておく。

参考にしたリンク

ウィンドウに、1から999までのカウントアップ値を表示させ、カウントの値に応じて1,10,100の位の棒グラフを描画する。最初はwx.ClientDCを使って描画し、次にwx.BufferedDCを使って、フリッカーノイズを対策してみる。

#!/usr/bin/env python
#coding:utf-8

import wx

class MyWindow(wx.Frame):
    def __init__(self, parent=None, id=-1, title=None):
        wx.Frame.__init__(self, parent, id, title)
        self.panel = wx.Panel(self, size=(300, 200))
        self.panel.SetBackgroundColour('WHITE')
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer)
        self.Fit()
        self.counter = 0
        self.timer.Start(50)

    def OnTimer(self, event):
        self.counter += 1
        if self.counter == 999:
            self.timer.Stop()
        pos_x = 30
        pos_cnt_y = 20
        g_height = 40
        g_width  = 28
        pos_g1_y = pos_cnt_y + g_height
        pos_g2_y = pos_g1_y + g_height
        pos_g3_y = pos_g2_y + g_height
        cnt_str = "%03d" % self.counter
        g_width1 = int(cnt_str[2]) * g_width
        g_width2 = int(cnt_str[1]) * g_width
        g_width3 = int(cnt_str[0]) * g_width
        dc = wx.ClientDC(self.panel)
        dc.Clear()
        dc.SetTextForeground('green')
        font = wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
        dc.SetFont(font)
        dc.DrawText(cnt_str, pos_x, pos_cnt_y)
        dc.SetPen(wx.Pen('blue'))
        dc.SetBrush(wx.Brush('blue'))
        dc.DrawRectangle(pos_x, pos_g1_y, g_width1, g_height)
        dc.SetPen(wx.Pen('red'))
        dc.SetBrush(wx.Brush('red'))
        dc.DrawRectangle(pos_x, pos_g2_y, g_width2, g_height)
        dc.SetPen(wx.Pen('yellow'))
        dc.SetBrush(wx.Brush('yellow'))
        dc.DrawRectangle(pos_x, pos_g3_y, g_width3, g_height)

if __name__ == '__main__':
    app = wx.PySimpleApp()
    w = MyWindow(title='wxgr-timer1')
    w.Center()
    w.Show()
    app.MainLoop()

メモ

  • テキストの色を変更するにはSetTextForegroundメソッドをコールする。
  • テキストの文字サイズを変更するには、サイズを指定してwx.Fontでfontオブジェクトを作成し、デバイスコンテキストオブジェクトのSetFontメソッドをコールする。
  • テキストを表示するにはDrawTextメソッドをコールする。

実行すると

フリッカーノイズ対策した描画

#!/usr/bin/env python
#coding:utf-8

import wx

class MyWindow(wx.Frame):
    def __init__(self, parent=None, id=-1, title=None):
        wx.Frame.__init__(self, parent, id, title)
        self.panel = wx.Panel(self, size=(300, 200))
        self.panel.SetBackgroundColour('WHITE')
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer)
        self.Fit()
        self.counter = 0
        self.timer.Start(50)

    def OnTimer(self, event):
        self.counter += 1
        if self.counter == 999:
            self.timer.Stop()
        pos_x = 30
        pos_cnt_y = 20
        g_height = 40
        g_width  = 28
        pos_g1_y = pos_cnt_y + g_height
        pos_g2_y = pos_g1_y + g_height
        pos_g3_y = pos_g2_y + g_height
        cnt_str = "%03d" % self.counter
        g_width1 = int(cnt_str[2]) * g_width
        g_width2 = int(cnt_str[1]) * g_width
        g_width3 = int(cnt_str[0]) * g_width
        cdc = wx.ClientDC(self.panel)
        bmp_w, bmp_h = self.panel.GetSize()
        bmp = wx.EmptyBitmap(bmp_w, bmp_h)
        bdc = wx.BufferedDC(cdc, bmp)
        bdc.Clear()
        bdc.SetTextForeground('green')
        font = wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
        bdc.SetFont(font)
        bdc.DrawText(cnt_str, pos_x, pos_cnt_y)
        bdc.SetPen(wx.Pen('blue'))
        bdc.SetBrush(wx.Brush('blue'))
        bdc.DrawRectangle(pos_x, pos_g1_y, g_width1, g_height)
        bdc.SetPen(wx.Pen('red'))
        bdc.SetBrush(wx.Brush('red'))
        bdc.DrawRectangle(pos_x, pos_g2_y, g_width2, g_height)
        bdc.SetPen(wx.Pen('yellow'))
        bdc.SetBrush(wx.Brush('yellow'))
        bdc.DrawRectangle(pos_x, pos_g3_y, g_width3, g_height)
        cdc.DrawBitmap(bmp,0,0)

if __name__ == '__main__':
    app = wx.PySimpleApp()
    w = MyWindow(title='wxgr-timer2(no flicker)')
    w.Center()
    w.Show()
    app.MainLoop()

メモ

  • フリッカーノイズを発生させないためにwx.BufferedDCを使う
    • まず、wx.ClientDCオブジェクトを作成する。
    • 次に、wx.EmptyBitmapでビットマップバッファーを作成し、これを指定したwx.BufferedDCオブジェクトを作成する。
    • wx.BufferedDCオブジェクトに対してグラフィックを描画する。
    • ClientDCオブジェクトのDrawBitmapメソッドをコールして、描画済みのビットマップを表示させる。いちいち描画しないのでフリッカーノイズは発生しない。

実行すると