POIでコネクタを描いてみる
POIでコネクタは描けるのか?
SIerはExcelが大好きなので、設計書もExcelで作ることが多い(いいか悪いかは置いといて…)。
でも手で全部書くのは面倒なので、Javaのソースから自動生成できると便利だなー、とか思うことがある。
設計書には、オートシェイプとかコネクタを使って図も入れたい。
だけど、POIでコネクタは描けるんだろうか?
一応それらしいメソッドはあったが…
Javadocを覗くと、XSSFDrawingクラスにcreateConnectorというメソッドがあった。
これっぽいんだけど…、こいつの引数はXSSFClientAnchorなんだよね。
つまり、座標を指定するんだけど、接続先の図形は指定しなくていいの?
とりあえず、コードを書いて実行してみる。
try (Workbook workbook = new XSSFWorkbook()) { Sheet sheet = workbook.createSheet(); XSSFDrawing drawing = (XSSFDrawing)sheet.createDrawingPatriarch(); XSSFClientAnchor anchor1 = drawing.createAnchor(0, 0, 400000, 100000, 1, 1, 1, 1); XSSFTextBox textBox1 = drawing.createTextbox(anchor1); textBox1.setLineWidth(1); textBox1.setLineStyleColor(255, 0, 0); textBox1.setFillColor(255, 255, 0); XSSFClientAnchor anchor2 = drawing.createAnchor(0, 0, 400000, 100000, 2, 3, 2, 3); XSSFTextBox textBox2 = drawing.createTextbox(anchor2); textBox2.setLineWidth(1); textBox2.setLineStyleColor(255, 0, 0); textBox2.setFillColor(255, 255, 0); XSSFClientAnchor anchor3 = drawing.createAnchor(200000, 100000, 200000, 0, 1, 1, 2, 3); XSSFConnector connector = drawing.createConnector(anchor3); connector.setLineWidth(1); connector.setLineStyleColor(128, 0, 0); File file = new File("connector.xlsx"); try (OutputStream out = new FileOutputStream(file)) { workbook.write(out); } }
一応それらしいのはできたんだけど…
テキストボックスを動かしてみると、線が付いてこない。
これは「コネクタ」じゃなくて、ただの「線」だ。
コネクタのXMLを見てみる
とは言え、XSSFConnectorにそれらしいメソッドは見当たらない。
ただ、XMLレベルでいじれるメソッド(getCTConnector)はあるので、これを使えば何とかなるかも。
という訳で、コネクタが保存されたxlsxファイルのXML構造を調べてみる。
上で作成したxlsxファイルの他、ちゃんとコネクタの接点をつなげたxlsxファイルを用意して、拡張子をzipに変えて展開、xl/drawings/drawing1.xmlを見比べてみる。
すると、後者だけにある怪しい要素が見つかった。
<xdr:wsdr> <xdr:twoCellAnchor> <xdr:cxnSp> <xdr:nvCxnSpPr> <xdr:cNvCxnSpPr> <a:stCxn id="2" idx="2"/> <a:endCxn id="3" idx="0"/> </xdr:cNvCxnSpPr> ...
おそらく、idは図形を特定するID、idxは図形における接点の場所(たぶん上が0で下が2)だろう。
IDの謎
で、以下のようなコードを追加したんだけど…、うまくいかない…。
connector.getCTConnector().getNvCxnSpPr().getCNvCxnSpPr().addNewStCxn().setId(textBox1.getCTShape().getNvSpPr().getCNvPr().getId()); connector.getCTConnector().getNvCxnSpPr().getCNvCxnSpPr().getStCxn().setIdx(2); connector.getCTConnector().getNvCxnSpPr().getCNvCxnSpPr().addNewEndCxn().setId(textBox2.getCTShape().getNvSpPr().getCNvPr().getId()); connector.getCTConnector().getNvCxnSpPr().getCNvCxnSpPr().getEndCxn().setIdx(0);
いろいろ調べてみると、どうもIDがおかしいっぽい。
正しいxlsxの方は、
テキストボックス1 = 2 テキストボックス2 = 3 コネクタ = 4
なんだけど、POIの方は
テキストボックス1 = 1 テキストボックス2 = 2 コネクタ = 1
になっている。
IDが重複しているのがおかしいし、正しいxlsxでは1が欠番になっている。
以下のようにしたら、どうやらうまくいったようだ。
textBox1.getCTShape().getNvSpPr().getCNvPr().setId(2); textBox2.getCTShape().getNvSpPr().getCNvPr().setId(3); connector.getCTConnector().getNvCxnSpPr().getCNvPr().setId(4); connector.getCTConnector().getNvCxnSpPr().getCNvCxnSpPr().addNewStCxn().setId(textBox1.getCTShape().getNvSpPr().getCNvPr().getId()); connector.getCTConnector().getNvCxnSpPr().getCNvCxnSpPr().getStCxn().setIdx(2); connector.getCTConnector().getNvCxnSpPr().getCNvCxnSpPr().addNewEndCxn().setId(textBox2.getCTShape().getNvSpPr().getCNvPr().getId()); connector.getCTConnector().getNvCxnSpPr().getCNvCxnSpPr().getEndCxn().setIdx(0);
ちゃんとつながっている!
とは言え、また今回も謎が残ってしまった…。
OS | Windows 7 |
Office | 2010 |
Java | 8u31 |
Apache POI | 3.11 |