INDEX  Home

VBAとOOo Basicの互換性「オブジェクトの取得」

この記事はUNIX USER誌(株式会社ソフトバンクパブリッシング)の2004年11月号に掲載したものを、同誌編集部の許可を得て転載しています。HTML化するにあた り、若干手を加えてありますので、掲載記事とまったく同じ内容ではありません。 この記事の内容に関しては、もっぱら松井幹彦が責任を負っ ています。

OpenOffice.org Basicに関しては「OpenOffice.org Basic研究室」もご覧ください


UNIX USER 11月号 OpenOffice.org研究室

VBAOpenOffice.org Basicの互換性:オブジェクトの取得」


こんにちは。松井幹彦です。「OpenOffice.org互換性研究室」へようこそ。前号からVBAOpenOffice.org Basicの互換性について取り上げています。前回は、プロシージャの呼び出しなど、フロー制御の部分をみていきました。引き続いて今回は、オブジェクトを取得して操作する部分についての互換性を見ていきましょう。


  1. オブジェクトを取得する手順の違い


前月に引き続いて今月も「Excel VBA 実用サンプルコレクション」を活用することにします。この書籍にはExcel VBAを使ったサンプルコードが800点ほど掲載されています。それぞれのコードは、実用的な単位できれいに整理してとめられています。もちろん、OpenOffice.org Basicのことはまったく意識されていませんから、マクロの互換性のチェックにはぴったりというわけです。


まず、オブジェクトを取得する手順の違いを示す分かりやすい例として「セルを含む行/列の表示/非表示を設定する(C-031)」というサンプルコードを取り上げます。

VBAのコードはリスト1のようになっています。

【リスト1】−−Excel


Option Explicit
Sub C_Sample031()
    Dim myRng As Range
    Set myRng = Range("A1") '任意のセル
    myRng.EntireRow.Hidden = True '行の非表示
    myRng.EntireColumn.Hidden = True '列の非表示
    MsgBox "行列を非表示にしました。再表示します"
    myRng.EntireRow.Hidden = False '行の表示
    myRng.EntireColumn.Hidden = False '列の表示
    Set myRng = Nothing 'オブジェクトの解放
End Sub
 

念のために内容の概略を見ておきましょう。まず、Range型の変数を宣言し、「A1セル」オブジェクトへの参照を格納します。次に、EntireRowプロパティおよびEntireColumnプロパティを使って、行全体および列全体を取得し、そのHiddenプロパティを操作しています。いったん非表示にして、MsgBoxで確認した後に、再表示します。


では、互換性のチェックおよびポーティング作業に入りましょう。

このマクロを含むExcelファイルをCalcで開きます。そして、「ツール」−「マクロ」コマンドでOpenOffice.org Basic IDEを起動して、コードを編集します。

この作業の前提として、OpenOffice.orgのオプション設定で、「VBA属性」パネルの「Microsoft ExcelBasic Codeの読み込み」チェックボックスがオンになっている必要があります。ここまでの手順の詳細については、前号を参照してください。

さて、編集後のコードをリスト2に示します。必要な編集処理の内容を順番に解説していきましょう。


  1. オブジェクト型変数の宣言: VBAではRangeという固有オブジェクト型の変数を宣言しています。OpenOffice.org Basicでは、このような事前バインディングは使用できません。次のように総称オブジェクト型変数に変更します。

----------------------

Dim myRng As Range

Dim myRng As Object

----------------------


  1. オブジェクトへの参照の取得: VBAではRange("A1")という指定で「アクティブブック」内の「カレントワークシート」上の「A1」セルを取得できます。しかし、OpenOffice.org Basicでは、オブジェクト・コンテナを順番にたどっていく必要があります。次のようになります(OpenOffice.org BasicではSetステートメントを省略しています)。

----------------------

Set myRng = Range("A1")

myRng = ThisComponent.Sheets(0).getCellRangeByName("A1")

