知識の倉庫の整理はてなブログからワードプレスに引っ越しました。ここでは中小企業診断士の勉強記や経理、派遣社員として働いて気づいたこと、その他にプログラミング関連やVBAについて思ったことを書いています。現在はJavaScriptを勉強中。2019.02.08前回のActiveXコントロールと同様に今回はフォームコントロールを無効にする方法についての話です。ExcelVBAでシートを利用して何らかのシステムや簡易的なマクロを作る場合、ボタンなどの1つや2つ設置することもあるかと思います。システム作りを進めていると「こういった場合はユーザーにボタンを押させたくない」とか「こういった場合はユーザーにこのボタンだけを押させたい」といった状況も出てくるでしょう。処理の流れからある特定のボタンしか押せないようにすることでユーザーを迷わせないようにする、セキュリティ上、ある特定の場合は全てのボタンを押せないようにする、といった状況も考えられます。フォームモジュールを使ったフォームを使うほうがシステムを作るには楽でしょう。言っても業務の都合上、機能の都合上どうしても「Excelのシート上にフォームコントロールを使ったシステム」を作らざるを得ない場合もあるかもしれません。いった時に、ExcelVBAのコードでシート上のボタンの押せる押せないを何らかのアクションをトリガーとして切り替えられたら便利です。「シート上に設置したフォームコントロールを無効にする」ためのコードをインターネット上で調べてみたのですがなかなか見つけられませんでした。フォームモジュールのコントロールを無効にするコードはたくさん見かけるのですが、シート上に設置するフォームコントロールを無効にするコードは見つかりません。自分の探し方が悪かったのかもしれませんが、そもそもシート上に設置したコントロールはExcelの仕様上、無効にはできないようです。自分の調べた範囲でそのような文章を何度も目にしたのですが、「何とかしてフォームコントロールを無効にできる方法はないか」と考えていたので色々と試行錯誤してみました。その結果、偶然にも「シート上に設置したフォームコントロールを無効にできる方法」を見つけました。Excelの開発タブから設置するボタンの種類には大きく「フォームコントロール」と「ActiveXコントロール」があり、以下の前回の過去記事ではActiveXコントロールを「使用不可」にするコードについて説明しました。今回はシート上に設置したフォームコントロールをShapesとIf文を使って無効にできる方法について説明していきます。目次ExcelVBAのShapesとIf文でシートのフォームコントロールを無効にするコード1つ目の「フォームコントロール」プロシージャの説明If文からEnabled=Falseの状態を利用してフォームコントロールの有効無効を切り替える今回のコードとフォームコントロールの補足まとめあわせて読みたいExcelVBAのShapesとIf文でシートのフォームコントロールを無効にするコード今回の機能の概要としては、コードを2つ使います。1つ目のコードで指定のフォームコントロール(ボタン等)のEnabledプロパティの状態をFalseにし、2つ目のコードをフォームコントロールのボタンにマクロとして登録します。その登録したマクロのコード内にIf文を入れてボタンのEnabledプロパティがFalseの時はボタンを押しても機能させない、EnabledプロパティがTrueの時は目的の機能を使えるようにする、という方法になります。完全にフォームコントロールのボタンを無効にはできませんが、「形」として無効にするというやり方です。ここまでの説明では何を言っているかわからないと思うので順番に説明してきます。結論としては次の2つのコードを使います。1つだけではできません。ちなみにExcel2013で動作を確認しています。Sub今回は上記のコードに加えて以下のコードも必要になってきます。いずれも標準モジュールに入力します。Sub今回は「フォームコントロール」プロシージャと「テスト1」プロシージャを記述しました。この2つのコードについて順番に解説をしていきます。1つ目の「フォームコントロール」プロシージャの説明わかりやすく説明できるように一度以下に再掲します。Subこのコードの意味として、まず2行目で変数cを宣言。Eachステートメントで「Sheet1」シート上にあるフォームコントロールを順番に変数cに格納していきます。ここがひとつポイントで3行目の「Shapes」でフォームコントロールではなく、ActiveXコントロールの両方とも変数cに格納できます。このShapesコレクションというのは基本的にはシート上にある全ての「描画オブジェクト」を指します。円とか四角の図形とかグラフ、画像といったオブジェクトです。ActiveXコントロールやフォームコントロールもShapesコレクションに含まれることになります。Falseの意味は、Sheets(“Sheet1”)は「Sheet1」シートを指します。Shapes(c.Name)は指定したシート上にある全ての描画オブジェクトの中でコントロールの名前が「c.Name」になるものを指します。c.Nameは順次描画オブジェクトをcに格納していって、Nameプロパティからcに格納した描画オブジェクトの名前を取得できるようにしています。DrawingObjectが、描画オブジェクトの名前が「c.Name」になる個別の具体的なオブジェクトを指します。Falseで今回の記事の目的であるフォームコントロールを無効にする、ということになります。ポイントはShapes(c.Name).EnabledではなくShapes(c.Name).DrawingObject.Enabledという風に「DrawingObject」が途中に入ります。DrawingObjectsではなく「DrawingObject」という風に最後に「s」は入らないので、見落としやすいので注意してください。eachステートメントを使うとシート上にある全ての描画オブジェクトを見ていくことになります。仮にその中に「吹き出し」といったコントロールとは別のオブジェクトなど、一部はエラーになってしまうものがあります。自分が確認した範囲では、フォームコントロール、ActiveXコントロールのEnabledプロパティは全てFalseに設定できました。「c.Name」の部分で最初からフォームコントロールに設定している文字列を指定するIf文を使って指定のオブジェクト名のフォームコントロールだけEnabledプロパティをFalseにできるようにするといった風にして指定のフォームコントロールにだけ設定がされるようにした方が良いと思います。ここまで書いたような4行目のコードにすることで、それぞれ特定のフォームコントロールを指せるようになります。cで変数cに格納する描画オブジェクト(今回の記事ではフォームコントロール)を変えていきそれを繰り返す、という流れになります。ここまでのコードの注意点としては、ここまでではシート上に設置した各フォームコントロールはEnabled=Falseという状態を保持しただけで、「無効」にはなっていません。これは以下のMicrosoftのヘルプにもあるように「仕様」でどうしても実質的に無効にはできないようです。設定しても、登録されたマクロが実行される題名が「Excel2010」となっているので、バージョンがExcel2007の時はここまでに記述したコードでもフォームコントロールを無効にできたと思います。自分のパソコンで使っているExcel2013でのここまでのコードでは、確かにEnabled=Falseにしてもフォームコントロールのボタンは押せたままになっています。試しにボタンを押したらメッセージボックスが表示されるようにしたのですが、どうやってもメッセージボックスが表示されました。最初の内は自分の入力したコードが良くなかったのではないかと思い色々と試行錯誤してみましたが上手くいかず、やはりコードの問題ではないようです。何か良い方法がないか悩んでいる時に見つけたのが先程引用したMicrosoftのページです。設定しても、登録されたマクロが実行される」とあるので、一見するともうどうしようもないかのように思えます。そのページから次のような方法を思いつきました。If文からEnabled=Falseの状態を利用してフォームコントロールの有効無効を切り替える先述の以下のMicrosoftのページには次のように書かれています。設定しても、登録されたマクロが実行されるこの現象を回避するには、以下の例のように、処理の冒頭にマクロが実行されないよう制御文を追加してください。Subこのコードを見てピンときました。ここまでで、Excel2010以降では、フォームコントロールをEnabled=Falseにしても無効にはできず、「その状態を保持するだけ」と書きました。この部分がポイントで、If文からEnabled=Falseの状態を利用してフォームコントロールの有効無効を切り替える、というコードになります。引用したコードが適用できるのは「ActiveXコントロール」の場合です。ボタン1_Click()」とあり、ボタンのクリックイベントになっているからです。実験してみたのですが、フォームコントロールの場合はこのクリックイベントのプロシージャを作ることが出来ませんでした。指定のシートにフォームコントロールがあってもコードウィンドウのオブジェクトボックスにはそのオブジェクト名は表示されません。作成_Click()」のイベントプロシージャを作って中に何かコードを入力しても動作しません。「マクロの登録」で登録されるコードが優先されてしまうのですが、逆にこれを利用します。今回の記事の最初の方で書いた2つ目のコードを以下に再掲します。Sub上記のコードをボタンの「マクロの登録」で登録します。今回の記事で記述したフォームコントロールのEnabledプロパティをFalseにする1つ目のコードを実行します。その後、上記のコードを登録したボタンを押すと、そのボタンのEnabledプロパティがFalseの場合は「aaa」の文字列が書かれたメッセージボックスが表示されます。逆にEnabled=Trueだと「bbb」の文字列が書かれたメッセージボックスが表示されます。「aaa」と「bbb」の文字列が表示されるメッセージボックスは、Enabledプロティの状態によってちゃんと条件分岐できるか確認しているだけで、通常は「aaa」の行は削除すれば、Enabled=Falseであれば何も起きないようにできます。「bbb」の行の部分に、そのフォームコントロールに動作させたいコードを入力すれば、フォームコントロールが有効の場合(Enabled=Trueの状態)は目的の動作をさせることができます。無効の場合は何も起きない、という機能にできます。複数のフォームコントロールに適用したいのであれば、別にモジュールかプロシージャを作って、そちらにさせたい動作のコードを入力してcallステートメントとプロシージャ名を「bbb」の行に置き換えるという方法もあります。“○○○”という風にコード上で設定するという方法もあります。(“○○○”の部分に目的のプロシージャ名を入れる)使う人が使いやすい形で変えていただければと思います。今回のコードとフォームコントロールの補足ここまでで必要な一連の処理は書けました。ここでは、ここまで記述したこと以外で次の3点について書いていきます。フォームコントロールを無効にしても文字色までは変わらないShapesを使うとActiveXコントロールも「無効」にできるフォームコントロールで「無効」にできるのは標準で搭載されている8種類の全てのフォームコントロール1について説明してきます。今回のコードではフォームコントロールを形として「無効」にすることはできますが、同時に文字色までは変えることはできません。ActiveXコントロールだとEnabled=Falseにすると文字色もグレーになって無効になったことがわかりやすいのですが、フォームコントロールだと自動では文字色は変更されません。そのため、必要であればフォームコントロールの文字色を変更するコードが別途必要になります。そのコードについては以下の記事を参照していただければと思います。ExcelVBAでシートにあるフォームコントロールのボタンの文字色を変更する方法2について説明してきます。Shapesを使うとActiveXコントロールも「無効」にできるのですが、ここまで説明してきたようにShapesはそのブック上、シート上にある全ての描画オブジェクトを指します。eachを使う際、If文などで何も制限をかけないと、フォームコントロールもActiveXコントロールも一部のその他のオブジェクトも無効にしてしまいます。前回以下のようなActiveXコントロールだけを無効にする過去記事を書いたのは、フォームコントロールやActiveXコントロールを分けて使いたい人がいる場合を考慮してのことです。ExcelVBAのOLEObjectsでシート上のActiveXコントロールを使用不可にする方法ですから特定のフォームコントロールやActiveXコントロール、もしくは特定のコントロールだけを無効にしたい、有効無効を切り替えたい場合は、適宜使い分けるか、If文などでオブジェクト名を指定していただければと思います。3のフォームコントロールで「無効」にできるのは標準で搭載されている9種類の全てのフォームコントロールについてですが、一覧にすると以下のような形になります。Bar試しに上記のフォームコントロール全てでEnabledプロパティをFalseにしてみましたが、Enabled=Falseという状態は保持するのですが、無効にはなりませんでした。したら自分の手違いなどもあるかもしれませんが、Excel2010以降で全てのフォームコントロールを状況によって無効にしたい場合は、今回の処理が必要になってくるかと思います。まとめ今回はActiveXコントロールの時と違ってかなりてこずりましたし、途中で挫折しそうになりました。いうのも以下のコードをF8キーで1行ずつデバッグする時に黄色のラインがエラーなく通過したので、これでいけると思ったからです。Falseデバッグが無事終了後、うきうきしながらボタンを押しました。すると設定されているマクロのメッセージボックスが表示されてしまい愕然としました。「えっ?何で?」という風に。上記のコードを試行錯誤しながら見つけるだけでも大変だったのに、解決策を見つけるためにまた調べなければならないとなると気持ちが落ち込むばかりでした。なんとか偶然も重なって解決策が見つかったわけですが、今回の件はExcelのバージョンの仕様上どうしようもない、という点はありました。それを補うための「代替案」というものを見つけられたのは色々と勉強になりました。今回の件から、今後はそのアプリケーションの仕様上どうしてもできない機能があっても「何か代替案はないか」ということを考えながらコードを見ていこうと思います。コメントをキャンセルメールアドレスが公開されることはありません。