正月にちまちま整備していた Excel Like Uno が、まあ動くようになったので仮リリースしておきます。
https://github.com/moonmile/ExcelLikeUno
12月に LibreOffice Calce の Python マクロを使って、諸々を試していたのですが、現状の uno api だけでは限界がありそうなので、更にラップをするライブラリを作って試しています。
目的としては、
- UNO API の複雑さを隠蔽し、Excel/VBA に近いメソッド・プロパティ名でする
- 型定義を充実させ、IDE 補完と静的解析をサポート
なところで、従来の Excel VBA に似せています。
実は LibreOffice Calc でも Option VBASupport 1 のオプションを付けると VBA 互換モードで動かせます。かなり Excel VBA に近いところまでエミュレートするので Excel VBA から移行する場合はこっちのほうが楽かもしれません。
ただ、いまさら VBA でやりたくないし、どうせならば Python か何か別の言語でやりたいところです。
サンプル calc_sample_cell.py
from excellikeuno import connect_calc
from excellikeuno.typing.calc import CellHoriJustify, CellVertJustify
(desktop, doc, sheet) = connect_calc()
cell = sheet.cell(0, 0) # A1 セルを取得
cell.text = "Hello, World!" # 値を設定
sheet.range("A1:C1").merge(True) # A1:C1 を結合
cell.font_size = 16
cell.font_name = "Arial"
cell.font_color = 0xFF0000 # フォント色を赤に
cell.row_height = 2000 # 行の高さを設定 20 mm
cell.HoriJustify = CellHoriJustify.CENTER
cell.VertJustify = CellVertJustify.CENTER
sheet.cell(0,1).text = "id"
sheet.cell(1,1).text = "name"
sheet.cell(2,1).text = "address"
sheet.range("A2:C2").CellBackColor = 0xFFBF00 # A2:C2 の背景色を設定
data = [
[1, "masuda", "tokyo"],
[2, "suzuki", "osaka"],
[3, "takahashi", "nagoya"],
]
sheet.range("A3:C5").value = data # 範囲にデータを一括設定
こんな感じで、最初に connect_calc() で接続してから、
- sheet.cell( column, row ) でセルを取得
- cell.font_size などのプロパティを使う
といいうことができます。テキストや値は、getText() や setText() を使うのではなく、text プロパティを使います。実際には、数値は value プロパティ、テキストが text プロパティにしてあります。