----------------------


  1. ドキュメントの取得: 上の例ではThisComponentステートメントでドキュメントオブジェクトを取得しています。この部分について解説を加えておきましょう。ThisComponentは、実行中のBasicコードが含まれているドキュメントへのショートカットです。OpenOffice.org Basicには、もうひとつStarDesktopオブジェクトのCurrentComponentプロパティを使ってドキュメントにアクセスする方法があります。こちらは、Excel VBAApplication.ActiveWorkBookにほぼ相当します。ただし、この方法(StarDesktop.CurrentComponent)を使った場合には、OpenOffice.org Basic IDEの中でサンプルコードを走らせることができないという不都合が生じます(IDEの中では、StarDesktopオブジェクトのCurrentComponentプロパティはIDE自身を表すためです)。したがって、IDE内での作業をVBEと同じようにおこなうときは、 ThisComponentステートメントを使う方がよいでしょう。


  1. ワークシート番号の指定: OpenOffice.org Basicでは、インデックスの開始値は、常に「0」です。この点にはくれぐれも注意が必要です。上のコードにおけるSheets(0)は、1枚目のワークシート、すなわち「Sheet1」を表します。


  1. RowsおよびColumnsオブジェクトの取得: VBAではEntireRowEntireColumnプロパティを使って、行全体および列全体を取得しています。これに相当するのはRowsおよびColumnsプロパティです。

----------------------

myRng.EntireRow.Hidden = True

myRng.EntireColumn.Hidden = True

myRng.Rows.IsVisible = False

myRng.Columns.IsVisible = False

----------------------


  1. 表示/非表示の設定: Hiddenプロパティに対応するOpenOffice.org Basicの機能はIsVisibleプロパティです。したがってTrueの指定はFalseに置き換える必要があります。


以上でポーティングが完了です。それぞれ対応するオブジェクト、対応するプロパティに置き換えていくだけで終了できます。なれてしまえば、ごく簡単な作業です。次のような結果となります。


【リスト2】−−Calc


Option Explicit
Sub C_Sample031()
    Dim myRng As Object
    myRng = ThisComponent.Sheets(0).getCellRangeByName("A1") '任意のセル
    myRng.Columns.IsVisible = False '行の非表示
    myRng.Rows.IsVisible = False '列の非表示
    MsgBox "行列を非表示にしました。再表示します"
    myRng.Columns.IsVisible = True '行の表示
    myRng.Rows.IsVisible = True '列の表示
    Set myRng = Nothing 'オブジェクトの解放
End Sub
 


OpenOffice.org Basicにおけるオブジェクトの取り扱いについて、ポイントを2つほど挙げておきましょう。



【リスト3】−−Calc


    ……
    Dim oDocument As Object
    Dim oSheet As Object
    Dim myRng As Object
    oDocument = ThisComponent
    oSheet = oDocument.Sheets(0)
    myRng = oSheet.getCellRangeByName("A1")
    ……
 


  1. セルを操作するときの問題点


前項では、オブジェクト取得の基本例として、ワークシートの「行」「列」へのアクセスを取り上げました。今度は「セル」にアクセスしてみましょう。「セル」へのアクセスでは、VBAOpenOffice.org Basicで基本的な違いがあります。そのことを取り上げる前に、まず共通している部分を見ておきましょう。


次のサンプルコードも「Excel VBAサンプルコレクション」から取り上げます。指定のセルにデータを入力し、入力したデータを取得してダイアログに表示します。このプロシージャのポイントは、入力データとして「"2002"」という「文字列」を設定していることです。Excelではセルに「標準」書式が設定されていると、「文字列」として数字を入力しても、「数値」として格納されます。このことについては、あとで詳しく説明しますので、頭に置いておいてください。


リスト4が元のVBAのコードです。リスト5OpenOffice.org Basicにポーティングしたものです。


【リスト4】−−Excel


Option Explicit
Sub B_Sample001()
    Dim myRng As Range
    Set myRng = Range("A1") '任意のセル
    With myRng
        .Clear 'セルのクリアー
        .Value = "2002" '値を設定
        '準備ここまで
        MsgBox "セル" & .Address & "の値は " & .Value & " です"
    End With
    Set myRng = Nothing 'オブジェクトの解放
