Calc(23)セルやセル範囲のアドレスの取得方法

2017-10-15

旧ブログ

t f B! P L
OOoBasic/Calc/address - ...?のBasicの例を参考にPythonでセルやセル範囲のアドレスを取得してみます。

前の関連記事:Calc(22)セル範囲とセル範囲コレクションのサービスとインターフェイスの比較


文字列アドレスの取得

def macro():
 doc = XSCRIPTCONTEXT.getDocument()  # ドキュメントを取得。
 controller = doc.getCurrentController()  # ドキュメントのコントローラ。
 selection = controller.getSelection()  # 選択しているオブジェクトを取得。
 cellranges = doc.createInstance("com.sun.star.sheet.SheetCellRanges")  # com.sun.star.sheet.SheetCellRangesをインスタンス化。
 cellranges[""] = selection  # セル範囲のコレクションに挿入する。名無しでもいい模様。
 address = cellranges.getRangeAddressesAsString()  # 文字列でアドレスを取得。
 sheets = doc.getSheets()  # シートコレクション。
 sheet = sheets[0]  # 最初のシート。
 sheet[0, 0].setString(address)  # A1セルに出力。
これで選択しているセルのアドレスの文字列がA1セルに出力されます。


シート名が先頭についてきます。

このときselectionがセル範囲オブジェクトが入っています。

単一セルを選択しているときはセルオブジェクトが入っています。

セルオブジェクトがサポートしているサービスはセル範囲オブジェクトのサポートするサービスに加えてcom.sun.star.sheet.SheetCell, com.sun.star.table.Cellをサポートしています(Calc(13)セルとセル範囲とのサービスとインターフェイスの比較参照)。


離れた複数セルのアドレスもちゃんと出力されます。

このときselectionはセル範囲コレクションオブジェクトが入っています。

セル範囲オブジェクトはcom.sun.star.sheet.SheetCellRangeサービスに代わって、com.sun.star.sheet.SheetCellRangesサービスをサポートしています。
def macro():
 doc = XSCRIPTCONTEXT.getDocument()  # ドキュメントを取得。
 selection = doc.getCurrentSelection()  # 選択しているオブジェクトを取得。
 cellranges = doc.createInstance("com.sun.star.sheet.SheetCellRanges")  # com.sun.star.sheet.SheetCellRangesをインスタンス化。
 cellranges[""] = selection  # セル範囲のコレクションに挿入する。名無しでもいい模様。
 address = cellranges.getRangeAddressesAsString()  # 文字列でアドレスを取得。
 sheets = doc.getSheets()  # シートコレクション。
 sheet = sheets[0]  # 最初のシート。
 sheet[0, 0].setString(address)  # A1セルに出力。
コントローラのgetSelection()メソッドで選択したオブジェクトを取得していましたが、モデルにgetCurrentSelection()メソッドがあったのでそちらを使うようにしました。

com.sun.star.sheet.SheetCellRangesサービス


上のマクロではSheetCellRangesサービスのインスタンスを使っています。

このサービスはサービスマネジャーでインスタンス化してもNoneしか返ってきませんので、ドキュメントのcreateInstance()メソッドでインスタンス化します。

SheetCellRangesサービスのインスタンスはセル範囲のコレクションになります。

アドレスを文字列として取得するgetRangeAddressesAsString()メソッドはセル範囲やセルのメソッドにはなく、セル範囲のコレクションにしかないメソッドなので、セル範囲をこのコレクションに追加してから、getRangeAddressesAsString()メソッドで文字列のアドレスを取得しています。

OOoBasic/Calc/sheetcellranges - ...?には複数のセル範囲内を置換するBasicの例があります。

インデックスアドレスの取得


セルの場合はgetCellAddress()メソッドでCellAddress Structが取得できます。

またgetRangeAddress()メソッドでCellRangeAddress Structを取得できます。

セル範囲でもgetRangeAddress()メソッドでCellRangeAddress Structを取得できます。

