ふにゃるんv2

もとは、http://d.hatena.ne.jp/Wacky/

タイミングチャートをIronPythonとExcelを使って書いてみる

いつもの如く、ネットをふらふらしていたら、以下のBlogネタを見つけました。

そっか〜、Excelでもタイミングチャート書けるんだぁ…。


…ちと勉強用にIronPythonを使って、Excelにタイミングチャートを書くツールを作ってみっかな?

という訳で

作ってみました。
名前は、t_cha(T-茶)って命名してみました。(茶に意味は無い)

つまりは、↓こんな事ができます。
t_cha1
t_cha1 posted by (C)wacky


使い方は、以下のステップを踏みます。

  1. テキスト形式で、タイミングチャートデータを作ります
    タイミングチャートデータの書式は、タイミングチャート清書ツール:原稿の作り方の一部をサポートしています(まぁ、後述するソースを見れば一目瞭然ですね)
  2. "t_cha.py"って言う、IronPythonプログラムを動かします
    第1引数に1.のテキストファイルを与え、第2引数には、出力したいExcelファイル名を与えます
  3. "t_cha.py"が動いて、テキストファイルを読み込んでExcelの上にタイミングチャート図を作ります
    その後、Excelファイルに出力して終了します

ふむ、結構簡単に作れるもんですね。

t_chaを使う前の、お膳立て

今回のIronPythonツールは、Excelを必要とします。
という訳で、以下のようにして、COMタイプライブラリをIronPythonで読める形式のライブラリに変換してください。
(実行例は、Excel2000ですが、.olbファイルさえ合わせれば、何でもOKだと思います)

C:\Program Files\Microsoft Office\Office>tlbimp "C:\Program Files\Microsoft Offi
ce\Office\EXCEL9.OLB" /out:excel9.dll
Microsoft (R) .NET Framework Type Library to Assembly Converter 2.0.50727.42
Copyright (C) Microsoft Corporation.  All rights reserved.

Type library imported to C:\Program Files\Microsoft Office\Office\excel9.dll

実行すると、以下の3ファイルが自動生成されます。

  • excel9.dll
  • office.dll
  • vbide.dll

出来たら、t_chaを実行するフォルダにコピーして下さい。

t_chaのソースコード

次に、t_chaのソースを以下に示します。

ファイル名は、"t_cha.py"とでもして下さい。

#!/usr/bin/env python
# coding: cp932
"""
参考にしたリンク。

-shirouの現実touhi[wp] ≫ タイムチャート作成ソフト(他
 http://www.shirou.jp/blog1/?p=520
-なひたふJTAG日記: Microsoft Excelで波形を描く方法
 http://nahitafu.cocolog-nifty.com/nahitafu/2007/04/excel_e5a2.html
-タイミングチャート清書ツール tchart
 http://www.mech.tohoku-gakuin.ac.jp/rde/contents/library/tchart/indexframe.html
-【VB.NET】COMラッパーアセンブリに厳密名で署名 - Insider.NET
 http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=27151&forum=7
-Excel97 の COM の IDL から TLB を生成したい
 http://m--takahashi.com/bbs/pastlog/09100/09068.html
"""
import sys
import nt
import clr
clr.AddReferenceToFile("Excel9.dll")
from excel9 import *
clr.AddReferenceToFile("Office.dll")
from Office import *

