Calc(65)フレームとコントローラの位置

2018-02-02

旧ブログ

t f B! P L
フレームやコントローラに「位置」はないはずですが、フレームがコンテナウィンドウの親ウィンドウとして、コントローラがサービスを介さないプロパティで位置を取得できることがわかったので、Calc(64)コンテナウィンドウとコンポーネントウィンドウの位置の取得のマクロに追加します。

前の関連記事:Calc(64)コンテナウィンドウとコンポーネントウィンドウの位置の取得


コンテナウィンドウの親ウィンドウのサービスとインターフェイス

def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 tcu = smgr.createInstanceWithContext("pq.Tcu", ctx)  # サービス名か実装名でインスタンス化。
 doc = XSCRIPTCONTEXT.getDocument()
 controller = doc.getCurrentController()  # コントローラの取得。
 frame = controller.getFrame()  # フレームを取得。
 containerwindow = frame.getContainerWindow()  # コンテナウィンドウの取得。
 accessiblecontext = containerwindow.getAccessibleContext()  # コンテナウィンドウのAccessibleContextを取得。
 accessiblecontextparent = accessiblecontext.getAccessibleParent()  # AccessibleParentを取得。
 tcu.wtree(accessiblecontextparent)
コンテナウィンドウの親ウィンドウのサービスとインターフェイス一覧をこれで調べたところコンテナウィンドウと同じサービスとインターフェイスでした。

コンテナウィンドウの親AccessibleContextであるAccessibleParentは定数AccessibleRole=21になっておりフレームに該当しますが、フレームとは違います。

フレームとコントローラの位置を取得するマクロ

from itertools import zip_longest
from com.sun.star.sheet import CellFlags as cf # 定数
from com.sun.star.awt import Point  # Struct
from com.sun.star.util import MeasureUnit
def macro(documentevent=None):  # 引数は文書のイベント駆動用。import pydevd; pydevd.settrace(stdoutToServer=True, stderrToServer=True)
 outputs = [("", "X", "Y", "X onScreen", "Y onScreen"),]  # 出力する行。列数は統一する必要あり。
 doc = XSCRIPTCONTEXT.getDocument()  # 現在開いているドキュメントを取得。
 controller = doc.getCurrentController()  # コントローラの取得。
 frame = controller.getFrame()  # フレームを取得。
 # コンテナウィンドウ
 outputs.append(("ContainerWindow",)) 
 containerwindow = frame.getContainerWindow()
 possize = containerwindow.getPosSize()
 outputs.append(("PosSize", possize.X, possize.Y))
 outputs.append(("AccessibleContext",))
 accessiblecontext = containerwindow.getAccessibleContext()
 location = accessiblecontext.getLocation()
 outputs.append(("Location", location.X, location.Y), )
 locationonscreen = accessiblecontext.getLocationOnScreen()
 outputs.append(("LocationOnScreen", "", "", locationonscreen.X, locationonscreen.Y))
 outputs.append(("",)) 
 # フレームの位置を取得。コンテナウィンドウの親AccessibleContextから取得。
 outputs.append(("Frame",)) 
 accessiblecontextparent = accessiblecontext.getAccessibleParent()
 possize = accessiblecontextparent.getPosSize()
 outputs.append(("PosSize", possize.X, possize.Y))
 accessiblecontext = accessiblecontextparent.getAccessibleContext()
 location = accessiblecontext.getLocation()
 outputs.append(("Location", location.X, location.Y), )
 locationonscreen = accessiblecontext.getLocationOnScreen()
 outputs.append(("LocationOnScreen", "", "", locationonscreen.X, locationonscreen.Y))
 outputs.append(("",)) 
 # コンポーネントウィンドウ
 outputs.append(("ComponentWindow",)) 
 componentwindow = frame.getComponentWindow()
 possize = componentwindow.getPosSize()
 outputs.append(("PosSize", possize.X, possize.Y))
 outputs.append(("AccessibleContext",))
 accessiblecontext = componentwindow.getAccessibleContext()
 location = accessiblecontext.getLocation()
 outputs.append(("Location", location.X, location.Y))
 locationonscreen = accessiblecontext.getLocationOnScreen()
 outputs.append(("LocationOnScreen", "", "", locationonscreen.X, locationonscreen.Y)) 
 outputs.append(("",)) 
 # コントローラ
 outputs.append(("Controller",))
 possize = controller.getPropertyValue("VisibleArea")  # 1/100mmで返ってくる。
 point = componentwindow.convertPointToPixel(Point(possize.X, possize.Y), MeasureUnit.MM_100TH)  # クリックしたセルの左上角の座標。1/100mmをpxに変換。
 outputs.append(("VisibleArea", point.X, point.Y))
 possize = controller.getPropertyValue("VisibleAreaOnScreen")
 outputs.append(("VisibleAreaOnScreen", "", "", possize.X, possize.Y))
 outputs.append(("", "Left", "Top"))
 border = controller.getBorder()
 outputs.append(("Border", border.Left, border.Top))
 # シートに出力。
 sheet = getNewSheet(doc, "Positions")  # 連番名の新規シートの取得。
 rowsToSheet(sheet["A1"], outputs)
 controller.setActiveSheet(sheet)  # 新規シートをアクティブにする。
