試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

LibreOffice/OpenOffice.orgのCalcで選択範囲内のセル背景色を1行おきなどに変更するマクロを作成

LibreOffice/OpenOffice.orgのCalc(表計算ソフト)において、(マクロの実行時に)選択されている範囲内のセルの背景色に対して

  • 1行おきに色を付ける
  • 3行のまとまりごとに色を付ける

とするマクロのファイルを作成した。奇数番目の行/まとまりと偶数番目の行/まとまりの色が逆のバージョンも含んでいる。
表によってはこれを用いることで見やすくなる場合がある。1行おきに色を付けるバージョンでは実験的なマルチスレッド版(1行ごとにスレッドを作成して処理する)も用意したが、何か問題がある可能性もある。

(2014/9/8)1行おきに背景色を付けるには、実際にはマクロは用いずにオートフォーマット機能を用いるのが最も手っ取り早い。
準備:

  1. 新規に表計算ドキュメントを作成
  2. A1からD1の範囲を選択
  3. コンテキストメニュー「セルの書式設定」で「背景」タブの「背景色」を「灰色 3」など好きな色にする
  4. A3からD3の範囲の背景色を同様に変更(A1-D1からのコピペでも可)
  5. A1からD4の範囲を選択
  6. メニュー「書式 - オートフォーマット」でダイアログを開く
  7. 「追加」ボタンを押して「シマシマ」など好きな名前を付けた後「OK」を押してダイアログを閉じる

この後でA1からD4の範囲は消してよく、上記の準備は一度だけ行えばアプリケーションの設定として保持される(毎回行う必要はない)。シマシマにしたい任意の範囲を選択後「書式 - オートフォーマット」でダイアログを開いて先程付けた名前の項目が選択された状態で「OK」を押すと背景色が付く
以下、以前の内容となる。


下のスクリーンショットは使用例となる。

マクロ実行前

マクロ「m01_set_cell_bg」の実行後

動作に必要なパッケージ,スクリプトの配置場所などの説明はここでは行わない(「メールマガジン:LibreOfficeのマクロの言語にPythonを使用する際の環境について(2012年5月時点)」の記事を参照)。
注意点として、マクロを実行すると行の高さが変化する場合があるが、マクロ実行後、選択範囲はそのままで行番号部分(表の一番左)のコンテキストメニュー項目「行の高さ」を選択し、出てくるダイアログの「標準値」にチェックを入れて「OK」を押すと標準の高さになる。
なお、セルの背景色として使用される色についてはファイルの最下部にある変数で変更できるようにしてある。初期値は「0xeaebec」と「-1(塗りつぶしなし)」とした(上のスクリーンショットのように、白と灰色のシマシマ模様になる)。

[任意]ファイル名: calc_set_cell_bg.py ライセンス: GPL-3 (or lator) エンコーディング: UTF-8

# -*- mode: python; coding: utf-8; python-indent: 2 -*-

# OpenOffice.org/LibreOffice Calcにて選択されたセル範囲の背景色を
# 1行もしくは3行のまとまりごとに変えるPythonマクロ
#
# Copyright (C) 2012 kakurasan
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

from com.sun.star.awt.MessageBoxButtons import BUTTONS_OK
from com.sun.star.awt import Rectangle
import threading


class NotOooCalcException (Exception):
  """
  Calcの中でマクロが呼ばれなかったときに発生する例外
  """
  pass