この Python コードを実行すると、LibreOffice Calc だと、こんな表示になります。
まあ、一般的な表ぐらいはできそうな状態です。
サンプル calc_sample_shogiban.py
罫線のサンプルを見てみましょう。
# 将棋盤を作る
from excellikeuno import connect_calc
from excellikeuno.typing.calc import CellHoriJustify, CellVertJustify
from excellikeuno.typing.structs import BorderLine
(desktop, doc, sheet) = connect_calc()
# sheet.name = "将棋盤"
ban = sheet.range("A1:I9");
ban.CellBackColor = 0xFFFACD # 背景色を薄い黄色に設定
ban.row_height = 1000 # 行の高さを設定 20 mm
ban.column_width = 1000 # 列の幅を設定 20 mm
# 罫線を設定
for cell in [c for row in ban.cells for c in row]:
borderline = BorderLine()
borderline.Color = 0x000000
borderline.OuterLineWidth = 50
borderline.InnerLineWidth = 0
borderline.LineDistance = 0
cell.TopBorder = borderline
cell.BottomBorder = borderline
cell.LeftBorder = borderline
cell.RightBorder = borderline
# センタリング
cell.HoriJustify = CellHoriJustify.CENTER
cell.VertJustify = CellVertJustify.CENTER
# フォントサイズを大きく
cell.font_size = 16.0
cell.CharColor = 0x000000 # 黒色に設定
# 駒を配置
pieces = [
["香", "桂", "銀", "金", "王", "金", "銀", "桂", "香"],
["", "飛", "", "", "", "", "", "角", ""],
["歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩"],
["", "", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", "", ""],
["歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩"],
["", "角", "", "", "", "", "", "飛", ""],
["香", "桂", "銀", "金", "王", "金", "銀", "桂", "香"],
]
ban.value = pieces # 一括で駒を配置
# 相手の駒を反転表示
for r in range(9):
for c in range(9):
cell = ban.cell(c, r)
if pieces[r][c] != "" and r < 3:
cell.CharRotation = 180 # 180度回転

セルの大きさを変えて(いわゆる将棋盤にします)、駒をセルに書いていきます。
罫線をつけるところと、文字が180度回転させることができます。
まあ、これを Excel でやるかどうかは別ですが、Excel 方眼紙ぐらいならば作れそうです。
サンプル calc_sample_tsurukame.py
これは図形を配置する例です。
# 鶴亀オセロのサンプル
from excellikeuno import connect_calc
from excellikeuno.typing.structs import BorderLine
(desktop, doc, sheet) = connect_calc()
# sheet.name = "鶴亀オセロ"
ban = sheet.range("A1:H8");
ban.CellBackColor = 0x006400 # 背景色を濃い緑色に
ban.row_height = 1000 # 行の高さを設定 10 mm
ban.column_width = 1000 # 列の幅を設定 10 mm
# 罫線を設定
for cell in [c for row in ban.cells for c in row]:
borderline = BorderLine()
borderline.Color = 0x000000
borderline.OuterLineWidth = 50
borderline.InnerLineWidth = 0
borderline.LineDistance = 0
cell.TopBorder = cell.BottomBorder = cell.LeftBorder = cell.RightBorder = borderline
# オセロの駒を Shape で配置
pieces = [
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "黒", "白", "", "", ""],
["", "", "", "白", "黒", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
]
for r in range(8):
for c in range(8):
cell = ban.cell(c, r)
piece = pieces[r][c]
if piece == "":
continue
sheet.shapes.add_ellipse_shape(
x=cell.position.X + 200,
y=cell.position.Y + 200,
width=600,
height=600,
fill_color=0x000000 if piece == "黒" else 0xFFFFFF,
line_color=0x000000,
)

セルに罫線と背景色をつけて、オセロの駒は EllipseShape(楕円)を使います。
サンプル calc_sample_mahjong.py
フォント指定と TextShape を使った例です。
# 麻雀牌を並べる
from excellikeuno import connect_calc
from excellikeuno.typing.calc import LineStyle
(desktop, doc, sheet) = connect_calc()
# sheet.name = "麻雀牌"
hai = ['1','1','1', '2','2','2', '3','3','3', '4','4','4', 'a',' ','a']
# 13個の TextShape をシートに追加
for i in range(hai.__len__()):
shape = sheet.shapes.add_text_shape(
x=i * 1600,
y=1000,
width=1500,
height=2000,
text=str(hai[i]),
fill_color=0xFFFFE0 # 薄い黄色
)
# 背景色を設定
shape.FillColor = 0xFFFFE0 # 薄い黄色
# 枠線の色を設定
shape.LineStyle = LineStyle.SOLID # SOLID
shape.LineWidth = 50 # 線の太さを50 (1/100 mm)
shape.LineColor = 0x008000 # 緑
# テキストを中央揃え
shape.HoriJustify = 1 # CENTER
shape.VertJustify = 1 # CENTER
# フォントサイズを大きく
shape.font_size = 48.0
# フォントの指定
shape.CharFontName = "GL-MahjongTile"
# 麻雀牌を並べる
for i, shape in enumerate(sheet.shapes):
shape.PositionX = i * 1600 # X位置をずらす
shape.PositionY = 1000 # Y位置を10 mmに設定
# 完成

麻雀用のフォント “GL-MahjongTile” を使って TextShape を使った例です。
フォント自体は PC にインストールしないと駄目なので、埋め込みはできません。
図形が貼り付けられると、フローチャートとかネットワーク図とかの生成ができるようになります。
Calc 内部からマクロで呼び出す
いままでの例は外部から Python コードを使って呼び出すのですが、Calc 内部から Python コードを呼び出すには、XSCRIPTCONTEXT を使わないといけません。ただし、ちょっと初期化コードが外部呼出しからとは異なるのがややこしいのですが、以下のように書けます。
import inspect
import os
import sys
from typing import Any, Tuple
# Ensure this script's directory is importable so the local excellike package resolves
BASE_DIR = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
if BASE_DIR not in sys.path:
sys.path.append(BASE_DIR)
from excellikeuno.table.sheet import Sheet
# XSCRIPTCONTEXT に接続する
def connect_calc_script() -> Tuple[Any, Any, Sheet]:
desktop = XSCRIPTCONTEXT.getDesktop()
doc = desktop.getCurrentComponent()
controller = doc.getCurrentController()
sheet = Sheet(controller.getActiveSheet())
return desktop, doc, sheet
def hello_to_cell():
( _, _, sheet ) = connect_calc_script()
sheet.cell(0, 0).text = "Hello Excel Like for Python!"
sheet.cell(0, 1).text = "こんにちは、Excel Like for Python!"
sheet.cell(0,0).column_width = 10000 # 幅を設定
cell = sheet.cell(0,1)
cell.CellBackColor = 0x006400 # 濃い緑に設定
cell.CharColor = 0xFFFFFF # 文字色を白に設定
g_exportedScripts = (
hello_to_cell,
)

こんな風にマクロを実行します。

connect_calc_script 部分を自前で書かないといけないのが難点なので、これは connect_calc にうまく吸収させる予定です。Calc と接続した後は、uno api は共通化されているので同じコードが動きます。つまり ExcelLikeUno ライブラリも外部からでも内部からもで動くということです。
内部で使える Python マクロで何が良くなるかと言うと、こんな風に vscode 使って Python コードが書けるという点です。Excel VBA 互換や、独自 Basic のコードだと付属のエディタでしか書けませんが、Python コードならば vscode で書けます。さらに言えば、git と連携もできるので、コードの保存が可能です。

ただし、コード保存の場所が
C:\Users\<ユーザー名>\AppData\Roaming\LibreOffice\4\user\Scripts\python\
というややこしい場所になっているのが難点で、excellikeuno ライブラリもここに配置しなければいけません。これも今後なんとかしていこうと考えています。
参照先
https://github.com/moonmile/ExcelLikeUno
README.md にもう少し詳しい説明があります。Linux 版や Docker 版などは、準備中。