End Sub
 


 

【リスト5】−−Calc


Option Explicit
Sub C_Sample031()
    Dim oDocument As Object
    Dim oSheet As Object
    Dim myRng As Object
    Dim oCellName As String
    oDocument = ThisComponent
    oSheet = oDocument.Sheets(0)
    oCellName = "A1"
    myRng = oSheet.getCellRangeByName(oCellName) '任意のセル
    With myRng
        .clearContents(511) 'セルのクリアー
        .Value = "2002" '値を設定
        '準備ここまで
        MsgBox "セル" & oCellName & "の値は " & .Value & " です"
    End With
    Set myRng = Nothing 'オブジェクトの解放
End Sub
 


リスト5には、全体の処理手順の部分で大きな修正が1カ所あります。


  1. セルのアドレスを変数に格納する: 「セル」オブジェクトを取得するにあたって、リスト4Excel VBA)では、A1セルへの参照をRange"A1")という具合に、アドレスを直接指定しています。しかし、リスト5OpenOffice.org Basic)の方では、セルのアドレスをいったん文字列型の変数に格納しています。その理由は、OpenOffice.org Basicでは、「セル」オブジェクトのアドレスをA1形式で再取得するのが難しいからです。そのことについては、このあとで詳しく解説します。


この部分を除けば、コードの内容はほとんど変わりません。すでに前項で解説した範囲の修正がほとんどです。2点ほど解説を加えておきましょう。


  1. セル内容のクリア: このサンプルコードでは、セルに値を設定する前にセルの内容をクリアしています。OpenOffice.org Basicでは内容のクリアはclearContentsメソッドを使います。このclearContentsメッソドでは削除するデータの内容を表1のフラグで指定します。定数を加算することによって、同時に複数のデータ内容を削除することも可能です。ここでは「511」のフラグをたてることによって、書式設定なども含めたすべてのデータ内容をいっぺんに削除しています。

フラグ 内容
1 VALUE 日付や時刻として書式設定されていない数値
2 DATETIME 日付や時刻として書式設定されている数値
4 STRING 文字列
8 ANNOTATION セルに付けられたコメント
16 FORMULA 計算式
32 HARDATTR セルに直接指定した書式
64 STYLES 間接的に設定した書式
128 OBJECTS セルに配置された図形描画オブジェクト
256 EDITATTR セル内の一部のテキストに対してのみ施された書式


  1. Valueプロパティの設定: もうひとつのポイントは、セルへのデータ値の設定です。VBAOpenOffice.org Basicも、ともにValueプロパティを設定しています。2002という数字を " " で囲むことによって文字列として入力していますが、この文字列「2002」は、どちらのケースでも、数値データとしてセルに入力されます。


上記の3.について、さらに説明を加えておきましょう。ここは、とても重要なところです。上で述べたように、コードの内容も同じで、その結果として得られるものも同じです。しかし、実は、それは‘たまたま’なのです。VBAOpenOffice.org Basicでは、次のような処理の違いがあるからです。

まず、Excelですが、セルへのデータ入力はValueプロパティを使います。文字データを入力するときはその値を " " で囲みます。数値を入力するときは " " で囲まずに入力します。桁区切りスタイルや日付、時刻などは " " で囲んで入力します。それというのも、セルの書式が「標準」の場合は、数値データとみなすことのできる文字列データを、数値としてとり扱う機能があるからです。この機能を使って、ちょうど手作業でセルにデータを入力するのと同じ要領でデータを設定できます。

それに対してOpenOffice.org Basicでは、設定するデータの種類に応じてプロパティを使い分けます。文字列の場合はStringプロパティ、数式の場合はValueプロパティを使います。

ここでは、たまたまValueプロパティだったので、どちらのケースも文字列として入力した「"2002"」というデータが数値データとして取り込まれました。では、入力データを「"東京"」に変更したら結果はどうなるでしょうか。

