高橋メソッドマシーンぽいもの

新人研修のガイダンス用資料をつくらにゃ〜とあせりながらも六本木で働いていた元社長のアメブロを読んでたら、高橋メソッドの話が出てきて、そういやこんなのがあったな〜、これ使えばよくね?って思ったわけです。

で、高橋メソッドマシーンなるものの存在を知って、これオフラインで使えんかなぁと思ったのですがどうにもよく分からず、wxPython で自作してみました。
xrc のファイル(resource.xrc)

<?xml version="1.0" ?>
<resource>
  <object class="wxFrame" name="MainFrame">
    <title>Drawing</title>
    <centered>1</centered>
    <bg>#FFFFFF</bg>
    <font>
      <size>72</size>
      <style>normal</style>
      <weight>bold</weight>
      <underlined>0</underlined>
      <family>swiss</family>
      <face>MS ゴシック</face>
      <encoding>WINDOWS-1252</encoding>
    </font>
    <style>wxNO_BORDER</style>
  </object>
</resource>

python スクリプト(tmethod.py)

# encoding: utf-8
import wx
import wx_utils
from wx_utils import XRC,XRCID,XRCCTRL
import re
from optparse import OptionParser

USAGE=u"""高橋メソッド
マシーンぽいもの
on wxPython
 
SPACE で次へ

起動方法

>tmethod.py ファイル名

ファイル
の中身

テキスト
オンリー

空行の
改行で
ページ切替

文字コードは
UTF-8 のみ(?)

起動
オプション

-e 文字コード

ファイルの
文字コード
指定

UTF-8
以外もOK

-c

ページ
カウント
表示

-s

自動「ご清聴
ありがとう
ございました。」

操作方法

SPACE
で次へ

BackSpace
で前へ

Esc
で終了
"""

class MainFrame(wx.Frame):
    binder=wx_utils.bind_manager()
    # 初期化
    def __init__(self,parent=None,text=USAGE,count=False):
        pre=wx.PreFrame()
        XRC().LoadOnFrame(pre,parent,'MainFrame')
        self.PostCreate(pre)
        self.binder.bindall(self)
        # 全画面表示
        size=wx.ScreenDC().GetSize()
        self.SetSize(size)
        self.SetPosition(wx.Point(0,0))
        #print size
        # キーイベント処理テーブル
        self.key_handler = {
            wx.WXK_ESCAPE : self.OnKey_Escape,
            wx.WXK_SPACE : self.OnKey_Space,
            wx.WXK_BACK : self.OnKey_Back,
        }
        # 表示する文字列
        r_ret = re.compile(ur'\n\n+')
        if type(text)==str:
            text=unicode(text,"utf-8")
        self.text=[[y for y in x.split(u"\n")] for x in r_ret.split(text)]
        for text in self.text:
            if text[-1]=="":
                text.pop()
        self.current_idx=0
        # フォント
        self.font = wx.Font(1,wx.DEFAULT,wx.NORMAL,wx.BOLD)
        # マージン
        self.margin = wx.Size(20, 20)
        # ページカウント
        self.pagecount = count
    # 描画イベントハンドラ
    @binder(wx.EVT_PAINT)
    def OnPaint(self, evt):
        # デバイスコンテキストの準備
        dc = wx.BufferedPaintDC(self)
        dc.SetBackground(wx.WHITE_BRUSH)
        dc.Clear()
        dc.SetPen(wx.BLACK_PEN)
        # マージン
        ox = self.margin.GetWidth()
        oy = self.margin.GetHeight()
        # 画面サイズ取得
        size = dc.GetSize()
        sw = size.GetWidth()
        sh = size.GetHeight()
        # 描画範囲計算
        cw = sw - ox * 2
        ch = sh - oy * 2
        text = self.text[self.current_idx]
        # フォントサイズの決定
        # 72 ポイントの場合のサイズを算出し
        self.font.SetPointSize(72)
        dc.SetFont(self.font)
        pw = 0
        ph = 0
        for t in text:
            w, h = dc.GetTextExtent(t)
            if pw < w:
                pw = w
            ph += h
        # 必要な範囲と最大範囲の比率から縦横のポイントサイズを算出し
        pw = 72 * cw / pw
        ph = 72 * ch / ph
        # 小さいほうをフォントのポイントサイズとする
        ptsize = min(pw, ph)
        # 新たなポイントサイズのフォントを設定
        self.font.SetPointSize(ptsize)
        dc.SetFont(self.font)
        # 描画領域のサイズを確定し、描画位置の決定
        pw = 0
        ph = 0
        for t in text:
            w, h = dc.GetTextExtent(t)
            if pw < w:
                pw = w
            ph += h
        py = (sh - ph) / 2
        # 表示
        for t in text:
            w,h = dc.GetTextExtent(t)
            dc.DrawText(t, (sw-w)/2, py)
            py += h
        # ページカウント
        if self.pagecount:
            self.font.SetPointSize(20)
            dc.SetFont(self.font)
            text = u"%d/%d"%(self.current_idx+1, len(self.text))
            w, h = dc.GetTextExtent(text)
            dc.DrawText(text, sw-ox-w, sh-oy-h)
    # キーの処理
    @binder(wx.EVT_KEY_UP)
    def OnKeyUp(self, evt):
        code = evt.GetKeyCode()
        # テーブルにキーコードがあれば処理する
        if code in self.key_handler:
            self.key_handler[code](evt)
    # ESC で終了
    def OnKey_Escape(self, evt):
        self.Close()
    # スペースで進む
    def OnKey_Space(self, evt):
        if self.current_idx<len(self.text)-1:
            self.current_idx += 1
            self.Refresh(False)
    # BackSpace で戻る
    def OnKey_Back(self, evt):
        if self.current_idx>0:
            self.current_idx -= 1
            self.Refresh(False)

