Shapeを操作するコードなどで見かける「msoTrue/msoFalse」という定数と、
通常使用している「True/False」との違いを解説します。
同じところ
内部数値では同じ値を扱っています。
ExcelVBAにおいて「 Trueは-1 / Falseは0 」なのですが、
msoTrue / msoFalse も同様に「 -1 / 0 」という値になっています。
よって図形(Shape)の状態を変更する以下ようなコードは、
どちらで書いても同じ動きになります。
' どちらも「縦横比を固定」をONにするコード 対象図形.LockAspectRatio = True 対象図形.LockAspectRatio = msoTrue
違うところ
msoTrue/msoFalseについてざっくりと概念的な話から入ると、
この2値はそれ以外の選択肢が存在する際に登場します。
msoTrue/msoFalseは「MsoTriState列挙型」という仲間に所属しており、
この列挙型には以下の値が設定されています。
| 定数 | 値 |
| msoCTrue | 1 |
| msoFalse | 0 |
| msoTrue | -1 |
| msoTriStateMixed | -2 |
| msoTriStateToggle | -3 |
この中でTrue/False以外に頻出なのがmsoTriStateMixedであり、
Mixとある通り「混在状態である」ことを表します。
例えば先ほどの「縦横比を固定:LockAspectRatioプロパティ」について、
選択している図形(Selection)の状態を調べてみましょう。
' 選択している図形の「縦横比を固定」チェックの状態を調べる Debug.Print Selection.ShapeRange.LockAspectRatio
このコードでLockAspectRatioの値を調べてみると、
- 選択図形の縦横比が固定なら「-1」すなわちmsoTrue
- 選択図形の縦横比が固定されていないなら「0」すなわちmsoFalse
- 複数の図形を選択中で縦横比の固定が図形ごとに異なっているなら「-2」すなわちmsoTriStateMixed
という結果を取得することができます。
このようにTrueでもFalseでもない第3(4~)の状態が存在するプロパティは、
それを表現するための他の値が用意されています。
この値を返り値にしていると真偽値を返すことができないため、
True/Falseとは別にTrue/Falseを表す定数が用意されているということですね。
よってこれらは全く別ものなのですが、
同じ動きになるよう内部数値を一緒にしてくれているため、
「どちらで書いても動くコードが多い」という理屈になります。
使い分け
内部数値は同じのため、代入はどちらを使ってもOKです。
' どちらも「縦横比を固定」をONにするコード 対象図形.LockAspectRatio = True 対象図形.LockAspectRatio = msoTrue
問題は判定で、こちらは注意が必要になります。
ひとまず内部数値は同じであるため、
比較演算子「=」を使ったIf文ではどちらのコードでもOKです。
' どちらも「縦横比を固定」がONかチェックするコード If 対象図形.LockAspectRatio = True Then If 対象図形.LockAspectRatio = msoTrue Then
問題が発生するのは「比較演算子=を使用しない判定文」で、
以下のコードは「状態が混在した図形でも判定を突破」してしまいます。
' 「縦横比を固定」がONかチェックするコードと見せかけて・・・ If 対象図形.LockAspectRatio Then ' ← 「 = True 」を書かない ' !このコードはLockAspectRatioがmsoTriStateMixedでもTrue側に分岐!
理屈は後述しますが、論理演算において「0以外はTrue」という扱いのため、
このコードは「0」であるmsoFalse以外がすべてTrueとして扱われます。
この仕様には注意しておいてください。
ちなみに3択以上のプロパティを表現するこの仕様はよくある実装で、
お馴染みの「シートの表示設定:Worksheet.Visible」も同じ仕様になっています。
シートの表示設定は「表示/非表示/ VBAでしか解除できない非表示」の3択が存在し、
| 定数名 | 値 | 状態 |
|---|---|---|
| xlSheetVisible | -1 [True] | 表示 |
| xlSheetHidden | 0 [False] | 非表示 |
| xlSheetVeryHidden | 2 | 非表示(Excel上で再表示不可) |
このような値で定義されています。
まさに「表示/非表示はTrue/Falseでも動くようして3択目を追加した仕様」で、
以下の挙動もかなり似た形になっています。
' どちらもシートを再表示するコード シート.Visible = True シート.Visible = xlSheetVisible
' どちらもシートが表示されているか判定コード If シート.Visible = True Then If シート.Visible = xlSheetVisible Then
' !これだけはNG! これはシートが「VeryHidden」でもTrueになってしまう If シート.Visible Then
せっかくの機会ですし、この仕様も一緒に覚えてしまってください。
最後に使い分けですが、
代入でもちゃんとmsoTrueと書いた方が安全なのは間違いないのですが、
Selection.ShapeRange.は選択肢入力ができないためちょっと面倒です。
まあmsoTrueと書くくらいなら別にTrueとそんなに変わらないのですが、
Trueで済むところをxlSheetVisibleで書くのはかなり面倒ですよね。
Worksheets("○○")からだとやっぱり入力候補も出ませんし。
ということで、個人的には「動くんならTrue/FalseでOK」だと思って使っています。
お好きな方をお使いください。
おまけ:細かい仕様上の話
説明重視で飛ばした言語仕様の話だけ書いておきます。
最初にデータ型の説明ですが、
まずTure/Falseは「Boolean型のリテラル」で、
対してmsoTrue/msoFalseは「MsoTriState列挙型」内の要素です。
プロパティ「LockAspectRatio」は(正確には内部実装はVBAではないですが)
Enum MsoTriState msoCTrue = 1 msoFalse = 0 msoTrue = -1 msoTriStateMixed = -2 msoTriStateToggle = -3 End Enum Property Get LockAspectRatio() As MsoTriState ~~ End Property
こんな実装になっており、
「返り値の型がMsoTriState型のためBoolean型True/Falseはせない」ため、
「MsoTriState型(Long型)のmsoTrue/msoFalseを代わりに返す」仕様です。
※ 列挙型(Enum型)の各要素は計算上Long型として扱われます。
実際のコード挙動(VBAの暗黙の型変換)をC関数で再現すると、
まず代入コードは「Bool型がMsoTriState型に代入される際にLong型に変換」され、
結果がmsoTrueの値と一致と判定されて処理されます。
対象図形.LockAspectRatio = True ' ↓ こう処理される 対象図形.LockAspectRatio = CLog(True)
続いて「=」での判定コードですが、Long型とBoolean型を比較する際の「=」の挙動によりBoolean側がMsoTriState型(Long型)に変換されて動きます。
If 対象図形.LockAspectRatio = True Then ' ↓ こう処理される If 対象図形.LockAspectRatio = CLng(True) Then
これも問題なく動いてくれますね。
最後に「=」なしの判定コードですが、これはIfステートメントの仕様により、
条件式にあたる部分がBoolean型に変換されます。
If 対象図形.LockAspectRatio Then ' ↓ こう処理される If CBool(対象図形.LockAspectRatio) Then
こうなってしまうと、0以外のすべての数値がTrueになるわけですね。
数値化(CLng)と真偽値化(CBool)は真逆の動きですので、
せっかくここまでお読みいただいたんですしここで理解しておきましょう。
この仕様を理解した上で本ページの落とし穴を再度述べると
「返り値がBooleanでないプロパティを安易にIfステートに渡さない」
というのが最も理屈に合った対応であると言えそうです。
Is○○やExistsなど明らかなBoolean型でない限りは、
しっかり「=True」で判定を行っておきましょう。