セル範囲コレクションではgetRangeAddresses()メソッドでCellRangeAddress Structのシークエンス型が取得できます。
def macro():
 doc = XSCRIPTCONTEXT.getDocument()  # ドキュメントを取得。
 sheets = doc.getSheets()  # シートコレクション。
 sheet = sheets[0]  # 最初のシート。
 sheet.clearContents(511)  # シートのすべてを削除。
 selection = doc.getCurrentSelection()  # 選択しているオブジェクトを取得。
 # インデックスアドレスを取得する。
 if hasattr(selection, "getCellAddress"):  # セルのとき
  celladdress = selection.getCellAddress()
  sheet["A1"].setString("Sheet: {}, Row: {}, Column: {}".format(celladdress.Sheet, celladdress.Row, celladdress.Column))  # A1セルに出力。
 elif hasattr(selection, "getRangeAddress"):  # セルではなくセル範囲のとき
  cellrangeaddress = selection.getRangeAddress()
  sheet["A1"].setString("Sheet: {}, StartRow: {}, EndRow: {}, StartColumn: {}, EndColumn: {}"\
   .format(cellrangeaddress.Sheet, cellrangeaddress.StartRow, cellrangeaddress.EndRow, cellrangeaddress.StartColumn, cellrangeaddress.EndColumn))  # A1セルに出力。
 elif hasattr(selection, "getRangeAddresses"):  # セル範囲コレクションのとき
  cellrangeaddresses = selection.getRangeAddresses()
  for i, cellrangeaddress in enumerate(cellrangeaddresses):
   sheet[i, 0].setString("Sheet: {}, StartRow: {}, EndRow: {}, StartColumn: {}, EndColumn: {}"\
    .format(cellrangeaddress.Sheet, cellrangeaddress.StartRow, cellrangeaddress.EndRow, cellrangeaddress.StartColumn, cellrangeaddress.EndColumn))  # A1セルに出力。
これでセルの時、セル範囲のとき、セル範囲コレクションのときそれぞれインデックスアドレスを出力します。


セルの時は、シートインデックスと行インデックス、列インデックスを表示します。


セル範囲の時は、シートインデックス、セル範囲の開始と終了の行インデックスと列インデックスを表示します。


セル範囲コレクションのときは各セル範囲について一行ずつ出力します。

com.sun.star.table.CellAddressConversionでインデックスアドレスを文字列アドレスに変換する


OOoBasic/Calc/address - ...?にあるcom.sun.star.table.CellAddressConversionをドキュメントのcreateInstance()メソッドでインスタンス化します。

このcom.sun.star.table.CellAddressConversionはAPIリファレンスに載っていませんでした。

TCUで出力してみるとcom.sun.star.table.CellAddressConversionのサービスとインターフェイスは次のようになっていました。
def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 tcu = smgr.createInstanceWithContext("pq.Tcu", ctx)  # サービス名か実装名でインスタンス化。
 doc = XSCRIPTCONTEXT.getDocument()  # Calcドキュメント。
 celladdressconversion = doc.createInstance("com.sun.star.table.CellAddressConversion")
 tcu.wtree(celladdressconversion)

├─.beans.XPropertySet
│                        void  addPropertyChangeListener( [in]                         string aPropertyName,
│                                                         [in] .beans.XPropertyChangeListener xListener
│                                              ) raises ( .lang.WrappedTargetException,
│                                                         .beans.UnknownPropertyException)
│                        void  addVetoableChangeListener( [in]                         string PropertyName,
│                                                         [in] .beans.XVetoableChangeListener aListener
│                                              ) raises ( .lang.WrappedTargetException,
│                                                         .beans.UnknownPropertyException)
│     .beans.XPropertySetInfo  getPropertySetInfo()
│                         any  getPropertyValue( [in] string PropertyName
│                                     ) raises ( .lang.WrappedTargetException,
│                                                .beans.UnknownPropertyException)
│                        void  removePropertyChangeListener( [in]                         string aPropertyName,
│                                                            [in] .beans.XPropertyChangeListener aListener
│                                                 ) raises ( .lang.WrappedTargetException,
│                                                            .beans.UnknownPropertyException)
│                        void  removeVetoableChangeListener( [in]                         string PropertyName,
│                                                            [in] .beans.XVetoableChangeListener aListener
│                                                 ) raises ( .lang.WrappedTargetException,
│                                                            .beans.UnknownPropertyException)
│                        void  setPropertyValue( [in] string aPropertyName,
│                                                [in]    any aValue
│                                     ) raises ( .lang.WrappedTargetException,
│                                                .lang.IllegalArgumentException,
│                                                .beans.PropertyVetoException,
│                                                .beans.UnknownPropertyException)
├─.table.CellAddressConversion
└──(サービスやインターフェイスに属しないプロパティ)
           .table.CellAddress  Address
                       string  PersistentRepresentation
                         long  ReferenceSheet
                       string  UserInterfaceRepresentation
                       string  XLA1Representation

AddressプロパティにCellAddress Structでインデックスアドレスを渡せば、他のプロパティで変換した値が取得できました。