def main():
    from sys import argv
    import sys
    # 引数解析
    parser = OptionParser()
    parser.add_option('-e','--encoding',dest='encoding',default='utf-8',
                      type='string',
                      help=u"入力ファイルのエンコーディング指定"
                     )
    parser.add_option('-d','--debug',dest='debugmode',default=False,
                      action='store_true',
                      help=u"デバッグモード"
                     )
    parser.add_option('-c','--counter',dest='pagecount',default=False,
                      action='store_true',
                      help=u"ページカウント表示"
                     )
    parser.add_option('-s','--auto-thanks',dest='autothanks',default=False,
                      action='store_true',
                      help=u"自動「ご清聴ありがとうございました」"
                     )
    (options, args) = parser.parse_args(argv[1:])
    # 入力文字列の準備
    if len(args)>0:
        text=""
        for fname in args:
            text+=unicode(open(fname).read(), options.encoding)+u"\n\n"
        text=text.strip()
    else:
        text=USAGE
    # 自動「ご清聴ありがとうございました」機能
    if options.autothanks:
        text += u"\n\nご清聴\nありがとう\nございました。"
    # デバッグモード
    stdout=sys.stdout
    class X(object):
        def write(self, *args, **kwargs):
            pass
    if not options.debugmode:
        sys.stdout = X()

    app = wx.App()                               # アプリケーションのインスタンス作成
    wx_utils.XrcInit()                           # リソースの初期化
    frame = MainFrame(text=text,count=options.pagecount)                 # メインフレーム作成
    app.SetTopWindow(frame)                      # アプリケーションのウィンドウ階層のトップに据える
    frame.Show(True)                             # メインフレームを表示
    app.MainLoop()                               # メインフレーム終了待ち

if __name__=="__main__":
    main()

wx_utils.pyのお世話になってます。結構さくっとできました。wxPython とwx_utils.py ちょうべんり!あとフォントの取り扱いの勉強になりました。72ポイントが1インチで1インチは96ピクセル*1!とか。

全画面表示オンリーでフォントサイズは自動調整で最大化してます。そして聴衆に先の見えない絶望感を与えないためのページカウンタ付き!引数なしの単発起動で使い方が表示されます。これは内蔵テキストによりデモをかねています。絵を表示したりできるように…とか一瞬考えましたがごてごてつけ始めると高橋メソッドのよさが失われるな、と思ってやめました。


これでしんじんけんしゅうがいだんすはばっちりだ!!(原稿さえ書けば)

*1:dpi は設定による