いま述べたように、VBAにはStringプロパティはありません。文字列も数値もValueプロパティを使います。ですから、適切に文字列として入力できます。それに対してOpenOffice.org Basicでは、Valueプロパティに文字データが入力されるため0(ゼロ)の数値として入力されます(注:一般に、VBAでは数値以外の文字列を数値として代入しようとするとエラーとなりますが、OpenOffice.orgでは0という値として処理されます)。

ちなみに、VBAでは、RangeオブジェクトのValue プロパティは省略することも可能です。それは、このようにValueプロパティに汎用性があるからです。OpenOffice.orgでは、そのような省略はできません。

なお、念のために付け加えておきますが、数式を設定するときは、VBAOpenOffice.org Basicも、ともにFormulaプロパティを使います。


  1. 選択範囲を取得し、A1形式で表示する


では「セル」オブジェクトのアドレスの取得に話を進めましょう。リスト6は、「Excel VBAサンプルマクロ集」の 第1章の1ページ目 に掲載されているサンプルです。「基本オブジェクトを取得する」というセクションの最初のサンプルで、現在選択されているセルのアドレスをダイアログに表示するという単純なものです。

このサンプルは、この本の著者が、最も単純で最も基本的な例として挙げたものと言って良いでしょう。しかし、このサンプルコードには、Excel VBAOpenOffice.org Basicの違いが凝縮されています。


【リスト6】−−Excel


Option Explicit
Sub A_Sample001()
    Dim myRng As Range
    If TypeName(Selection) = "Range" Then
        Set myRng = Selection
        MsgBox myRng.Address
    Else
        MsgBox "セルが選択されていません"
    End If
    Set myRng = Nothing 'オブジェクトの解放
End Sub
 


処理内容にざっと目を通しておきましょう。このサンプルでは、たとえば図形オブジェクトなどが選択されている場合には、「セルが選択されていません」というメッセージを表示するように、あらかじめ場合分けをしています。その上でRange型の変数に選択オブジェクトへの参照を格納し、そのアドレスを表示します。

同じ処理をOpenOffice.org Basicに置き換えたものをリスト7に示します。


【リスト7】−−Calc


Sub A_Sample001()
    Dim oDocument As Object
    Dim myRng As object
    Dim SC As String
    Dim EC As String
    Dim SR As String
    Dim ER As String
    oDocument = ThisComponent
    myRng = oDocument.CurrentSelection
    If myRng.ImplementationName = "ScCellObj" Then '1セルの場合
        With myRng.getCellAddress
            SC = .Column
            SC = ColumnName ( SC ) 'A1形式のセル番地に変換
            SR = .Row + 1
            MsgBox SC & SR
        End With
    ElseIf myRng.getImplementationName = "ScCellRangeObj" Then 'セル範囲の場合
        With myRng.getRangeAddress
            SC = .StartColumn
            EC = .EndColumn
            SC = ColumnName ( SC ) 'A1形式のセル番地に変換
            EC = ColumnName ( EC ) 'A1形式のセル番地に変換
            SR = .StartRow + 1
            ER = .EndRow + 1
            MsgBox SC & SR & ":" & EC & ER
        End With
    Else 'セル以外が選択されている場合
        MsgBox "セルが選択されていません"
    End If
    Set myRng = Nothing 'オブジェクトの解放
End Sub


Function ColumnName ( ByVal ColumnNo As Long ) As String 'セル番地の変換
    If ColumnNo / 26 > 1 then
        ColumnName = Chr ( 65 + int( ColumnNo / 26 ) - 1 ) & Chr( 65 + ColumnNo MOD 26 )
    Else
        ColumnName = Chr ( 65 + ColumnNo MOD 26 )
    End If
End Function

 


VBAのものと比べると、だいぶ長い処理になっています。その理由は2つあります。


  1. セルアドレスをA1形式に変換する: インデックス値で返されるセルアドレスをA1形式の表示に変換する必要があります。すでに述べたように、OpenOffice.org BasicではCell(あるいはCellRange)オブジェクトのアドレスはインデックス値で返ります。セルアドレスをA1形式で得ることができないため、別途Fanctionプロシージャを作成してアドレスの変換をおこないます。


  1. CellCellRange: VBAにおけるRangeオブジェクトのAddressプロパティは、1セルの時は「A1」のように表示され、複数セルのときには「A1:C3」のように、自動的に切り分けがおこなわれます。ところがOpenOffice.org Basic ではこのような自動処理はおこなわれません。選択されているセル範囲が1セルなのか複数セルなのかを判断して、場合分けをして表示を切り替えてやる必要があります。


