ロゴ(青) ロゴ(緑)

Tips11: 関数カテゴリの増設

  エクセルで利用できる関数は「関数の貼り付け」ダイアログに表示される何れかのカテゴリに分類
され、VBAで作成したユーザー定義関数も、何もしなければ既定で『ユーザー定義』というカテゴ
リに入ります。カテゴリの種類は標準では

      財務(1)    日付/時刻(2)    数学/三角(3)    統計(4)    検索/行列(5)
      データベース(6)    文字列操作(7)    論理(8)    情報(9)    コマンド(10)
      ユーザー設定(11)    マクロ制御(12)    DDE/外部(13)    ユーザー定義(14)

の14種類があります(カッコ内の番号は『カテゴリ番号』と呼ばれるものです)。

  ユーザー定義関数はMacroOptions メソッドというものを使う事により、既定の「ユーザー定義(14)」
から他のカテゴリへ移す事ができますが、通常では、移す先は上記の14種類の内の何れかに限ら
れます。
  分析ツールをアドインすると、新たに『エンジニアリング』というカテゴリが追加されます(分析ツール
に含まれる関数は、この『エンジニアリング』カテゴリに割振られます)が、そのカテゴリ番号は15番
以降の何れかの番号(他にカテゴリを増設するようなソフトを使用していなければ15番)になります。

  関数を提供するアドインソフトを複数利用したり、自分で作成した関数の数が増えてきたりすると、
その全てが「ユーザー定義(14)」カテゴリに入っているが故に、アドインや自作の関数が混ざって
しまって(リストは名前順に並ぶだけなので、個々のブック別の区別はできない)、リストから選択し辛
い状況になっていきます。

  リスト上で一纏まりになるようにするには、予め「関数」設計の段階で『関数名』の頭に共通のプリ
フィックス文字を付けておくと効果的です(しかし、既に作ってしまって運用中の関数では、途中で
名前を変える事はできませんね)。

  そうすると、「分析ツールのように、新しいカテゴリを作って、そこに登録」したくなりますが、先に書
いたように、MacroOptions メソッドでは既存の1〜14のカテゴリ番号を記述する方法しか提供されて
いません。分析ツールや他のアドインなどでカテゴリが増設されていれば、15以降の番号をMacro
Options メソッドに指定する事で「そのカテゴリ」へ移す事が可能なはずですが、「そのカテゴリが何
番か?」というのがユーザーサイドでは確実には判りませんので移す事ができません。

(補)Excel2003 からは、MacroOptions メソッドに機能が追加されて『カテゴリ増設』が
      可能になりました。使い方は簡単で、今まで
            Category:=10
      という風に「数字で既存のカテゴリ番号を指定」していたところを、
            Category:="My Custom Category"
      という風に『文字列でカテゴリ名を指定』するだけです。存在しないカテゴリ名が指定
      された場合は「そのカテゴリ名」を自動的に増設する仕様になっています。
          Category (Excel 2003 ヘルプより引用)
Optional Variant.
An integer that specifies an existing macro function category (Financial, Date & Time, or User Defined, for example).
See the remarks section to determine the integers that are mapped to the built-in categories.
You can also specify a string for a custom category.
If you provide a string, it will be treated as the category name that is displayed in the Insert Function dialog box.
If the category name has never been used, a new category is defined with that name.
If you use a category name that is that same a built-in name, Excel will map the user defined function to that built-in category.
 
省略可能です。バリアント型 (Variant) の値を使用します。
既存のマクロ関数の分類 (財務、日付/時刻、ユーザー定義など) を示す整数値を指定します。
組み込みの各分類に対して割り当てられている整数値の一覧については、解説を参照してください。
また、ユーザー設定の分類を表す文字列を指定することもできます。
文字列を指定した場合は、[関数の挿入] ダイアログ ボックスに表示される分類の名前として認識されます。
指定した分類の名前が使用されていない場合は、その名前で新しい分類が定義されます。
組み込みの名前と同じ名前を使用した場合は、ユーザー定義関数がその組み込みの分類にマッピングされます。


  上記の方法は Excel2003から ですので、Excel97・2000・2002 では利用できませんが、実を
言うと、σ(^_^) の『kt関数アドイン』では、独自カテゴリの増設を以前より行なっています。
当然97〜2002で利用しています。

  これまでは、この「カテゴリ増設」手法の公開を控えてきましたが、2003から普通に増設できる
ようになった事が判りましたので解禁します(公開により、1つ/2つの関数でカテゴリ増設を行な
うような安易なソフトが出て来て、限りあるカテゴリ数をアッという間に使い切ってしまうという懸念
がありましたが、2003で簡単に増設できてしまう以上、隠しておく意味がなくなりましたので)。
  尚、この手法は、私の完全なオリジナルという訳ではありません。元ネタは海外サイト(Archive)
