OpenOffice.orgのマクロをPythonで記述して動かす(Calc上でマクロが動作しているかのチェックを改善)
「OpenOffice.orgのマクロをPythonで記述して動かす(Calc上でマクロが動作しているかのチェックと全シートのオブジェクトの取得に関するメモ)」では「XSCRIPTCONTEXT.getDocument()」で得たドキュメントオブジェクトのメンバ関数supportsService()の結果によって自作クラスのOOoCalcの中のメンバsupportedを設定し、オブジェクト生成後にこれをチェックするという流れをとっていたが、これはクラスの利用(マクロ本体の関数)側の処理の流れを制限し、オブジェクトの使い方によっては意図しないエラーが出ることにもなって好ましくないと思い、ユーザ定義例外を用いて処理を変更することにした。
class NotOOoCalcException(Exception): pass class Bridge(object): def __init__(self): self._desktop = XSCRIPTCONTEXT.getDesktop() self._document = XSCRIPTCONTEXT.getDocument() self._frame = self._desktop.CurrentFrame self._window = self._frame.ContainerWindow self._toolkit = self._window.Toolkit def run_errordialog(self, title='', message=''): ... class OOoCalc(Bridge): def __init__(self): Bridge.__init__(self) if not self._document.supportsService('com.sun.star.sheet.SpreadsheetDocument'): self.run_errordialog(title='エラー', message='このマクロはOpenOffice.org Calcの中で実行してください') raise NotOOoCalcException() # 以下、Calc固有のオブジェクトの取得などが続く def macroname(): try: calc = OOoCalc() # Calcの中かどうかをチェックする except NotOOoCalcException: return # 以下、Calc固有の処理が続く
「このマクロは...」のエラーダイアログの表示処理は各マクロの先頭からOOoCalcクラスの__init__()のチェック部分のほうに移動して、マクロ側からは単にtry-except文でNotOOoCalcException例外の処理でreturn文を実行するようにするだけにした。もしtry-except文の中でOOoCalcオブジェクトを生成しなくても、「このマクロは...」のダイアログの後に「OpenOffice.org のエラー」というダイアログが例外の発生を知らせてそこでマクロの実行は自動的に止まることになる。
BridgeやOOoCalcというような自作クラスを用意しているのは、OpenOffice.orgとの仲立ちをしている部分における決まりきった独特な書き方や中間のオブジェクトなどをできるだけ見えなくしてマクロ本体の関数の中をできるだけ見やすくするのが目的。
「OpenOffice.orgのマクロをPythonで記述して動かす(Calcのシート追加に関するメモとシート追加のコード例)」で貼り付けた例は以下のようになった。
[任意]ファイル名: [OOoユーザディレクトリ]/user/Scripts/python/calc_insert_sheet_2.py
# -*- mode: python; coding: utf-8 -*- import uno import unohelper class NotOOoCalcException(Exception): """ OOo Calcの中でマクロが呼ばれなかったときに発生する例外 """ pass class Bridge(object): """ PythonとOOoの仲立ちをする各種オブジェクトと それを用いた幾つかの操作を提供 """ def __init__(self): """ 各種オブジェクトの取得 """ # http://api.openoffice.org/docs/common/ref/com/sun/star/script/provider/XScriptContext.html # http://api.openoffice.org/docs/common/ref/com/sun/star/uno/XComponentContext.html # self._context = XSCRIPTCONTEXT.getComponentContext() # このコードでは未使用 # self._manager = self._context.ServiceManager # このコードでは未使用 self._desktop = XSCRIPTCONTEXT.getDesktop() self._document = XSCRIPTCONTEXT.getDocument() # http://api.openoffice.org/docs/common/ref/com/sun/star/frame/XDesktop.html self._frame = self._desktop.CurrentFrame # http://api.openoffice.org/docs/common/ref/com/sun/star/frame/XFrame.html self._window = self._frame.ContainerWindow self._toolkit = self._window.Toolkit def run_infodialog(self, title='', message=''): """ 情報ダイアログを表示する http://api.openoffice.org/docs/common/ref/com/sun/star/awt/XMessageBoxFactory.html http://hermione.s41.xrea.com/pukiwiki/pukiwiki.php?OOoPython%2FOverView """ msgbox = self._toolkit.createMessageBox(self._window, uno.createUnoStruct('com.sun.star.awt.Rectangle'), # ダイアログの種類を指定する文字列 # infobox,warningbox,errorbox, # querybox,messboxのいずれか 'infobox', 1, title, message) msgbox.execute() msgbox.dispose() def run_errordialog(self, title='', message=''): """ エラーダイアログを表示する http://api.openoffice.org/docs/common/ref/com/sun/star/awt/XMessageBoxFactory.html """ msgbox = self._toolkit.createMessageBox(self._window, uno.createUnoStruct('com.sun.star.awt.Rectangle'), 'errorbox', 1, title, message) msgbox.execute() msgbox.dispose() class OOoCalc(Bridge): """ OOo Calcの制御 BridgeをベースにCalcのサポート状態と全シートを追加したもの """ def __init__(self): Bridge.__init__(self) # 必須 # Calcの中から実行されたならTrue,それ以外ならFalse # http://api.openoffice.org/docs/common/ref/com/sun/star/lang/XServiceInfo.html if not self._document.supportsService('com.sun.star.sheet.SpreadsheetDocument'): self.run_errordialog(title='エラー', message='このマクロはOpenOffice.org Calcの中で実行してください') raise NotOOoCalcException() # Calcの全シート # プロパティSheetsかメンバ関数getSheets() # http://api.openoffice.org/docs/common/ref/com/sun/star/sheet/XSpreadsheetDocument.html self.__sheets = self._document.Sheets @property def sheets(self): return self.__sheets def m01_add_sheet(): "OOo Calcでシート「新しいシート」を一番左に追加" try: calc = OOoCalc() # Calcの中かどうかをチェックする except NotOOoCalcException: return # 新規シートを作成 sheetname = '新しいシート' # シートの存在をチェックする # 指定された名前のシートが既に存在していればTrue # http://api.openoffice.org/docs/common/ref/com/sun/star/container/XNameAccess.html if calc.sheets.hasByName(sheetname): calc.run_errordialog(title='エラー', message='既にシート "%s" が存在します' % sheetname) else: # 1番目の引数は名前 # 2番目の引数は追加位置(0は一番左に追加する) # http://api.openoffice.org/docs/common/ref/com/sun/star/sheet/XSpreadsheets.html try: calc.sheets.insertNewByName(sheetname, 0) # ここでは毎回ダイアログを出すことにする calc.run_infodialog(title='シート追加成功', message='シート "%s" を追加しました' % sheetname) except unohelper.RuntimeException: # 上限シート数を超えると例外unohelper.RuntimeExceptionが発生 calc.run_errordialog(title='エラー', message='シート数が上限に達したため\n新しいシートを追加できませんでした') return def m02_add_5_sheets(): "OOo Calcでシート「シート [番号]」を5つ続けて右側に追加" try: calc = OOoCalc() except NotOOoCalcException: return # 現在のシート数を取得 # http://api.openoffice.org/docs/common/ref/com/sun/star/container/XIndexAccess.html # プロパティCountかメンバ関数getCount() cnt = calc.sheets.Count for i in range(5): # iは0から4 sheetname = 'シート %d' % (i + 1,) if calc.sheets.hasByName(sheetname): calc.run_errordialog(title='エラー', message='既にシート "%s" が存在します' % sheetname) return else: # 追加シートが一番右に来るように2番目の引数を調整 try: calc.sheets.insertNewByName(sheetname, i + cnt) calc.run_infodialog(title='シート追加成功', message='シート "%s" を追加しました' % sheetname) except unohelper.RuntimeException: calc.run_errordialog(title='エラー', message='シート数が上限に達したため\n新しいシートを追加できませんでした') return def m03_add_300_sheets(): "OOo Calcでシート「シート [番号]」を300個続けて右側に追加(しようとする)" try: calc = OOoCalc() except NotOOoCalcException: return cnt = calc.sheets.Count for i in range(300): sheetname = 'シート %d' % (i + 1,) if calc.sheets.hasByName(sheetname): calc.run_errordialog(title='エラー', message='既にシート "%s" が存在します' % sheetname) return else: try: calc.sheets.insertNewByName(sheetname, i + cnt) except unohelper.RuntimeException: calc.run_errordialog(title='エラー', message='シート数が上限に達したため\n新しいシートを追加できませんでした') return # このタプルに名前を書いた関数のみマクロ選択ダイアログから実行できる # g_exportedScriptsを記述しない場合は全て実行可 g_exportedScripts = (m01_add_sheet, m02_add_5_sheets, m03_add_300_sheets)
関連記事:
- Pythonの例外とその処理に関する覚え書き(ユーザ定義の例外など)
- OpenOffice.orgのマクロをPythonで記述して動かす(概要,ファイル配置,ダイアログの表示)
- OpenOffice.orgのマクロをPythonで記述して動かす(Calc上でマクロが動作しているかのチェックと全シートのオブジェクトの取得に関するメモ)
- OpenOffice.orgのマクロをPythonで記述して動かす(Calcのシート追加に関するメモとシート追加のコード例)
- OpenOffice.orgのマクロをPythonで記述して動かす(Calcのアクティブもしくは任意のシートとセルのオブジェクトの取得)
- OpenOffice.orgのマクロをPythonで記述して動かす(Calcのセル内容へのアクセスについてとセル内容の操作に関する例)
使用したバージョン:
- OpenOffice.org(Go-oo) 3.1.1
- Python 2.6.4