上記が、処理が長くなっている2つの理由です。それ以外の編集部分について解説を加えておきましょう。


  1. オブジェクトの名前: VBATypeName関数に相当する処理は、getImplementationNameメッソドで実現できます。この場合に、CellオブジェクトかCellRangeオブジェクトかを知ることができますから、この情報をもとに2.のセルアドレスの表示を切り替える処理をすることが可能です。


  1. インデックス値とセル位置の関係: CellオブジェクトのアドレスはgetCellAddressメソッド、CellRangeオブジェクトのアドレスはgetRangeAddressメソッドで取得できます。前者の場合には、ColumnプロパティおよびRowプロパティの2つのインデックス値が、後者の場合にはStartColumnStartRowEndColumnEndRowプロパティの4つのインデックス値が得られます。すでに述べたように、OpenOffice.org Basicでは、インデックス値は0から始まります。(0,0)がA1セルです。この情報をもとにRC形式でセル番地を表示する場合のプロシージャをリスト8に示します。


【リスト8】−−Calc


Option Explicit
Sub A_Sample001()
    Dim oRange As Object
    Dim SC As String
    Dim EC As String
    Dim SR As String
    Dim ER As String
    oRange = ThisComponent.CurrentSelection.getRangeAddress
    SC = oRange.StartColumn + 1
    EC = oRange.EndColumn + 1
    SR = oRange.StartRow + 1
    ER = oRange.EndRow + 1
    MsgBox "R" & SR & "C" & SC & ":R" & ER & "C" & EC
End Sub
 


  1. 列名を取得する別解: 先ほどのリスト7は、上記のインデックス値をもとに、列番号を「A……AA……IV」に置き換えています。そのためにColumnNameというファンクションプロシージャを作成して計算によって列名を得ています。しかし、列全体にアクセスすると(冒頭のサンプル参照)、AB……などの列番号を直接取得することができます。この方法を使った例をリスト9に示します。


【リスト9】−−Calc


Option Explicit
Sub A_Sample001()
    Dim oRange As Object
    Dim oColumn As Object
    Dim CountColumn As Long
    Dim SC As String
    Dim EC As String
    Dim SR As String
    Dim ER As String
    oRange = ThisComponent.CurrentSelection
    oColumn = oRange.Columns '列全体を取得する
    CountColumn = oColumn.getCount '列数
    SC = oColumn.getByIndex(0).getName
    EC = oColumn.getByIndex( CountColumn - 1 ).getName
    SR = oRange.getRangeAddress.StartRow + 1
    ER = oRange.getRangeAddress.EndRow + 1
    MsgBox SC & SR & ":" & EC & ER
End Sub
 


どうでしょうか。このように、かなり面倒な処置が必要だということがおわかりいただけたと思います。オブジェクトの取得とその操作に関しては、一つ一つのオブジェクトごとに、きめ細かな対応が必要です。VBAからOpenOffice.org Basicへの移行では、これまで見てきたような、オブジェクトの取得や、プロパティやメッソドを置き換える作業が大きな比重を占めてきます。そのときに発生する問題点についての情報は、残念ながら今のところほとんど提供されていません。筆者は、本稿で解説してきたような情報を(整理ができ次第)筆者のWebサイトで公開していく予定です。

では、次号では、イベントとフォームの互換性を取り上げます。


本記事は、UNIX USER誌(ソフトバンクパブリッシング刊)の2004年11号に発表したものをHTML化したものです。したがって、現在のOpenOffice.orgの最新情報を反映したものではありません。

INDEX  Home


制作者:松 井幹彦

更新日: ,2005/06/23 15:56