class TimingChartExcel:
    """タイミングチャートをExcelで描画するクラス
        以下のように呼び出してください
        o = TimingChartExcel()
        o.create()
        o.draw_1signal(2, "clk", "_~_~")
        o.save("hoge")
    """
    def __init__(self):
        """コンストラクタ"""
        self.xlApp = None
        self.xlBook = None
        self.xlSheet = None
    
    def __del__(self):
        """デストラクタ"""
        # 強制的にExcelを閉じる
        self.xlBook.Saved = True
        self.xlApp.Quit()
    
    def RGB(self, r, g, b):
        """R, G, BをCOLORREF値に変換"""
        v = (r & 0xff) | ((g & 0xff) << 8) | ((b & 0xff) << 16)
        return v
    
    def create(self):
        """タイミングチャートを描画するファイルの新規作成
        """
        self.xlApp = ApplicationClass()
        self.xlApp.Visible = True
        
        # WorkBookを開く
        self.xlBook = self.xlApp.Workbooks.Add()
        # WorkSheetを開く
        self.xlSheet = self.xlBook.Sheets[1]
        print self.xlSheet.Name
        
        self.__描画の前準備()
    
    def __描画の前準備(self):
        self.xlSheet.Cells.Select()
        self.xlApp.Selection.ColumnWidth = 0.96
        self.xlApp.Selection.RowHeight = 9.6
        
        self.xlSheet.Columns["A:A"].Select()
        self.xlApp.Selection.ColumnWidth = 0.96 * 10

    def __1CLKの描画(self, x, y, c, pre_c):
        o = self.xlSheet.Cells[y, x]
        
        # 前後のデータが違うならば、縦線が必要だ
        if c != pre_c:
            self.xlSheet.Shapes.AddLine(o.Left, o.Top, o.Left, o.Top + o.Height)
        
        # '~'はHigh / '_'はLow / '|'はタイミング線を引く
        if c == "~":
            self.xlSheet.Shapes.AddLine(o.Left, o.Top, o.Left + o.Width, o.Top)
        elif c == "_":
            self.xlSheet.Shapes.AddLine(o.Left, o.Top + o.Height, o.Left + o.Width, o.Top + o.Height)
        elif c == "|":
            top = self.xlSheet.Cells[1, x].Top
            down = self.xlSheet.Cells[50, x].Top
            left = o.Left
            lo = self.xlSheet.Shapes.AddLine(left, top, left, down).Line
            lo.ForeColor.RGB = self.RGB(255, 0, 0)
            lo.DashStyle = MsoLineDashStyle.msoLineSquareDot
            return x
        else:
            raise "no char"
        
        return x + 1
    
    def draw_1signal(self, rowNo, name, data):
        """1つの信号の描画
            - rowNo = 描画する行位置(1〜以上を指定)
            - name タイミングチャートの信号名
            - data タイミングチャートのデータ文字列
        """
        print name, data
        self.xlSheet.Cells[rowNo, 1].Value = name
        
        x = 2
        pre_c = None
        for c in data:
            x = self.__1CLKの描画(x, rowNo, c, pre_c)
            pre_c = c
    
    def save(self, fileName):
        """現在のシートをファイルに保存"""
        if fileName.find(":") == -1:
            fileName = nt.getcwd() + "\\" + fileName
        print "save:" + fileName
        self.xlSheet.SaveAs(fileName)

def command_parse():
    """コマンド解析"""
    try:
        for i in range(len(sys.argv)):
            print "argv[%d] = %s" % (i, sys.argv[i])
            
        
        if len(sys.argv) < 3:
            raise "コマンド引数が足りないよ"
        
        in_file = sys.argv[1]
        out_file = sys.argv[2]
        return in_file, out_file
    except:
        print "USAGE> t_cha <入力ファイル(.TXT)> <出力ファイル(.XLS)>"
        raise

def main():
    in_file, out_file = command_parse()
    
    o = TimingChartExcel()
    o.create()
    
    f = file(in_file)
    row = 2
    for l in f:
        print l
        name, data = l.split()
        data = data.strip(" \t\n")
        o.draw_1signal(row, name, data)
        row = row + 2
    
    if raw_input("タイミングチャートを保存しますよ?(yes = 'Y')") == 'Y':
        o.save(out_file)

if __name__=="__main__":
    main()

t_chaの実行例

コンソールでの実行例を以下に示します。

$ ipy t_cha.py test.txt hoge.xls
argv[0] = t_cha.py
argv[1] = test.txt
argv[2] = hoge.xls
Sheet1
Clk             _~_~_~_~_~_~_~_~_~_~_~_~_~_~_~

Clk _~_~_~_~_~_~_~_~_~_~_~_~_~_~_~
Sync    _~~|__________~~__________~~___

Sync _~~|__________~~__________~~___
タイミングチャートを保存しますよ?(yes = 'Y')Y
save:F:\Wacky\Test\python\20070430.IronPythonでタイミングチャート\hoge.xls

上では、test.txtから、タイミングチャート図を作って、hoge.xlsに出力する。って事を行っています。

ちなみに、test.txtの中身は、どんなものかと言うと、↓こんな簡単なものです。

Clk		_~_~_~_~_~_~_~_~_~_~_~_~_~_~_~
Sync	_~~|__________~~__________~~___

ちょっとしたポイント

と言っても、大した事はありません。

  • 公開しないメソッドは、helpコマンドで表示されないように、"__"をプレフィクスに付けてます
  • IronPythonは、Unicodeで動くので、メソッド名に(一部)日本語使っちゃったりしてます
  • タイミングチャートの書式を拡充したかったら、"__1CLKの描画"メソッドをいじればOKでしょう
  • Excelのコンテナ配列にアクセスする時、IronPythonでは"()"でなく"[]"な点に注意
  • "ipy t_cha.py"ってのが面倒なら、pycとかでバイナリ化してしまって下さい