com.sun.star.table.CellRangeAddressConversionはCellRangeAddress StructをAddressに渡せます。
def macro():
 doc = XSCRIPTCONTEXT.getDocument()  # ドキュメントを取得。
 sheets = doc.getSheets()  # シートコレクション。
 sheet = sheets[0]  # 最初のシート。
 sheet.clearContents(511)  # シートのすべてを削除。
 selection = doc.getCurrentSelection()  # 選択しているオブジェクトを取得。  
 # インデックスを文字列アドレスに変換して出力数する。
 props = "ReferenceSheet", "PersistentRepresentation", "UserInterfaceRepresentation", "XLA1Representation"
 if hasattr(selection, "getCellAddress"):  # セルのとき
  celladdressconversion = doc.createInstance("com.sun.star.table.CellAddressConversion")
  celladdressconversion.Address = selection.getCellAddress()
  for i, prop in enumerate(props):
   sheet[i, 0].setString(prop)
   sheet[i, 1].setString(getattr(celladdressconversion, prop))
  sheet[:, :2].getColumns().setPropertyValue("OptimalWidth", True)  # 列幅を最適化する。
 else:
  cellrangeaddressconversion = doc.createInstance("com.sun.star.table.CellRangeAddressConversion") 
  if hasattr(selection, "getRangeAddress"):  # セルではなくセル範囲のとき
   cellrangeaddressconversion.Address = selection.getRangeAddress()
   for i, prop in enumerate(props):
    sheet[i, 0].setString(prop)
    sheet[i, 1].setString(getattr(cellrangeaddressconversion, prop))
   sheet[:, :2].getColumns().setPropertyValue("OptimalWidth", True)  # 列幅を最適化する。
  elif hasattr(selection, "getRangeAddresses"):  # セル範囲コレクションのとき
   cellrangeaddresses = selection.getRangeAddresses()
   for i, prop in enumerate(props):  # A列にプロパティ名を表示。
    sheet[i, 0].setString(prop)
   for j, cellrangeaddress in enumerate(cellrangeaddresses, start=1):
    cellrangeaddressconversion.Address = cellrangeaddress
    for i, prop in enumerate(props):
     sheet[i, j].setString(getattr(cellrangeaddressconversion, prop)) 
   sheet[:, :j+1].getColumns().setPropertyValue("OptimalWidth", True)  # 列幅を最適化する。 
これでインデックスアドレスを文字列アドレスに変換できました。


ReferenceSheet: シートインデックス
PersistentRepresentation: シート名を含んだ文字列アドレス
UserInterfaceRepresentation: シート名を含まない文字列アドレス
XLA1Representation: エクセル形式の文字列アドレス

AbsoluteNameで文字列アドレスを取得する方法

def macro():
 doc = XSCRIPTCONTEXT.getDocument()  # ドキュメントを取得。
 sheets = doc.getSheets()  # シートコレクション。
 sheet = sheets[0]  # 最初のシート。
 sheet.clearContents(511)  # シートのすべてを削除。
 selection = doc.getCurrentSelection()  # 選択しているオブジェクトを取得。      
 # インデックスを文字列アドレスに変換して出力数する。AbsoluteNameを使う方法。
 absolutename = selection.getPropertyValue("AbsoluteName") # セル範囲コレックションは$Sheet1.$A$4:$A$6,$Sheet1.$B$4という形式で返る。
 names = absolutename.replace("$", "").split(",")  # $を削除してセル範囲のリストにする。
 addresses = []
 for name in names:
  addresses.append(name.split(".")[-1])  # シート名を削除する。
 ", ".join(addresses)
 sheet["A1"].setString(", ".join(addresses))
これは変換というより単に文字列の加工をしているだけです。

例えば、セル範囲コレクションは$Sheet1.$A$4:$A$6,$Sheet1.$B$4という形式で返ってくるので、そこから不必要な部分を削除しています。

インデックスからはセル範囲オブジェクトにしてしまえばよいわけです。


セルまたはセル範囲、セル範囲コレクションから文字列アドレスを返す関数

def getRangeAddressesAsString(rng):  # セルまたはセル範囲、セル範囲コレクションから文字列アドレスを返す。
 absolutename = rng.getPropertyValue("AbsoluteName") # セル範囲コレクションは$Sheet1.$A$4:$A$6,$Sheet1.$B$4という形式で返る。
 names = absolutename.replace("$", "").split(",")  # $を削除してセル範囲のリストにする。
 addresses = []  # 出力するアドレスを入れるリスト。
 for name in names:  # 各セル範囲について
  addresses.append(name.split(".")[-1])  # シート名を削除する。
 return ", ".join(addresses)  # コンマでつなげて出力。
セルまたはセル範囲、セル範囲コレクションからシート名を削除した文字列アドレスを返す関数です。

参考にしたサイト


OOoBasic/Calc/address - ...?
セルのアドレス変換のBasicの例。

OOoBasic/Calc/sheetcellranges - ...?
セル範囲コレクションの解説。

次の関連記事:Calc(24)セルカーサーでセル範囲を変更する

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