class Util:
  @staticmethod
  def RGB (red, green, blue):
    """
    赤,緑,青の各成分を0から255(0xff)までの範囲で引数として受け取る形で
    色の値を計算して返す
    """
    if red > 0xff:
      red = 0xff
    elif red < 0:
      red = 0
    if green > 0xff:
      green = 0xff
    elif green < 0:
      green = 0
    if blue > 0xff:
      blue = 0xff
    elif blue < 0:
      blue = 0
    return red * 0x010000 + green * 0x000100 + blue * 0x000001
  @staticmethod
  def th_set_bg (i, selection):
    """
    背景色を設定するスレッド内の処理
    マルチスレッド版向け
    """
    range_addr = selection.getRangeAddress ()
    cell = selection.getCellRangeByPosition (0, i, range_addr.EndColumn - range_addr.StartColumn, i)
    if i % 2:
      cell.CellBackColor = Config.cell_color[0]
    else:
      cell.CellBackColor = Config.cell_color[1]
  @staticmethod
  def th_set_bg_reverse (i, selection):
    """
    背景色を設定するスレッド内の処理
    マルチスレッド版向け
    奇数行目と偶数行目の色が逆のバージョン
    """
    range_addr = selection.getRangeAddress ()
    cell = selection.getCellRangeByPosition (0, i, range_addr.EndColumn - range_addr.StartColumn, i)
    if i % 2:
      cell.CellBackColor = Config.cell_color[1]
    else:
      cell.CellBackColor = Config.cell_color[0]

class Bridge (object):
  """
  PythonとOOo/LOの仲立ちをする各種オブジェクトと
  それを用いた幾つかの操作を提供
  """
  def __init__ (self):
    """
    各種オブジェクトの取得
    """
    self._doc = XSCRIPTCONTEXT.getDocument ()
    self._win = XSCRIPTCONTEXT.getDesktop ().CurrentFrame.ContainerWindow
    self._tk = self._win.Toolkit
  def run_errordialog (self, title='', message=''):
    """
    エラーダイアログを表示する
    """
    mb = self._tk.createMessageBox (self._win, Rectangle (), 'errorbox', BUTTONS_OK, title, message)
    mb.execute ()
    mb.dispose ()

class OooCalc (Bridge):
  """
  OOo/LO Calcの制御
  BridgeをベースにCalcの選択範囲を追加したもの
  """
  def __init__ (self):
    Bridge.__init__ (self)
    if not self._doc.supportsService ('com.sun.star.sheet.SpreadsheetDocument'):
      self.run_errordialog (title='エラー', message='このマクロはCalcの中で実行してください')
      raise NotOooCalcException ()
  @property
  def selection (self): return self._doc.CurrentSelection


def m01_set_cell_bg ():
  """\
選択範囲内のセル背景色を1行おきに変更
初期設定では選択範囲が1行だとその範囲を塗り潰しなしにする使い方もできる"""
  try:
    calc = OooCalc ()
  except:
    return
  range_addr = calc.selection.RangeAddress
  n_cells = (range_addr.EndRow - range_addr.StartRow + 1) * (range_addr.EndColumn - range_addr.StartColumn + 1)
  if n_cells > Config.max_cells:
    calc.run_errordialog (title='エラー', message='指定された範囲({0}セル)が広すぎます'.format (n_cells))
    return
  for i in range (range_addr.EndRow - range_addr.StartRow + 1):
    cell = calc.selection.getCellRangeByPosition (0, i, range_addr.EndColumn - range_addr.StartColumn, i)
    if i % 2:
      cell.CellBackColor = Config.cell_color[0]
    else:
      cell.CellBackColor = Config.cell_color[1]

def m02_set_cell_bg_reverse ():
  """\
選択範囲内のセル背景色を1行おきに変更
奇数行目と偶数行目の色が逆のバージョン"""
  try:
    calc = OooCalc ()
  except:
    return
  range_addr = calc.selection.RangeAddress
  n_cells = (range_addr.EndRow - range_addr.StartRow + 1) * (range_addr.EndColumn - range_addr.StartColumn + 1)
  if n_cells > Config.max_cells:
    calc.run_errordialog (title='エラー', message='指定された範囲({0}セル)が広すぎます'.format (n_cells))
    return
  for i in range (range_addr.EndRow - range_addr.StartRow + 1):
    cell = calc.selection.getCellRangeByPosition (0, i, range_addr.EndColumn - range_addr.StartColumn, i)
    if i % 2:
      cell.CellBackColor = Config.cell_color[1]
    else:
      cell.CellBackColor = Config.cell_color[0]