で公開されていたロジック(Archive)です。但し、そのロジックには、解説HPにも書いてあるように
「分析ツール」がアドインされている状況では正しく動作しない不具合があります。ここで紹介する
ロジックは、その不具合を解消するように改良したものです。


=================================================================
      【関数カテゴリ】  増設方法の解説
=================================================================

(1) 新カテゴリを追加できるカテゴリ番号は『15〜32番』になります(14番は既定の「ユーザー
    定義」)。ただし、分析ツールや他のソフトによる割当が為されている場合には更にその後ろ
    になるので、15番から順に調べて「空いているか」を調べる必要があります。

(2) 「空いている」場合は、そのカテゴリ番号に対するカテゴリ名
            "User Defined"      (*) UserとDefined の間は半角空白
    になっているので、それを調べて判断しますが、カテゴリ番号から直接「カテゴリ名」を取得
    する方法がありません。ただし、何らかの名前定義が「そのカテゴリ番号」に対して為されて
    いれば、その名前を使って
            Application.Names ( "名前" ).Category
    とする事により取得できます。そこで、一時的に各カテゴリ番号に対して名前定義を行い、
    その名前を通して上記方法により「カテゴリ名」を取得します(当然、一時的に付けた名前
    定義は後で削除します)。

(3) カテゴリ番号に対して名前定義を行なうには、Excel4Macro
            DEFINE.NAME ( "名前" , 0 , 2 , , , カテゴリ番号 )
    を使います。これを実行する場合は[Application.ExecuteExcel4Macro]を使って
            Application.ExecuteExcel4Macro _
                "DEFINE.NAME(""名前"", 0 , 2 , , , カテゴリ番号 )"
    という風にします(カテゴリ番号は数字)。

(4) この後、『 Application.Names (名前).Category 』で得られたカテゴリ名が "User Defined"
    の場合に、カテゴリ名を "User Defined" から新カテゴリ名にリネームします。リネームする
    には、上記のDEFINE.NAME でカテゴリ番号のところを「新カテゴリ名」に置き換えて実行
    します。
            Application.ExecuteExcel4Macro _
                "DEFINE.NAME(""名前"", 0 , 2 , , , ""新カテゴリ名"" )"
   この時の「カテゴリ番号」を保存しておき、MacroOptions に指定します。

(5) 最後に、一時的に定義した『名前定義』を削除します。
            Application.ExecuteExcel4Macro "DELETE.NAME( ""名前"" )"

【留意事項】
  a) アドインブックの場合、アドイン属性のまま(非表示ブック)では上記の名前定義が
    失敗するので、一時的にアドイン属性を解除する必要があります。その際、ユーザー
    に見えないように[ScreenUpdating=False]にしておきます。また、この処理によって
    アドインブックに更新が加わるので、このままではエクセル終了時(アドインブックの
    クローズ時)にアドインブックの保存確認ウィンドウが表示されてしまいます。これを防
    ぐ為に、この処理後に[ThisWorkbook.Saved = True]として保存処理をキャンセルさ
    せる必要があります。

  b) アドインとして開かれる場合や、普通に参照設定によって開かれる場合には問題な
    いですが、[CreateObject]で起動されたExcel内から参照設定により開かれる場合には、
    上記の名前定義処理が失敗するので、それに備えてエラー処理(既定の14番に割り
    当てる)が必要になります。

  c) 最重要
    分析ツールが既にアドインされている場合には、『新カテゴリ』として使うカテゴリ番号
    に加えて、更にもうひとつのカテゴリ番号を確保しておかないと、[MacroOptions]が
    失敗します。つまり、先の説明した処理で、もうひとつのカテゴリ番号を「新カテゴリ名2」
    としてダミーでリネームしておく必要があります。こちらのカテゴリにユーザー関数を割
    り当てなければ、関数カテゴリのダイアログに表示される事はありません。

    増設できるカテゴリ番号は『15〜32』の18個ですが、上記の理由により、1カテゴリに
    付き2つのカテゴリ番号を消費しますので、この処理によって行なえる増設は9個まで
    です(この処理を使うブックが9個以上あるとパンクします)。



