<このシリーズの、前の記事 | このシリーズの目次 | このシリーズの、次の記事>
LibreOfficeまたはApache OpenOfficeのCalcスプレッドシートを拡張機能を通してJavaまたはマクロプログラムから操作する(読むまたは書く)方法を知る
前は、我々は、スプレッドシートセルの文字列を、既存の文字列を消去し、新たな文字列をセットすることでセットした。
確かにそうした。
既存の文字列の任意の位置に文字列を挿入したり、既存の文字列の任意の領域をある文字列で置き換えたり、既存の文字列の任意の領域を消去したりすることもできる。
それは、既存の文字列を取得して、得た文字列をJava内で操作し、既存の文字列を消去し、操作した文字列をセットすることでも行なえる。どちらが効率が良いのか?
既存の文字列がとても長い場合、後者のほうがはるかに効率が良い。なぜだか知らないが、長い既存文字列を前者の方法で操作するのは、不思議に多くのCPUリソースを必要とする。
どの程度の長さのことを言っているのか?
数千文字だ。我々の極度に低速なコンピューターでは、1文字追加するのに約20秒かかる。
そのコンピューターが極度に、極度に低速なことは知っているが、内部アルゴリズムが何か不適当ではないか?
たぶん、そんなに長い文字列がスプレッドシートセルにセットされるとは想定されていないのだろう。長い文字列を考慮に入れれば、もっと良いアルゴリズムがあるはずだと思う。
既存文字列がそれほど長くなかったらどうなのか?
そうした場合の正確なパフォーマンスは計測していない。大量データを処理していなければ、感知できるような違いはないだろう。
まあ、必要に直面したときに判断すればよいだろう。どちらにしろ、セル文字列を前者の方法で操作する必要性はあるのか?
ああ、前者の方法が必要とされるケースはある。既存の文字列がその部分によって異なったフォーマットになっている場合、文字列全体をただ置き換えるというわけにはいかない。
例えば、文字列中の1つの単語だけがイタリックという場合か?
そうだ。もちろん、文字列全体を置き換えてフォーマットをセットしなおすことはできるが、それは面倒かもしれない。文字列全体の既存のフォーマット情報を取得して、そのフォーマットを再適用しなければならない。
ふーむ、それが本当に面倒かどうかは知らないが、文字列がそれほど長くない場合、前者の方法で既存文字列を操作するのが自然そうだ。
長いセル文字列をその部分ごとにフォーマット適用したい場合には、何か方法を考えなければならないだろう。
ワードプロセッサーを扱っているわけではないので、込み入ったフォーマットが必要になるとは思わないが、文字列中の特定の単語を示すマーカーが欲しいということはあるかもしれない。
ああ、そうかもしれない。しかし、今、そこに深入りするのはやめておこう。
オーケー。
前の記事で行なったように、セルUNOオブジェクトから、'com.sun.star.text.XText'UNOインターフェースを使って、'com.sun.star.text.XTextCursor'インスタンスを得る。UNOインターフェース、'com.sun.star.text.XTextCursor'は、'com.sun.star.text.XTextRange'のサブインターフェースであり、セルの文字列のある選択された領域を代表する。
それでは、'com.sun.star.text.XTextCursor'インスタンスはただの単点カーソルではないわけだ。
選択された領域が縮んで文字が一つも選択されていない状態になれば、この'com.sun.star.text.XTextCursor'インスタンスは単点カーソルになる。
なるほど。
メソッド、'createTextCursor'で'com.sun.star.text.XTextCursor'インスタンスを得た場合、初期状態では文字列全体が選択されている。メソッド、'createTextCursorByRange'を使えば、カーソルが文字列の先頭か終端に置かれた'com.sun.star.text.XTextCursor'インスタンスを得ることができる。
おお。
カーソルは、メソッド、'goRight'か'goLeft'によって、それぞれ右か左に移動することができる。これらのメソッドでは、カーソルを何文字分移動させるかを指定できる。
カーソルは、'gotoStart'か'gotoEnd'によって、それぞれ文字列の先頭か終端に移動することができる。
文字列の領域はどのように選択できるのか?
上記4メソッドは、選択されている領域を拡張するかどうかを指定する引数を持っている。
ふーむ、察するに、ある領域を選択したい場合、その引数をオフにしてカーソルをその領域の左端に移動し、次に、その引数をオンにしてカーソルをその領域の右端まで移動すればよいわけだ。
そう。もちろん、反対方向に、カーソルを領域の右端に位置させ、左へ拡張することでも同じことができる。
なるほど。
カーソルの状態を調整した後、'com.sun.star.text.XText'UNOインターフェースの'insertString'メソッドを呼んで文字列を挿入する。'com.sun.star.text.XTextCursor'インスタンスと挿入するべき文字列を、それぞれ第1、第2引数として渡す。. 第3引数には、選択された領域を置換するかどうかを指定する。しない場合は、新たな文字列は選択された領域の前に挿入される。
文字列が挿入された後、カーソルの状態はどうなるのか?
選択された領域が置換されるか否かにかかわらず、カーソルは、挿入された文字列の後ろに、単点カーソルとして位置する。
ははあ。
選択された領域を消去したい場合は、空文字列で領域を置換するようにメソッド、'insertString'を呼べばよい。
なるほど。
結局、前記事のコードの後に以下のコードを書いた。
l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 8);
l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
l_spreadSheetCellInXText = (XText) UnoRuntime.queryInterface (XText.class, l_spreadSheetCell);
l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_textFormatIdentification));
l_string = "0123456789";
l_spreadSheetCell.setFormula ("");
l_textCursor = l_spreadSheetCellInXText.createTextCursor ();
l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
l_textCursor = l_spreadSheetCellInXText.createTextCursorByRange (l_spreadSheetCellInXText.getEnd ());
l_textCursor.gotoStart (false);
l_string = "A";
l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
l_textCursor.goRight ( (short) 1,false);
l_string = "B";
l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
l_textCursor.goRight ( (short) 1, false);
l_textCursor.goRight ( (short) 1, true);
l_string = "C";
l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
l_string = "D";
l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
l_textCursor.gotoEnd (false);
l_string = "E";
l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
l_textCursor.goLeft ( (short) 2, false);
l_string = "F";
l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
l_textCursor.goLeft ( (short) 2, false);
l_textCursor.goLeft ( (short) 1, true);
l_string = "G";
l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
l_textCursor.goLeft ( (short) 2, false);
l_textCursor.goLeft ( (short) 1, true);
l_string = "";
l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
カーソルを、既存文字列の終端に位置させた初期状態で取得し、文字列の先頭に移動した。
そう。もちろん、既存文字列の先頭に位置させた初期状態で取得することもできる。上記のようにしたのは、'gotoStart'メソッドの呼び出しを実証するためだ。
分かっている。
最終的なセル文字列は"A0B1CD346G8F9E"のはずだ。