def m03_set_cell_bg_3 ():
  """\
選択範囲内のセル背景色を3行のまとまりごとに変更
初期設定では選択範囲が3行以内だとその範囲を塗り潰しなしにする使い方もできる"""
  try:
    calc = OooCalc ()
  except:
    return
  range_addr = calc.selection.RangeAddress
  n_cells = (range_addr.EndRow - range_addr.StartRow + 1) * (range_addr.EndColumn - range_addr.StartColumn + 1)
  if n_cells > Config.max_cells:
    calc.run_errordialog (title='エラー', message='指定された範囲({0}セル)が広すぎます'.format (n_cells))
    return
  for i in range (range_addr.EndRow - range_addr.StartRow + 1):
    cell = calc.selection.getCellRangeByPosition (0, i, range_addr.EndColumn - range_addr.StartColumn, i)
    if (i / 3) % 2:
      cell.CellBackColor = Config.cell_color[0]
    else:
      cell.CellBackColor = Config.cell_color[1]

def m04_set_cell_bg_3_reverse ():
  """\
選択範囲内のセル背景色を3行のまとまりごとに変更
奇数番目のまとまりと偶数番目のまとまりの色が逆のバージョン"""
  try:
    calc = OooCalc ()
  except:
    return
  range_addr = calc.selection.RangeAddress
  n_cells = (range_addr.EndRow - range_addr.StartRow + 1) * (range_addr.EndColumn - range_addr.StartColumn + 1)
  if n_cells > Config.max_cells:
    calc.run_errordialog (title='エラー', message='指定された範囲({0}セル)が広すぎます'.format (n_cells))
    return
  for i in range (range_addr.EndRow - range_addr.StartRow + 1):
    cell = calc.selection.getCellRangeByPosition (0, i, range_addr.EndColumn - range_addr.StartColumn, i)
    if (i / 3) % 2:
      cell.CellBackColor = Config.cell_color[1]
    else:
      cell.CellBackColor = Config.cell_color[0]

def m05_set_cell_bg_mt ():
  """\
選択範囲内のセル背景色を1行おきに変更
初期設定では選択範囲が1行だとその範囲を塗り潰しなしにする使い方もできる

実験的なマルチスレッド版(1行1スレッド)"""
  try:
    calc = OooCalc ()
  except:
    return
  range_addr = calc.selection.RangeAddress
  n_cells = (range_addr.EndRow - range_addr.StartRow + 1) * (range_addr.EndColumn - range_addr.StartColumn + 1)
  if n_cells > Config.max_cells:
    calc.run_errordialog (title='エラー', message='指定された範囲({0}セル)が広すぎます'.format (n_cells))
    return
  for i in range (range_addr.EndRow - range_addr.StartRow + 1):
    threading.Thread (target=Util.th_set_bg, args=(i, calc.selection)).start ()

def m06_set_cell_bg_reverse_mt ():
  """\
選択範囲内のセル背景色を1行おきに変更
奇数行目と偶数行目の色が逆のバージョン

実験的なマルチスレッド版(1行1スレッド)"""
  try:
    calc = OooCalc ()
  except:
    return
  range_addr = calc.selection.RangeAddress
  n_cells = (range_addr.EndRow - range_addr.StartRow + 1) * (range_addr.EndColumn - range_addr.StartColumn + 1)
  if n_cells > Config.max_cells:
    calc.run_errordialog (title='エラー', message='指定された範囲({0}セル)が広すぎます'.format (n_cells))
    return
  for i in range (range_addr.EndRow - range_addr.StartRow + 1):
    threading.Thread (target=Util.th_set_bg_reverse, args=(i, calc.selection)).start ()


#  ------------------------------  以下設定用  ------------------------------  #


class Config:
  """
  設定項目
  """
  # 処理可能なセル数の上限
  # (マクロによっては多く選択しすぎた場合に長時間固まるため制限をかける)
  # 型:整数値
  max_cells = 131072

  # セルの背景色の組み合わせ
  # 「0x[赤成分][緑成分][青成分]」形式で色を指定(各成分は0からffまで)
  # 負の値にすると背景色なしになる
  # 型:整数値2つから成るタプル 値は「Util.RGB([赤成分],[緑成分],[青成分])」でも可
  cell_color = (0xeaebec, -1)
  #cell_color = (Util.RGB (234, 235, 236), -1)

関連記事:

使用したバージョン: