前の関連記事:LibreOffice5(135)スクロールバーコントロールのサービスとインターフェイスの一覧
Map AppFont (ma)とピクセルと1/100mmの変換をするマクロ
import unohelper # オートメーションには必須(必須なのはuno)。 from com.sun.star.style.VerticalAlignment import MIDDLE from com.sun.star.awt import XActionListener from com.sun.star.awt import Point # Struct from com.sun.star.util import MeasureUnit def macro(documentevent=None): # 引数は文書のイベント駆動用。 ctx = XSCRIPTCONTEXT.getComponentContext() # コンポーネントコンテクストの取得。 smgr = ctx.getServiceManager() # サービスマネージャーの取得。 doc = XSCRIPTCONTEXT.getDocument() # マクロを起動した時のドキュメントのモデルを取得。 docframe = doc.getCurrentController().getFrame() # モデル→コントローラ→フレーム、でドキュメントのフレームを取得。 docwindow = docframe.getContainerWindow() # ドキュメントのウィンドウ(コンテナウィンドウ=ピア)を取得。 toolkit = docwindow.getToolkit() # ピアからツールキットを取得。 m = 6 # コントロール間の間隔 nameX = {"PositionX": m, "Width": 10, "Height": 12, "Label": "X: ", "NoLabel": True, "Align": 2, "VerticalAlign": MIDDLE} # 名前Xの共通プロパティ。 numX = {"PositionX": nameX["PositionX"]+nameX["Width"], "Width": 40, "Height": nameX["Height"], "VerticalAlign": MIDDLE} # X値入力欄の共通プロパティ。 unitX = {"PositionX": numX["PositionX"]+numX["Width"], "Width": 32, "Height": nameX["Height"], "NoLabel": True, "VerticalAlign": MIDDLE} # 単位の共通プロパティ。 nameY, numY, unitY = nameX.copy(), numX.copy(), unitX.copy() # コントロールのプロパティの辞書をコピーする。 nameY["PositionX"] = unitX["PositionX"] + unitX["Width"] # 左隣のコントロールのPositionXと幅からPositionXを算出。 nameY["Label"] = "Y: " numY["PositionX"] = nameY["PositionX"] + nameY["Width"] unitY["PositionX"] = numY["PositionX"] + numY["Width"] controls = nameX, numX, unitX, nameY, numY, unitY # 1行に表示するコントロールのタプル。 button = {"Height": nameX["Height"]+2, "PushButtonType": 0} # ボタンの共通プロパティ。PushButtonTypeの値はEnumではエラーになる。 controldialog = {"PositionX": 100, "PositionY": 40, "Width": unitY["PositionX"]+unitY["Width"]+m, "Title": "Unit Converter", "Name": "ConvertUnits", "Step": 0, "Moveable": True} # コントロールダイアログのプロパティ。幅は右端のコントロールから取得。高さは最後に設定する。 dialog, addControl = dialogCreator(ctx, smgr, controldialog) # 1行目 for c in controls: c["PositionY"] = m nameX, numX, unitX, nameY, numY, unitY = [c.copy() for c in controls] # addControlに渡した辞書は変更されるのでコピーを渡す。 unitX["Label"] = unitY["Label"] = "px" addControl("FixedText", nameX) addControl("Edit", numX) addControl("FixedText", unitX) addControl("FixedText", nameY) addControl("Edit", numY) addControl("FixedText", unitY) # 2行目 y = unitY["PositionY"] + unitY["Height"] + m for c in controls: c["PositionY"] = y nameX, numX, unitX, nameY, numY, unitY = [c.copy() for c in controls] # addControlに渡した辞書は変更されるのでコピーを渡す。 unitX["Label"] = unitY["Label"] = "ma" addControl("FixedText", nameX) addControl("Edit", numX) addControl("FixedText", unitX) addControl("FixedText", nameY) addControl("Edit", numY) addControl("FixedText", unitY) # 3行目 y = unitY["PositionY"] + unitY["Height"] + m for c in controls: c["PositionY"] = y nameX, numX, unitX, nameY, numY, unitY = [c.copy() for c in controls] # addControlに渡した辞書は変更されるのでコピーを渡す。 unitX["Label"] = unitY["Label"] = "1/100mm" addControl("FixedText", nameX) addControl("Edit", numX) addControl("FixedText", unitX) addControl("FixedText", nameY) addControl("Edit", numY) addControl("FixedText", unitY) # 4行目 y = unitY["PositionY"] + unitY["Height"] + m message = {"Name": "Message", "PositionX": m, "PositionY": y, "Width": controldialog["Width"]-m*2, "Height": 12, "Label": "Pass any one of units and push Convert", "NoLabel": True} addControl("FixedText", message) # 5行目 button1, button2 = button.copy(), button.copy() button1["PositionY"] = button2["PositionY"] = message["PositionY"] + message["Height"] + m button1["Width"] = 40 button1["Label"] = "Con~vert" button2["Width"] = 30 button2["Label"] = "~Clear" button2["PositionX"] = unitY["PositionX"] + unitY["Width"] - button2["Width"] button1["PositionX"] = button2["PositionX"] - m - button1["Width"] actionlistener = ActionListener() addControl("Button", button1, {"setActionCommand": "convert" ,"addActionListener": actionlistener}) addControl("Button", button2, {"setActionCommand": "clear" ,"addActionListener": actionlistener}) dialog.getModel().setPropertyValue("Height", button1["PositionY"]+button1["Height"]+m) dialog.createPeer(toolkit, docwindow) # ダイアログを描画。親ウィンドウを渡す。ノンモダルダイアログのときはNone(デスクトップ)ではフリーズする。Stepを使うときはRoadmap以外のコントロールが追加された後にピアを作成しないとStepが重なって表示される。 # モダルダイアログにする。フレームに追加するとエラーになる。 dialog.execute() dialog.dispose() class ActionListener(unohelper.Base, XActionListener): def actionPerformed(self, actionevent): cmd = actionevent.ActionCommand source = actionevent.Source # ボタンコントロールが返る。 context = source.getContext() # コントロールダイアログが返ってくる。 message = context.getControl("Message") if cmd == "convert": edits = [context.getControl("Edit{}".format(i)) for i in range(1, 7)] edittxts = [e.getText() for e in edits] if ["".join((edittxts[i], edittxts[i+1])) for i in range(0, 6, 2)].count("")==2: # 2行だけテキストボックスが空文字の時。 pxToma, pxTomm, maTopx, maTomm, mmTopx, mmToma = createConverters(context) edit11, edit12, edit21, edit22, edit31, edit32 = edits for i in range(0, 6, 2): # 各行について。 x, y = edittxts[i], edittxts[i+1] if x or y: # いずれかは空文字でない時。 x = int(x) if x.isdigit() else 0 # テキストボックスの文字が数字の時は整数に変換。数字でなければ0にする。 y = int(y) if y.isdigit() else 0 if i==0: # 1行目に数字が入力されている時。 edit11.setText(x) edit12.setText(y) maX, maY = pxToma(x, y) edit21.setText(maX) edit22.setText(maY) mmX, mmY = pxTomm(x, y) edit31.setText(mmX) edit32.setText(mmY) u = "px" elif i==2: # 2行目に数字が入力されている時。 pxX, pxY = maTopx(x, y) edit11.setText(pxX) edit12.setText(pxY) edit21.setText(x) edit22.setText(y) mmX, mmY = maTomm(x, y) edit31.setText(mmX) edit32.setText(mmY) u = "ma" elif i==4: # 3行目に数字が入力されている時。 pxX, pxY = mmTopx(x, y) edit11.setText(pxX) edit12.setText(pxY) maX, maY = mmToma(x, y) edit21.setText(maX) edit22.setText(maY) edit31.setText(x) edit32.setText(y) u = "mm" message.setText("{} converted to other unit".format(u)) message.getModel().setPropertyValue("TextColor", None) return else: # パラメーターが1つだけでない時。 message.setText("Too many inputs or no input") message.getModel().setPropertyValue("TextColor", 0xFF0000) elif cmd == "clear": [context.getControl("Edit{}".format(i)).setText("") for i in range(1, 7)] message.setText("Pass any one of units and push Convert") message.getModel().setPropertyValue("TextColor", None) def disposing(self, eventobject): eventobject.Source.removeActionListener(self) def createConverters(window): def maTopx(x, y): # maをpxに変換する。 point = window.convertPointToPixel(Point(X=x, Y=y), MeasureUnit.APPFONT) return point.X, point.Y def mmTopx(x, y): # 1/100mmをpxに変換する。 point = window.convertPointToPixel(Point(X=x, Y=y), MeasureUnit.MM_100TH) return point.X, point.Y def pxToma(x, y): # pxをmaに変換する。 point = window.convertPointToLogic(Point(X=x, Y=y), MeasureUnit.APPFONT) return point.X, point.Y def pxTomm(x, y): # pxをmmに変換する。 point = window.convertPointToLogic(Point(X=x, Y=y), MeasureUnit.MM_100TH) return point.X, point.Y def mmToma(x, y): # 1/100mmをmaに変換する。 return pxToma(*mmTopx(x, y)) def maTomm(x, y): # maをmmに変換する。 return pxTomm(*maTopx(x, y)) return pxToma, pxTomm, maTopx, maTomm, mmTopx, mmTomaLibreOffice5(69)Javaの例:GUIをPythonにする その2のdialogCreator()は省略しています。
ダイアログコントロールやコントロールの位置や大きさはすべてma単位で設定しています。
コントロールの位置は隣にあるコントロールの位置と大きさから取得するようにし、ダイアログコントロールの大きさは表示するコントロールから算出しています。
unitconverter.ods
このマクロをCalcドキュメントに埋め込んだものです。
unitconverter.odsで単位を変換する
unitconverter.odsを開くとモーダルダイアログが出現します。
上からピクセル、Map AppFont、1/100mmの単位の数値の入力欄になっています。
いずれか一つの単位の枠のみ入力して「Convert」ボタンをクリックすると空欄になっている、他の単位の欄に変換後の値が出力されます。
VirtualVoxのゲストOSのlinuxBean14.04で100maを変換してみると上図のようになりました。
X方向では100maは208pxに、Y方向では100maは150pxに変換されています。
システムフォントの高さの1/8、幅の1/4が1maなので、変換時のシステムフォントの縦横比は約3:2とわかります(LibreOffice5(58)モードレスダイアログの例をPythonに翻訳する:その4)。
LibreOffice5(62)Map AppFont (ma)とピクセルでxdlファイルで設定した値でmaとpxを比較した値とは少し結果が異なりますが、その原因はよくわかりませんでした。
オプションダイアログだから違うのか、このときのシステムフォントの値が違うのかもしれません。
とりあえず実行中のダイアログを実測してみるとmaとpxの変換は値通りでした。
1/100mmでは実測よりも少し大きい結果となりましたが、どうしてLibreOfficeが画面の実寸を知るのか不思議です。
(2018.2.2追記。1/100mmをpxに変換するときも結構誤差がありました。Calc(65)フレームとコントローラの位置参照。)
Windows10で実行するとX方向もY方向も同じ値になりました。
つまりWindows10のシステムフォントの縦横比は2:1ということになります。
このマクロのダイアログ自身maで設定しているので、Windows10ではシステムフォントの縦横比を反映して、linuxBean14.04に比べてWindows10では幅が狭くなって高さは高くなっていることがわかります。
Windows10でシステムフォントを変更する方法はわかりませんでした。
0 件のコメント:
コメントを投稿