関数getNewSheet()とrowsToSheet()はCalc(44)ファイルフィルターのオプションダイアログで作成したものを使っています。

24行目でコンテナウィンドウのAccessibleContextからその親を求めています。

そこから取得した位置をフレームの位置として出力しています。

47行目でコントローラのVisibleAreaプロパティからRectangle Structを取得してますが、そのXYの単位は1/100mmになっていたので48行目でピクセルに変換しています。

コントローラのVisibleAreaプロパティもVisibleAreaOnScreenプロパティもIDLリファレンスには載っていないプロパティです(Calc(19)Calcコントローラのサービスとインターフェイス一覧参照)。

WindowPositions2.ods

このマクロを埋め込んだCalcドキュメントです。

フレームとコントローラの位置を取得する


マクロセレクターからドキュメント内のWindowsPositions→macroを実行すると次のような結果が出力されます。

ドキュメントウィンドウを最大化して実行しています。



linuxBean14.04での実行結果です。


Windows10での実行結果です。

画面の左上角を原点とする座標にある点


containerwindow.getAccessibleContext().getAccessibleParent().getAccessibleContext().getLocation()とcontainerwindow.getAccessibleContext().getAccessibleParent().getAccessibleContext().getLocationOnScreen()は同じ点を指していました。

これらはウィンドウの左上角の点に該当します。

しかしWindows10では負の値になっていてどうもおかしいです。

containerwindow.getAccessibleContext().getAccessibleParent().getPosSize()はメニューバーの左上角の点を指していました。

これはコンテナウィンドウの左上角と同じです。

controller.getPropertyValue("VisibleAreaOnScreen")は見えている左上セルの左上角の点を指していました。

シートをスクロールして左上セルが変化しても常に見えている左上セルの左上角の点を指していました。

A1セルの左上角を原点とする座標にある点


controller.getPropertyValue("VisibleArea")は見えている左上セルの左上角のA1セルの左上角に対する相対位置を返します。

単位は1/100mmなので今回のマクロではピクセル単位に変換しています。

72dpiでは1インチ25.4mmでその1/72は約0.353mm=35.3 1/100mmになるので、1/100mmの方が35倍精度が高いのでピクセルに変換すると誤差が生じます。

A1セルから遠ざかるほど誤差が大きくなってきます。

T39セルを左上にあるときcontroller.getPropertyValue("VisibleArea")ではピクセルに変換後はX1562Y649でしたが、A1セルの左上角からの実測はX1502Y647でした。

Y方向は2pxのずれですが、X方向は60pxもずれています。

60pxは72dpiでは21mmになります。

1/100mm単位ではX41301Y17159でした。

XYを入れ替えても同じ値が返ってきたので、数値が大きくなると誤差が大きくなるようです。

次の関連記事:Calc(66)AccessibleSpreadsheetDocumentViewのサービスとインターフェイスの一覧

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