『擬似からの脱却』記事が公開から20周年を迎えます。
(この20年で 「当たり前のテクニック」 として浸透してくれていると嬉しいです)
【コントロール配列】 は多数のコントロールを扱うフォームでは非常に便利な機能です。しかし、「VBにあってVBAにはない」
という、VBAユーザーにとって非常に残念で羨ましい機能でもあります。この記事では、本来、VBAが持っていない 「コント
ロール配列」 機能をイベント処理を含めて 『VB並みに扱える』 ようになる手法について解説しています。
小難しい解説はすっ飛ばして、とにかく今直ぐに使いたい、という方 ・・・・ 汎用クラス( clsBpca ) を ダウンロード して サンプルコード( $11 ) を参考に チャレンジ してください。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 某QA掲示板の過去ログに、「擬似からの脱却手法(clsBpca ) の存在意義に対する疑問」 というような会話が ありましたので、それへの答えを このページの末尾 に掲載しました。 ( 2022/1/22 追記 ) |
|
------------------------------------------------------------------------------------------------------------ |
【 擬似からの脱却 】 [ Breakthrough in the Pseudo-Control
Arrays ]
[ http://addinbox.sakura.ne.jp/Breakthrough_P-Ctrl_Arrays_Eng.htm ]
「擬似からの脱却」と銘打っていても、そもそも
「擬似」とは何を指しているの?
と聞かれるでしょうね。何なのかと言えば、それは、
VBAで使われているコーディング手法の「擬似コントロール配列」
の事です。すると次には
じゃあ「擬似コントロール配列」って何?
となりますので、先ずは「そこから」解説を始めます。
§1 | VB (Visual Basic) と VBA (Visual Basic for Application) | |||
§2 | Controls コレクション の利用 | §7 | クラスからフォーム内の情報を操作 | |
§3 | コレクション オブジェクトの利用 | §8 | 擬似から先ず1歩踏み出す | |
§4 | クラス モジュール って、何? | §9 | 擬似の足枷 | |
§5 | クラス モジュールの利用 | §10 | 擬似からの脱却 | |
§6 | 「擬似コントロール配列」で残る問題点 | §11 | その他のサンプルコード | |
§12 | Enter / Exit イベントの実装 | |||
( 初出 : §1〜5 [ 2004/5/17 ] , §6〜11 [ 2004/6/22 ] , §12 [2014/8/11]
clsBpca の 軌跡 ) ( 英訳 初出 : [ 2014/7/24 ] ) 【 旧 dion サーバー時の Internet Archive 】 |
||||
( News ) 汎用クラス Ver 2.0 ( 2014/8/11 リリース ) Enter , Exit , BeforeUpdate , AfterUpdate がサポートされました(仕組みは§12 を参照)。 ※ ワークシート上のコントロールを通り扱う場合は、コントロールの指定方法が ワークシート名.OleObjects ( コントロール名 ).Object というスタイルになります(clsBpca 利用例 参照) |
||||
( 参 考 ) この「擬似からの脱却」以前では、『VBAでのコントロール配列』に関する情報といえば、moug の 「スキルアップ講座 : クラスモジュールを使った究極のVBAプログラミング」 という記事(全7頁、内2頁でコントロール配列を解説)が唯一でした。残念ながら、moug の再編 に伴って、現在この記事は削除(2008年頃迄ありました)されていますが、Internet Archive で 拾う事ができます(上記リンクはInternet Archiveによるものです) 。内容としては、ここの§1〜5 に相当します。 |
[ clsBpca の 軌跡 ] [ 前頁 , 次頁 , §1 , §2 , §3 , §4 , §5 , §6 , §7 , §8 , §9 , §10 , §11 , §12 ]
[ 汎用クラス , トグルラベル クラス , Focus クラス , クラス アドイン , カレンダークラス ] [ 質問はメールへ ]
フォームで同じ使い方のコントロールを複数配置する場合、VBでは当たり前のように「コント
ロール配列」という機能が利用できます。
[ 例 ]
曜日ボタン(日曜〜土曜の7つ)を配置して、ボタンをクリックした時に、その曜日を
MsgBoxで表示してボタンカラーを変更する
という例を題材に考えてみます。
先ず[cmdWeek ]という名前で CommandButton を1つ配置してから、その CommandButton
をコピー&貼り付けすると、
既に同じ名前のコントロール'cmdWeek' があります。
コントロール配列にしますか?
というメッセージが表示されます。これに OK で応答した後、プロパティウィンドウを見ると、最初
のボタンは「cmdWeek (0)」に、今貼り付けたボタンは「cmdWeek (1)」という名前になっています。
これで”配列化”されたという事が判ります。同じ様に貼り付けを繰り返し、全部で7つのボタンを
用意します(キャプションは各々"日曜","月曜"〜"土曜"に変えます)。
配置したボタン(7つの内のどれでも)をダブルクリックすると、コードウィンドウ内に
というイベントプロシジャーのコードが挿入されます。コントロール配列にしていない場合は、
Private Sub cmdWeek_Click(Index As Integer)
End Sub
と、引数が入りません。つまり、実行時に、この7つのボタンのどれをクリックしても、呼び出され
Private Sub cmdWeek_Click()
End Sub
るイベントプロシジャーは「cmdWeek_Click 」という『ひとつだけ』という事です。
その時に
「何番目のボタンか?」という番号(0〜) が [Index] という引数
で渡されます。このイベントプロシジャー内でボタンにアクセスする場合、このIndex値を使って
『 cmdWeek ( Index ) 』という風に記述すれば、クリックしたボタンに対してアクセスできます。
この『ひとつ』のイベントプロシジャーだけで【7つの曜日ボタン全て】をカバーしており、
-- 実際のプログラム例 --
Private Sub cmdWeek_Click(Index As Integer)
Dim vntWeekName As Variant
vntWeekName = Array("日", "月", "火", "水", "木", "金", "土")
MsgBox vntWeekName(Index) & "曜日ボタンがクリックされました(" & Index & ")"
If (cmdWeek(Index).BackColor = vbButtonFace) Then
cmdWeek(Index).BackColor = vbRed
Else
cmdWeek(Index).BackColor = vbButtonFace
End If
End Sub
日曜ボタンをClick →「日曜ボタンがクリックされました ( 0 ) 」
金曜ボタンをClick →「金曜ボタンがクリックされました ( 5 ) 」
と、どのボタンをクリックしても、同じ様に表示され、またクリックの度にボタンカラーが変わると
いう動きをしてくれます。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
では、VBAの場合は、どうでしょうか?
VBAでは、元々VBのような「コントロール配列」という機能はありませんので、
[ cmdWeek ]という名前で CommandButton を1つ配置してから、
その CommandButton をコピー&貼り付けする
としても、貼り付けた2番目のボタンが[CommandButton1]という既定の名前になるだけです(その
まま、順次貼り付けていけば[CommandButton2] [CommandButton3]‥‥‥)。つまり、VBAでは
【同じ名前での定義は出来ない】という訳です。仕方ないので、各々の名前を
[cmdSun] [cmdMon] [cmdTue] [cmdWed] [cmdThu] [cmdFri] [cmdSat]
という風に変更します。当然、名前が違うのですからイベントプロシジャーも各々独立した別個の
ものとなります。
したがって、VBAで
Private Sub cmdSun_Click()
End Sub
Private Sub cmdMon_Click()
End Sub
:
:
Private Sub cmdSat_Click()
End Sub
[ 例 ]
曜日ボタン(日曜〜土曜の7つ)を配置して、ボタンをクリックした時に、その曜日を
MsgBox で表示して ボタンカラーを変更する
という処理を行なうには、VBで書いたイベントプロシジャーの中身(と同等なコード)を、日〜土の
7つのイベントプロシジャーに【同じ様に】記述してやらなければいけない、という事です。
Private Sub cmdSun_Click()
MsgBox "日曜日ボタンがクリックされました"
If (cmdSun.BackColor = vbButtonFace) Then
cmdSun.BackColor = vbRed
Else
cmdSun.BackColor = vbButtonFace
End If
End Sub
Private Sub cmdMon_Click()
MsgBox "月曜日ボタンがクリックされました"
If (cmdMon.BackColor = vbButtonFace) Then
cmdMon.BackColor = vbRed
Else
cmdMon.BackColor = vbButtonFace
End If
End Sub
--- 以下省略 ---
これでは、コーディング量が増えるばかりで、全く効率的ではありませんね。 ┐('〜`;)┌
[ 前頁 , 次頁 , §1 , §2 , §3 , §4 , §5 , §6 , §7 , §8 , §9 , §10 , §11 , §12 ]
[ 汎用クラス , トグルラベル クラス , Focus クラス , クラス アドイン , カレンダークラス ] [ 質問はメールへ ]
[ Home へ戻る ]
( この場所へのリンク ) | |
( 2022/1/22 追記 , 2022/6/26 一部加筆修正 , 2024/6/12
追記 ) 某QA掲示板 (既にかなりの過去ログではありますが …)で ・ 『 脱却 』 という言葉遣いが何か偉ぶってる? ・ そもそも、『 擬似からの脱却 』 手法を利用する事に意味が有るの? ・ clsBpca のインターフェースで、コントロールを登録するのに Add メソッド という方式を採用 している意味が分からない。何故、迂遠な事をしてるのか? 素直に [ 〜.Item ( Index ) = コントロール ] にすれば良いのに というような会話(議論)がされていたのを見つけてしまいました。それに答えていこうかと思います。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 〜 『 脱却 』 という言葉遣いが何か偉ぶってる? 〜 「擬似コントロール配列」 止まりで 「VB の コントロール配列」 との越せない高い壁を、当時未だ 誰もやっていない方法を見つけ出して、VBAでも単体コントロールと同じレベルの扱い易さで コントロール配列のイベント処理を構築できたという 「難題を克服した、壁をぶち破ったぞ」 という 感情を表現して 『 脱却 ・ Breakthrough 』 という言葉を敢えて選んでいます。 日本におけるVBAの先駆者であり、擬似コントロール配列というクラス利用法を世に広めた 元 moug主催の大村あつしさんでも 「擬似 止まり」 でした。 なので、自信を持って「壁を破った」 と自負していますし、『ブレークスルー』 と名乗れる内容の記事であると思っています。 当時も、その後も暫くの間、散々ネットを海外(英語圏)も含めて探し回りましたけど、このような 手法の解説は見当たりませんでした(公開していないだけで、何処かの誰かはとっくに知ってて 使っていたのかもしれませんが…) ( clsBpca の軌跡 ) 〜 『 擬似からの脱却 』 手法 ( clsBpca モジュール ) を利用する意義? 〜 この手法の目的は、最初から VB と同じように コントロール配列の 【 イベント処理を UserForm モジュール内に記述 】 できるようにする という一点だけです。それだけです。 その為の複雑な処理を ブラックボックス化して、ユーザーサイドでは難しい事は考えずに通常の単体コントロール と同じように、インテリセンス付きで、全く意識することなく簡単に コントロール配列を使って フォーム の プログラ ミング を サポート できるようにしたのが、汎用モジュール ( clsBpca ) です。 「イベント処理を UserForm モジュール内に記述できるようにする 」 以上の機能を持たせる場合は、これを参考に 新たに組み直せば良いと思います(例 : トグルラベルクラス )。 「イベント処理を UserFormモジュール内に記述 」 だけで良いならば、元にして作り直す必要はありません。 色々な機能が付いていて複雑だから シンプル にしたいというのかもしれませんが、不要ならばその機能を使わな ければ良いだけなので。 〜 何故、 Add メソッド? 〜 何故と言われても、それが一番自然であり、且つ、安全な インターフェース だったからです。 不特定多数の人が利用する事が前提の ツール ですので、「どのような使われ方をしても正しく動作する/正しくエラー 処理される」 というのが大事です。その事を検討した上で決めた インターフェース です。 擬似からの脱却では、 @ 対象コントロールを最初に全て登録 ( Add メソッド : クラス内部の Collection に Add ) Collection に Add するステップなので clsBpca のインターフェース でも Add メソッド としています。 A その後で一括して 「子クラス展開 & 動作条件の設定」 を行なう ( Rgst メソッド ) という流れで コントロール の登録処理を行ないます。 この手順にすることによって、擬似からの脱却手法の肝である 「子クラス展開」 を行なう際に (および、動作条件の 設定についても) B この時点で対象 コントロール が決まっている (個数が固定されている) C その後で対象 コントロール が増えることが無い D コントロール番号 ( Index ) が連続して振られており、歯抜けが無い という メリット があります。この前提が得られるだけで、クラス 内での登録処理の ロジック がかなり楽になります。 clsBpca では 「発生イベント の指定/制限」 という動作条件があり、全ての子クラス 内に等しく登録しておく必要が あるのですが、上記の保証があるおかげで無駄な チェックロジック も必要なく プログラミング できています。 逆に、これらの保証が得られない インターフェース の場合、安全な ツール とするには、様々な 「もしも」 に漏れ なく対応しておかなければいけません。 [ 〜.Item ( Index ) = コントロール ] という スタイル で コントロール の登録を行なう場合、 a) Index を 1 から連番で指定して貰える保証がない b) 番号が歯抜けになったり ( 1, 3, 7, … )、登録順で番号が前後 ( 1, 5, 2, 7, 4, … ) したりする可能性もある c) 既に登録済みの番号 ( Index ) に重複して コントロール を登録してしまう可能性もある d) 「後で追加」 という可能性もある というような、「そんな事はしないだろう」 という 『もしも』 にも対処できてなければなりません。 自分だけで使うものならば、どのように設計しようと、曖昧な部分が有ろうと、変な使い方では異常終了しようとも、 設計者イコール唯一の使用者であれば、正しい使い方を熟知しているわけですから構わないでしょう。しかし、 不特定多数の人に安全に利用してもらう以上は、このような事も考慮する必要があります。それだけ、余計な チェックロジック が必要になります。 以上のような検討の結果、Add メソッドでコントロール を登録していく インターフェース が ベスト であろうという 結論になりました。 ちなみに、clsBpca では 『後で追加』 を禁止していますが、【 動的に明細行を増やす 】 という要求仕様は普通に あり得ます。このような ケース では、増やす際に 「一旦全て解除して、増えた コントロール も加えて登録し直す」 という手順を踏むことによって対応できます。サンプルコード がありますので参考にしてください。 ---- ( 2024/6/12 追記 ) ---- 尚、§5〜§9 節において、コントロール の登録を Item プロパティ で行っている のは、クラスモジュール の仕組みと使い方を説明するのが主眼で、その為に簡易な手順で済ませている事と、プロパティ ( Let / Get ) を 説明する サンプル としても丁度良かった為です。不特定多数の利用を前提とする ツール を作製する場合には、 上述のような配慮が必要になります。 |
|
||
角田 桂一 Mail:addinbox@h4.dion.ne.jp CopyRight(C) 2004 Allrights Reserved. |