Pythonでマクロ:チェックボックス再論

アンケート調査のように多数の質問項目がありそれにチェックを入れるような状況を想定したLibreofficeのマクロをPythonで作る問題である。

以前にはチェック項目が少ないばあいのマクロを紹介した。チェック項目が多くなると手動でチェック欄を設定するが大変になる。

問題はこうだ:

Calcシートサンプル
Calcシートサンプル

画像のようにLibreofficeのCalcのシート上に多くのチェック項目が書かれているとする。これらにチェック欄を設定(フォームやダイアログ上のチェックボックス)することである。

ここでは

ダイアログのマクロでCalcシート上のチェック項目を読み込み必要な個数のチェックボックスをダイアログの中に自動的に作る。ユーザはこのチェックボックスに必要なチェックを入れ「完了」ボタンを押すとその結果がシートに反映される。「リセット」ボタンは全てのチェック欄のリセットに使う。

マクロの実行画面
マクロの実行画面

マクロの本体は長いので最後に載せた。このマクロはシート上のチェック項目の多寡に拘わらず使えるが、チェック項目は多くなったときにはチェックボックスがダイアログ画面をはみ出してしまう。ダイアログに縦スクロールを付けてダイアログ画面を制御できればよいわけであるがこれは未実装である。

【マクロ】

#coding: utf-8>

import uno
import screen_io as ui
import unohelper
from com.sun.star.awt import XActionListener

#「完了」ボタンの処理
class FinishedListener(unohelper.Base, XActionListener):
  def __init__(self, ckbxs, sheet):
    self.ckbxs = ckbxs
    self.sheet=sheet
  def actionPerformed(self, evnt):
    for i,ckbx in enumerate(self.ckbxs):
      if(ckbx.State):
        self.sheet.getCellByPosition(1, i+1 ).String = '○'
      #ui.Print(ckbx.State)
#「リセット」ボタンの処理
class ResetListener(unohelper.Base, XActionListener):
  def __init__(self, ckbxs):
    self.ckbxs = ckbxs
  def actionPerformed(self, evnt):
    for ckbx in self.ckbxs:
      ckbx.State=0

def python_macro_ckbx(*arg):
#
#シート
  doc = XSCRIPTCONTEXT.getDocument()
  sheet = doc.Sheets[0]
  #データのある行数を調べる
  sRange = sheet.getCellRangeByName("A1")
  sCursor=sheet.createCursorByRange(sRange)
  sCursor.collapseToCurrentRegion()
  MaxDataRow = sCursor.Rows.Count-1
  ui.Print(MaxDataRow)
  items=[]
  for  i in range(MaxDataRow):
    item = sheet.getCellByPosition(0, i+1 ).String
    #ui.Print(item)
    items.append(item)
#
#ダイアログ
  ctx = XSCRIPTCONTEXT.getComponentContext()
  smgr = ctx.getServiceManager()
  dialogM = smgr.createInstance('com.sun.star.awt.UnoControlDialogModel')
  # Size of DialogM
  dlgWth = 150
  dlgHgt = 200
  dialogM.Width = dlgWth
  dialogM.Height = dlgHgt
  dialogM.Title = "選択ダイアログ"
#

#コントロールの作成・登録
#ラベル
  lab1 = dialogM.createInstance('com.sun.star.awt.UnoControlFixedTextModel')
  tabIndex = 0
  lab1.Name = 'FixedLabel'
  lab1.TabIndex = tabIndex
  lab1.PositionX = 10
  lab1.PositionY = 10
  lab1.Width = 100
  lab1.Height = 10
  lab1.Label = "選択(複数)してください。"
  lab1.Align = 1					# 0 : Left / 1 : Center / 2 : Right
  lab1.Border = 0
  lab1.TextColor = 0xff0000
  lab1.Enabled = 1
  dialogM.insertByName('FixedLabel', lab1)
#ボタン
  btn1 = dialogM.createInstance('com.sun.star.awt.UnoControlButtonModel')
  tabIndex += 1
  btn1.Name = 'OkBtn'
  btn1.TabIndex = tabIndex
  btn1.PositionX = dlgWth-50
  btn1.PositionY = dlgHgt/2 - 20
  btn1.Width = 32
  btn1.Height = 10
  btn1.Label = '完了'
  btn1.PushButtonType = 0		# 1 : OK
  dialogM.insertByName('OkBtn', btn1)
#
  btn2 = dialogM.createInstance('com.sun.star.awt.UnoControlButtonModel')
  tabIndex += 1
  btn2.Name = 'ResetBtn'
  btn2.TabIndex = tabIndex
  btn2.PositionX = dlgWth-50
  btn2.PositionY = dlgHgt/2 + 20
  btn2.Width = 32
  btn2.Height = 10
  btn2.Label = 'リセット'
  btn2.PushButtonType = 0		# 1 : OK
  dialogM.insertByName('ResetBtn', btn2)
#チェックボックス
  ckbxs=[]
  for i in range(MaxDataRow):
    ckbx = dialogM.createInstance('com.sun.star.awt.UnoControlCheckBoxModel')
    tabIndex += 1
    ckbx.Name = items[i]
    ckbx.TabIndex = tabIndex
    ckbx.PositionX = 10
    ckbx.PositionY = 15+15*i+10
    ckbx.Width = 100
    ckbx.Height = 15
    ckbx.Label = items[i]
    # Dialog Modelの仕様に CheckBox Button1 の仕様を設定
    dialogM.insertByName(items[i], ckbx)
    ckbxs.append(ckbx)

# Create the dialog and set the model
#ダイアログの生成とモデルの登録
  dialog = smgr.createInstance('com.sun.star.awt.UnoControlDialog')
  dialog.setModel(dialogM)
#コントロールの登録
  cmdBtn1 = dialog.getControl('OkBtn')
  cmdBtn2 = dialog.getControl('ResetBtn')
#エヴェント監視(ボタンが押されたとき)
  btn1_listener = FinishedListener(ckbxs, sheet)
  cmdBtn1.addActionListener(btn1_listener)
  btn2_listener = ResetListener(ckbxs)
  cmdBtn2.addActionListener(btn2_listener)
#
#窓の生成そしてこの窓をダイアログ画面として使う
  window = smgr.createInstance('com.sun.star.awt.Toolkit')
  dialog.createPeer(window,None)		# None : OK / none : NG
#
  dialog.execute()
  dialog.dispose()