下記の『FuncCategory_Create 』を Workbook_Open イベントプロシジャー内で実行します。
 
  Sub FuncCategory_Create( )
  Const cstCatName As String = "MyFunction"    ' 増設するカテゴリ名(任意)
  Dim i As Integer
  Dim strCat As String
  Dim intMyCat1 As Integer    ' 1つ目の[User Defined]の番号
  Dim intMyCat2 As Integer    ' 2つ目の[User Defined]の番号、および ループカウンタ
  Dim intUserDefineCount As Integer
  Dim vntRC As Variant
  Dim blnAddin As Boolean

    ' アドイン状態では名前追加が出来ないので、作業中は一時的にアドイン属性を解除する。
    ' そうするとアドインブックが見えてしまうので画面更新を停止する。

    blnAddin = ThisWorkbook.IsAddin
    If ( blnAddin = True ) Then
        Application.ScreenUpdating = False
        ThisWorkbook.IsAddin = False
    End If

    ' ダミーの名前を[15]以降のカテゴリに追加し、その名前から『カテゴリ名』を取得して[User Defined]の
    ' 場合に、そのカテゴリ番号を求める。
    ' (注)14番の[User Defined]は、ユーザー定義関数の既定カテゴリなので、使えるのは15番以降になる。
    ' ※[分析ツール]がアドインされていると、最初に見つかる[User Defined]に加えて、その次の[User Defined]
    '     までカテゴリを作っておかないと[MacroOptionsメソッド]でエラーになる


    intUserDefineCount = 0
    intMyCat1 = 0
    intMyCat2 = 14
    On Error Resume Next
    Do
        intMyCat2 = intMyCat2 + 1
        vntRC = Application.ExecuteExcel4Macro( _
                "DEFINE.NAME(""DummyName" & intMyCat2 & """,0,2,,," & intMyCat2 & ")")
        If ( vntRC = False ) Then
            Exit Do
        End If
        strCat = Application.Names("DummyName" & intMyCat2).Category
        ' UserとDefined の間には半角空白が必要
        ' Excelを終了しないでアドイン登録/解除を繰り返した場合に備えて
        ' [MyFunction〜]の名前で割り当てられているカテゴリを再利用する

        If ( strCat = "User Defined" ) Or ( strCat Like ( cstCatName & "*") ) Then
            intUserDefineCount = intUserDefineCount + 1
            If ( intUserDefineCount = 1 ) Then
                intMyCat1 = intMyCat2
            End If
        End If
    Loop Until ( intUserDefineCount = 2 ) OR ( intMyCat2 >= 32 )

    If ( vntRC =False ) Then
        ' カテゴリ増設に失敗したので既定の14番にする
        intMyCat1 = 14
        Goto L1
    Else
        If ( intUserDefineCount < 2 ) Then
            ' 追加する余裕が無いので既定の14番にする
            intMyCat1 = 14
            GoTo L1
        End If
    End If

    ' 1つ目の[User Defined](⇒intMyCat1)のカテゴリ名を"MyFunction"に変更する
    Application.ExecuteExcel4Macro _
            "DEFINE.NAME(""DummyName" & intMyCat1 & """,0,2,,,""" & cstCatName & """)"

    ' 2つ目の[User Defined](⇒intMyCat2)のカテゴリ名を"MyFunction_DummyCategory"に変更する
    ' ※分析ツールがある場合にエラーとならない為に必要な2つ目のカテゴリだが、こちらに何も登録
    '     しなければ、関数ウィザードに表示される事は無い

    Application.ExecuteExcel4Macro _
            "DEFINE.NAME(""DummyName" & intMyCat2 & """,0,2,,,""" _
                        & cstCatName & "_DummyCategory" & """)"

    '------------------- MacroOptions 登録ブロック ----------------------
    ' 登録先は、1つ目の[User Defined](⇒intMyCat1)
    ' 増設エラー時は[intMyCat1]に14(既定)が入っている

  L1:
    Application.MacroOptions Macro:="CatTest1", _
            Description:="カテゴリ追加テスト1", Category:=intMyCat1

    Application.MacroOptions Macro:="CatTest2", _
            Description:="カテゴリ追加テスト2", Category:=intMyCat1
    ' 以下、必要な分だけ関数を登録する

    '-------------------------------------------------------------------
    ' ダミーで登録した名前を削除する
    ' 2つ目の[User Defined](⇒intMyCat2)まで

    For i = 15 To intMyCat2
        Application.ExecuteExcel4Macro "DELETE.NAME(""DummyName" & i & """)"
    Next i
    On Error GoTo 0

    ' アドイン属性を戻し、画面更新を復活させる。
    ' アドインブックの更新を行なったので、エクセル終了時にアドインブックの保存確認が出ないようにする。

    If ( blnAddin = True ) Then
        ThisWorkbook.IsAddin = True
        ThisWorkbook.Saved = True        ' Save のキャンセル
        Application.ScreenUpdating = True
    End if
  End Sub



  '----( テスト登録用の関数 )--------------------------
  Function CatTest1( ByVal aa As Integer ) As Integer
      CatTest1 = aa
  End Function

  Function CatTest2( ByVal aa As Integer ) As Integer
      CatTest2 = aa
  End Function

 




Home  Back Page  Next Page

ロゴ(ゴールド) ロゴ(ゴールド)

角田 桂一 Mail:addinbox@h4.dion.ne.jp CopyRight(C) 2004 Allrights Reserved.