● [★ AccessやExcel等のVBAの独学に最も重要!!] とりあえず Access2000 で、テキストボックスやフォーム、サブフォーム、レポート、サブレポート、その他、等々を「参照」したいときのプログラムコードの書き方(参照方法)と重要注意事項
※まだ書きかけです。すみません。
※間違ってたらすみません。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。
★ 「参照」の理解の重要性 (プログラミング的にも、会社や個人のデータ管理の効率化コストダウン的にも、お子様たちの未来的にも。)
フォームやサブフォーム、レポートやサブレポート、コントロール(テキストボックスやコンボボックス、コマンドボタンなど)を参照するには色んな指定方法があります。
「参照する」とは、「現在アクティブなフォームのアクティブなテキストボックスの名前や値 等々」とか「×××フォームの××サブフォームのレコードセット(行や列での構成でのデータ)の内容 等々」とか、そういったものを「調べる」というか、「取得する」というか、「見に行く」というか、「覗きにいく」というか、そんな感じのことです。
あるいは、テキストボックスに何らかの値を入れたり、ボタンを押したことにする、など、何らかの自動操作をVBAプログラムを使ってしたいとき、その各部品たちを、操作の「目標物・対象物」として「指定したい・指定する」ときにも「参照する」という風に言ったりします。
ここではその時の指定方法をご紹介します。
「Bizパソコン技」のところで、『パソコン操作は「選択」の状況をつかむことが一番大事。最重要。これができねば、何も操作できない。100%上達しない。パソコンはスマホみたいにシングルタスクかつ感覚的な選択状態がないからです。逆に「選択」の状況がわかりさえすれば、次に何をしたらいいかもわかってくるのでパソコンの習得が速くなります』といったようなことを書かせていただきました。
「参照」も似たようなところがあって、これがわからないと、VBAプログラミングでは何もできません。
「参照」はVBAプログラムを書く上だけでの、そのとき限定の「選択、のようなもの・・・」「VBA構文・文法と同様に スタート地点」といえるかもしれません。
色んな状況下で「参照≒操作対象の選択」ができれば、「わかりにくいVBAプログラミングが多少でもわかりやすくなる」と思います。できなければ、VBAプログラミングを習得することができず、必ず(100%に近い確率で)挫折してしまいます。これが理解できなければ、いくら構文を勉強しても何もできません。
逆に、「参照≒VBAでの色んな操作対象の選択」ができれば、あとは、「IF文」「For文(For Each文含む)」「Do Until文」「エラー処理」だけ知っていれば、今のマシンパワーならそれだけで、零細様の事務用プログラムならほぼ90%以上が作れてしまいます。(フォーム上でドラッグ処理を必要としないものに限りますが。グループウェアやガントチャートなどはAccessでは作れない、と思ったほうが効率がいいです。)
まかなえてしまいます。(Win32APIのことも少し知っているとより便利ですが)
Select Case文も、While文も、その他の文も、もちろん知っていたほうが有利に決まっていますし、もちろん、ゆくゆくは覚えなければならないものですが、でも、超初心者の場合、「IF文」「For文(For Each文含む)」「Do Until文」「エラー処理」すら使えないのに、先にそれをムリに覚える必要もありません。
「IF文」「For文(For Each文含む)」「Do Until文」「エラー処理」をしっかり学んでからでも遅くはありません。
現実に、初級・中級の「一般的な定型の事務処理だけ」なら、特に「複雑な条件での集計やリストアップ」だけなら、「SQL」さえ学んでおけば、「IF文」「For文」「Do Until文」「エラー処理」だけで十分です。
なんとかなります。
「With」もべつに使わなくていいです。
「With」はむしろ「害悪」です。オブジェクト変数や真のオブジェクト階層(オブジェクトモデル=オブジェクト式作成)の学習の邪魔でしかありません。特に初心者にとっては。
「Wth」なんか頻繁に使ってると、「マジで」、VBA的に「バカ」になってしまいます。
「With」は本来、「どうしてもWith使うしかしょうがないところ」だけに使えばいいもの、です。
それ以外はオブジェクト変数を使います。
どうしても、With使いたかったらいったんオブジェクト変数に代入してから、そのオブジェクト変数に対してWithを使えばいいです。
逆に、Withなんか使わずに、オブジェクト変数に代入する癖をつけると、「値やオブジェクトを返す自作関数化」「部品化」「2度手間減らし」がラクになり、ひいては、プロパティやメソッドの理解、オブジェクトブラウザの理解、ヘルプの理解、につながり、いちいち「Web検索なんか」しなくてもヘルプで数分でエラー解決できる場面が増えてきます。
プロパティもメソッドも「名前付き引数が使える」とか、「引数をカッコで囲む場合と囲まなくていい場合がある」等々が在るってことは、多分、「関数」、「プロシージャ」と似た仕組みで動いていると推測が立つわけですので。
そもそも、もともと「名前付き引数が使える」とか、「引数をカッコで囲む場合と囲まなくていい場合がある」っていうのは、メソッドだけのものじゃなくてプロパティはもちろん、「プロシージャ」のものです。
ヘルプにはっきりそう書いてあります。
そのような成長を阻害するのが「With」です。
VBAが「下の下のまま」「いつまでたっても」「上達しない人」の「100%」が、
「Withばっかり使ってる」。
「オブジェクト変数」を知らない、詳しくない。
「オブジェクトの階層構造」や、階層を省略しないオブジェクト式の書き方を知らない。
「値やオブジェクトを返す関数」を作れない。聴いたことも無い。
という状況のまま、です。
話がそれてすみません。
ただ、どうしても、「IF文」「For文(For Each文含む)」「エラー処理」だけでは賄えない時や、会社のお仕事のルールで、「Select Case文も、While文も、その他の文も、全部使わないとダメ」という場合は覚える必要があります。
もちろん、ゆくゆくは全部・・・というか、「Select Case文も、While文」あたりも覚えなければなりません。
でも、とりあえず、「IF文」「For文(For Each 含む)」「Do Until文」「エラー処理」だけでもなんとかなります。
個人事業主さまで、べつに誰からも何も言われない、なら、「IF文」「For文(For Each文含む)」「エラー処理」だけ知っていれば、今のマシンパワーならそれだけで、零細様の事務用プログラムならほぼ70%以上が作れてしまいます。
特に、エンドユーザーコンピューティングでは、「売るソフト」を作るわけじゃないですから、それで十分です。
Excelでゲーム作ったり、高度なシュミレーションしたり、など、コンマコンマ?一秒でも速く動かしたい、という状況ならダメですけど、そうじゃないなら、「IF文」「For文(For Each文含む)」「エラー処理」だけで十分 オーケーです。
そして、それらのことよりも、「参照≒VBAでの色んな操作対象の選択」の理解の深さ、や「SQL」の基礎のほうが大切です。私たち素人には・・・。(他のmdbやxlsファイル、docファイルのCOMオードメーションや参照設定での参照も含め)
あくまでも、プロのSEになるわけじゃなく、売るソフトを作るわけじゃなく、エンドユーザーコンピューティング、かつ、専任社内SEではなく、営業さんや経理さんのお仕事との兼任SEとして、のみ、の場合に限りますけど・・・。
特に「Access」や「AccessでのDAOやADOの操作」のプログラミングにおいては、それが顕著に言えると感じます。
売るわけじゃないソフトを作る場合、「参照」の知識が十分で深いなら、VBAの知識はそれなりで十分対応できるので、逆に、それ以外に「SQL(Excelで言う Microsoft Query の文字情報のほう)」の知識を増やしていったほうが、VBAだけを使うよりも、事務的なシステム限定なら、より効率よく、高度に作れるようになります。
非常に高飛車な態度ですみませんが、プロの方々の市販書籍やWebサイトでもこの点が十分に説明されていないので、初心者は独学において、「なんで?ちゃんと参照≒選択したつもりがエラー??」となり、右往左往することになってしまいます。
あるいは、メモデータベースのような小さなものは作れるけど、そこをほんの少し超えたものですら、自力で作れない・・・、「本当は市販の参考書以上のことがしたいのに、どうしていいか全然わからない」という状況に陥ってしまいます。
つまり、「参照」について、詳しく説明されていないので、「独学で挫折するのも当然」ということになってしまいます。
「参照」がVBAのスタートなので、それが分からなければ結局「スタートからつまづいているんだからそりゃ挫折も当然ですよね・・・」「スタートである、参照のしかた≒操作対象の指定のしかた、から、まず間違えているなら、それはもう もれなく100%挫折してしまいますよね・・・。"基本的な参照≒基本的な操作対象の選択"ができなければ、中級や上級の参照もできるわけないんですから・・・」ということになってしまいます。
今まではそれでも良かったのかもしれませんが、今後は子供さんたちが、より、プログラミングを学んでいく時代になっていくと思われます。
ですので、本当にエラそうな態度で申し訳ないのですが、僕目線、素人目線、エンドユーザー目線からなんですが、プロの方々におかれましては、このサイトよりも、もっと詳しい「参照」についてのご説明ができるはずなので、もっと、「参照」について、敏感に、ていねいに、詳しく、ご説明いただけたらなあ、と思います。
もちろん有料でもかまいませんので、子供さんたちのために、詳しくご説明してくださったらなあと思います。
近い将来お子さま方やお若い方々が、色んな意味で、「他国に負ける前に」「負けないように」「打ち負かすのではなく遅れを取らないか、できれば、やさしくリードできるように」、少しでも動いて頂けたら・・・と思います。
僕はこれで儲けるつもりはありませんけど、プロの方々なら、「参照≒選択が自由にできる生徒さん相手」になら、「どれだけでも教えられるネタ」「より高度なネタ」をいくらでも持っていらっしゃると思いますので、出し惜しみせず、どんどんと、「基礎の重要で深い部分」「エラー対策」「ヘルプの読み方」などを本当にどんどんと、無料で広めて「独学でやれる範囲の底上げ」をしてほしいと思います。
無料で基礎だけでも多くの人に広まれば、次の展開が必ずしやすくなると思います。
そこで儲けたいと思う方は、高度なネタはいくらでもあるはずなので、どんどん儲ければいいと思います。
関数のネスト技や合わせ技、VBAの基礎とか、そんなもので儲けようと思ったらいけないと思います。
そして、VBAの基礎、参照の多くの具体例、エラー対策、ヘルプの読み方、Excelでの仮説と検証の事例等々をどんどん無料で教えるべきです。
「仮説と検証」をするのにも、並べ替えだけでもできる、高度なシステムがなくてもできる、そいういう「仮説と検証」はいくらでもあるからです。
PDCAサイクル回しや5W1H活用、「問題の数値化」などもきっと同じだと考えます。
(特に「問題の数値化」は。)
今は、出し惜しみしすぎて、そういった基礎すら広まってない状況です。
これでは、いつまでたっても「お金をとってまで、しかし、基礎までしか教えられず、応用ができない」人しか育ちません。
これまでの20年がそうだったように。
これまでの20年のExcel教育で、会社が何か変わりましたか?
中小企業や零細企業に何か変革がありましたか?
Excelでいいこと、って、ありました?
僕は、「何も起こっていない」と思います。
「20年前と何も変わっていない」と感じます。
別に、いいことなんて起こってない、と思います。
いまだに、Excelやパソコンを「紙と電卓の延長とだけ」にしか使えない人が9割以上です。
Excelやパソコンを「真のコンピュータとしても両方」使える人は20年前からまったくと言っていいほど増えていません。
変わってるわけがないですよね?
「VBAを使える人が増えた」、と主張する人がいらっしゃるかもしれませんが、でもそのVBAにしても、ほぼ全員と言っても過言でないほど、「Excelやパソコンを 紙と電卓の延長とだけ」にしか使わない使い方のうえでのVBA利用のため「SQL」も全く知らず、「SQL」も全く知らないこと主なが原因で、本来なら書かなくていい無駄なコードをいっぱい書いている可能性があります。
おかしいと思いませんか?
20年も。
そんな風に放置されて続けていたのです。
「データ管理教育」は。「Excel教育」は。
こんなんでは、「プログラミング教育が大事」とか言っていますが、また結局「誰も育たない」とか、「潰れていく」、「一部の人だけ」、になってしまうのが目に見えています。
というか、火を見るよりも明らか、と言っても過言ではないかもしれません。
「20年も経ってるのに、Excelすら、紙と電卓レベルすら脱却させられないのに、プログラミング教育なんか成功するわけないじゃん」というのが僕の感想です。
行うべきは、ゲームプログラミングよりも、まずはデータベースプログラミングだと思います。
もちろん、とっかかりはゲームプログラミングで全然いいのですが、「多くの人に」とか「一般的な人としては社会に出てから役に立つように、助けになるように」「データに振り回されないレベルの最低限の知識を」・・・、と考えるとやっぱりデータベースプログラミングやSQLやピボットテーブルだと思います。
ビジネスシーンを想定した、データの整理のしかた、活用のしかた、のほうが多くの一般人の役に立つと思いますので。子供さん達も大半は「一般人」になります。
そこで、みんながみんな、データベースプログラミングやデータの管理が自分でできれば、みなさん、「ハイパー一般人」「ハイパー凡人」になれます。
僕はつねづね、「凡人やハイパー凡人がいるからこそ、エリートは成り立っている」とか、「凡人とハイパー凡人といなかったら、エリートは何もできない。パレートの法則からしてもエリートは人数が2割くらいしかいないから。凡人やハイパー凡人ナメんじゃねえぞ!というくらいのつもりで行ったほうがいい」と思っているのですが、その凡人やハイパー凡人が育つと思うのです。
ゲームプログラミングはゲームを心の底から愛している人だけが、更にさらに、頑張っていけばいいと思います。
その意味では、(有料でいいので)プロの方々の力も必要だと思いますが、それ以上に、学校教育で、特に商業科だけでなく、小、中、の義務教育や高校教育でも、簡単なゲームおよび、それ以上に「ピボットテーブル操作」から教えるのが大切かと考えます。
結局はそれが日本全体の、中小企業様や零細企業さま、個人事業様、の底上げのためになると信じています。
子供さんたちの未来にもつながると思っています。
もう、ついでのついで、なので、少し辛辣なお話をしてしまいますと、そしていちエンドユーザーの立場から言わせてもらいますと・・・、例えば前述の「Excelが出て20年もたつのに・・・」ということなんですが・・・、
「未だに ExcelVBAや関数のネストができる素人の人が現場に少ない、目に見える形で増えてない、のが現実」
「しかもシステム導入で本当に幸せになっているひとがそんなに多くないのも現実」
「は?エンドユーザーコンピューティング?(EUC?)寝ぼけてんの?と言われるのが現実」
「正直、20年前とほとんど変わっておらず、進歩していないのが現実」
「BI、BI、とエラそうに言ったところで失敗するのがオチ。ほとんど。Excelを使った仮説と検証やPDCAサイクル回し、問題の数値化すら風土化できていないのに、そんな企業がBIで成功するわけがない、というのが現実」
「”Excelで仮説と検証やPDCAサイクル回し・問題の数値化を風土化・・・”といったテーマの本やWeb情報を見たことが無いというのが現実」
「Excel=集計というより、Excel=きれいな作表、表作ってお仕事おしまい、どれだけ速く表を作るか、的な内容が多く、そもそもExcelでの集計が中小零細にとって、”真に役にたっている”とは思えないのが現実」
「きれいな作表、が本当に役に立っているのか?疑わしい。その仕事、その作表、Excelそのもの、すら、本当に必要?という状況なのが現実」
「ExcelVBA使えても一部だけで、多くは、誰のパソコンのどこに目的のデータが在るかすら不明。データの所在地が社内でぐっちゃぐちゃ。というのが現実」
「そんなExcelのぐっちゃぐちゃを解消しましょう~、UnitBaseなんていかが?SalesForceなんていかが?Access?だめだめ、あんなできそこない、という情報ばかりが増えているのが現実」
「SalesForceは数万社が利用しているけど、対費用効果が上がっている会社さまがどれだけあるか?UnitBaseもAccessVBAめんどうくさいという経験が無いと全く簡単じゃないので、対費用効果が上がっている会社さまがどれだけあるか?というのが現状」
「そしてそれらを導入しても成功する例は少なくほとんどが失敗する。ExcelでSQLの教育がなされないから。UnitBaseもAccessの操作性を知らないとまったく簡単じゃない。というのが現実」
「この20年間、Excelでなんか変わった?という状況なのが現実」
・・・のまま、なのは、繰り返しになりますが、やっぱり、プロの方々が「基礎の出し惜しみ」をしているからだと思います。
基礎なんかで儲けなくても、もっと高度なネタでどれだけでも儲けられるのに、基礎ごときで儲けようとしてるからです。Excelの老舗のWebサイトの先生がたのような大きなVBA他無料サイトは素晴らしいと思いますが、(大変失礼ながら)それ以外の何も公開していない先生方は特にそうだと思います。
出し惜しみしてなかったら、20年のうちに、20年経った今まさに、「多分3人に一人はExcelVBAができる、ピボットくらいは常識、Excelでの仮説と検証やPDCAサイクル回し・問題の数値化なんて常識だろ?ExcelVBA?見える化のために真っ先にグラフ動かしてなんぼだろ?ピボットやMSQUERY動してなんぼだろ?それ以外に自動シュミレーションや自動クロス集計表処理だろ?」、といった状況にもなってるはずで、そういうテーマが初級クラスの講義ばっかりになっているはずです。
「Excelを紙と電卓の延長としてだけ」でしか使えず、「真のコンピュータとしても両方」という形で使えない、という状況は、例えば「真の売上」のことを「あえてリピータ顧客様からの売上だけと定義する」ということをせず、「一回こっきりのお客様の分であっても売上げは売上だ」とカウントしてしまう甘い状況、と、「絶対にほんものにはなれない」という意味で同じだと思います。いつか、しっぺ返しがきます。
「一回こっきりのお客様の分も売り上げは売上だ」とカウントしても、その売り上げは、本当の売上じゃなくて「単なるお客様からのお恵み」だからです。
セブンの鈴木敏文先生が、「お客様の立場で考えれば必ず売り上げは上がる。が、売上が上がることは保証するが、お客様の幸せのことまでは知らんよ。」と思っているか思っていないかはわかりませんが、例えばそういうのとも同じです。
アベノミクス、成功したと言いたいのでしょうけど、私たち庶民の暮らしは何もラクになっていません。若い男子たちなんて「数年前からとても結婚なんてできない年収で変わる気配なんてあるわけない」とあきらめている人が増え続けていると聞きます。そういう「成功」とは とてもじゃないですけど呼べない状況と同じです。
ホンモノのほう、ホンモノに近づける方向を向けているかどうかといったら向けていないと思います。
子供さんたちが、将来ずっと、そんな状況のままでいいのか?ということなんです。
Excelが出て、20年も経つのに、この20年はずっとそうでした。
AccessもExcelも、書籍やWebサイトの内容については、もちろん、昔よりはわかりやすくなったとは思いますけど、でも「独学するには説明が少なすぎて挫折する少し難しいレベル」から脱却できてないのには、かわりはありません。VBAプログラミングについては、「初心者本までは理解できるけど、それ以上が急に、しかも、10倍以上、”難易度が上がる”」という状況を打破できていないと思います。もちろん掲示板で聞く方法もありますが、聞かなくてもある程度わかる、という、「基礎の、より詳しい教え方」が必要なのだと思います。
前置きが長くなりすぎて、すみません。
でも、全部、「参照」と直接的、間接的に、関係の深い、メチャクチャ重要なお話なので、どうか、ご理解ください。
では、まずAccessでの「参照」についての 素人エンドユーザー目線からの「一番の注意事項」からご説明させて頂きます。
★ 「超重要!!」Access2000VBAでの、各種「参照」における一番注意して欲しい点=「書き方」
AccessVBAでコードを書く上でもっとも重要な注意点です。
これを知っておかないと、あとでとても面倒くさいことになります。
それは、フォームやレポート、もしくは コントロール(テキストボックスやコンボボックス、コマンドボタンなど)を参照するときには、書籍やWeb記事、パソコン教室、MOS試験本、などでよく紹介される、「!」や「.」を使った参照をできるだけしないようにする・・・ということです。(サブフォームがらみの参照は「.Form」が出てくるのでやむを得ないですけど。また、ほかにも似たような状況があるかもですけど。でも私たちド素人は、メンテや引継ぎ、VBAへの理解や共用部品をつくる等々の意味でも、基本的には、できるだけ、「!」や「.」を使った参照をしない、ということで統一したほうが無難です。)
そのかわり、できるだけ(というか私たち素人の場合は「必ず」に近いです)、カッコとダブルクォーテーションを使用します。
例えば・・・、
「Forms("フォーム名")("テキストボックス名")」とか
「Me("フォーム名")("テキストボックス名")」等々・・・
・・・といった形で書く・・・ということです。(DAOやADOなどの「ミドルウェア」を扱う場合もです。)
1 2 3 4 5 6 7 8 9 10 11 12 |
' ' 'Forms!フォーム名!テキストボックス名 とか Forms.フォーム名.テキストボックス名 とか 'じゃなくて・・・ Forms("フォーム名")("テキストボックス名") 'と書きます ' 'Me!フォーム名!テキストボックス名 とか Me.フォーム名.テキストボックス名 とか 'じゃなくて・・・ Me("フォーム名")("テキストボックス名") 'と書きます ' |
お使いの書籍やWeb記事などと違うかったり、あまり紹介されていなくて怪しくお感じになるかもしれませんが、私たち素人は、基本、こちらのスタイルを守って、できるだけ「統一」してください。
理由は「のちのちの作り足し、作り変えがしやすくなるから」や、「のちのちの管理が少しでもラクになるから」「共用部品を作りやすくなる」「共用部品を多く作れば機能の実装もメンテもラクになるから」「統一することで、エラーや記述ミスを出にくくする」「書き換え時にコントロール名などを見つけやすい。特に置換技が有効でない時」等々・・・ということからです。
また、ExcelVBAでの参照(オブジェクトの取得)でも、同じ書き方をするので、『ExcelとCOMオートメーション機能で連携する』ような場合に、プログラムコード的にExcelとAccessが統一されるのでさらに分かりやすくなります。その理由も大きいです。
プロの方はこんなこと考えなくてもチャチャチャっと何でもやれてしまうのでいいのですが、私たち素人はメンテや引継ぎ、作り足し、作り変えが大変になると面倒なので、一応考えて、統一しておいたほうが無難です。
ちなみに、このスタイルを覚えておくと、例えばこんなこともできます。(プログラミング初心者の方にはまだ理解が難しいかもしれませんのですみませんが)
1 2 3 4 5 6 7 8 9 10 11 12 |
' ' Dim FormName01 As String Dim TbxName01 As String FormName01 = "f_売上入力画面" TbxName01 = "tbx_日付" Msgbox Forms(FormName01)(TbxName01).Value Msgbox Forms(FormName01)(TbxName01).ForeColor Msgbox Forms(FormName01)(TbxName01).Width ' |
上記の例だと、「f_売上入力画面」メインフォームの、「tbx_日付」テキストボックスの値や文字色、幅、がメッセージボックスに表示されます。
もしこれを、フォームの名前やテキストボックスの名前を変えたいときは、
FormName01 = "××××××"
TbxName01 = "×××××"
のところだけ修正すればいいだけなので、メンテがラクになります。
その他のメリットもあります。
また、こんなこともできますし・・・
(フォーム名だけ変数利用をしてテキストボックス名はベタ書きするとか・・・)
1 2 3 4 5 6 7 8 9 10 |
' ' Dim FormName01 As String FormName01 = "f_売上入力画面" Msgbox Forms(FormName01)("tbx_日付").Value Msgbox Forms(FormName01)("tbx_時刻").Value Msgbox Forms(FormName01)("tbx_入力者").Value ' |
・・・こんなこともできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
' ' Sub MsgboxTest01(FormName01 As String , TbxName01 As String) Msgbox Forms(FormName01)(TbxName01).Value Msgbox Forms(FormName01)(TbxName01).ForeColor Msgbox Forms(FormName01)(TbxName01).Width End Sub ' ' '同じモジュール内のイベントプロシージャなどで以下のコードを実行 Call MsgboxTest01("f_売上入力画面" , "tbx_日付") ' ' |
上記の例だと、「Call・・・」の行が実行されると、「Sub MsgboxTest01 ~ End Sub」の部分までが呼び出されて、その中の3行のプログラムが実行されます。
つまり、「f_売上入力画面」メインフォームの、「tbx_日付」テキストボックスの値や文字色、幅、がメッセージボックスに表示されます。
(初心者のかたにおかれましては、詳しい説明がここではできずにすみませんが、ばくっとしたイメージだけでも持ってもらえたら嬉しいです。「FormName01」と、「TbxName01」を追いかけてみてください。)
・・・というわけで、詳細というかすこしの補足につきましては、「服屋さん時代に自分で作って使っていた、Access2000での、自作のバーコードPOSレジのmdbファイルのダウンロード(サンプルダミー売上データ付き)」のところでも書いたので、そちらの内容をそのまま転載します。
Access2000VBAを始める前に、必ずお読みください。
まだ始めてすぐでしたら、これまでのものをできるだけ変えるか、面倒なら、今後からだけでも、カッコとダブルクォーテーションを使う方法に切り替えてください。
Excel2000VBAではどうなのかわかりませんが、同じようなことがあるかもしれません。(とりあえずExcelの「ユーザーフォーム」では同じことが言えます。)
※以下の転載部分では、「!」のことについて多く書いてありますが、「.」を使っての参照も同様です。「.」での参照も、基本、やらないようにします。
※また、通常のAccessVBA以外にも、DAOやADOといった「ミドルウェア」で、テーブルやクエリなどのレコードセットの列を参照する場合も同じです。
「rs("フィールド名")」のようにカッコとダブルクォーテーションを使って記述・統一します。「.」や「!」を使うことは、基本、やらないようにします。
====転載部分ここから====
◎VBAプログラムのことで、できればマネしてほしくないこと
これ作ったときはまだ初心者でしたのでほんとになんにも分かってないので基本的に全部、マネしないほうがいいと思うのですが、特にマネしてほしくないのが(今もダメなままなのでその他のことも あまりマネしないほうがいいかもですけど)・・・・
本バーコードPOSレジのVBAコードでは、フォーム上のテキストボックスなど、各コントロールを参照する際に、「!」を使って、例えば「Me!テキスト123」のように書いてしまってしますが、これはできればマネしないほうがいいかもです。
例えば「フォーム01」というフォームの上に配置してある、「氏名」というテキストボックスを参照する場合は、
Forms("フォーム01")("氏名")
とか、
Me("氏名")
とか、
「!」を使わずに、各コントロールやフォームの名前を "" で囲んでさらに( )で囲むような形を取ったほうがいいとは思います。
というのも、このスタイルでコントロールを参照すると、Me("氏名") の "氏名" の場所に文字列型の変数を入れる(使う)、あるいは、「数値型の変数 & 何らかの文字列」を使うことができるからです。
それができると変数を用いてループやオブジェクト変数処理などがやりやすくなります。
ひいては、共用部品や共用関数などが作りやすくなって、フォームや部品がだだくさに増えていくことを抑えられます。
共用部品や共用関数などが増えれば、バグや仕様変更・機能追加等々で修正したい場合も修正箇所も減ることにになり管理がしやすくなります。色々とメリットが多いです。
もちろん、「!」を使うのも自由なのですが、最低限、「どちらのスタイルを常用するか?」くらいは決めておくと、あとで修正がしやすいかもしれません。
常時「!」を使って、共用部品のところだけ( )と"" を使うか、あるいは逆に、常時( )と"" を使ってどうしても「!」じゃないとダメなときや「!」を使って何かの区別をしたいところだけ「!」を使うなど、役割を持たせると良いと思います。
僕は今はどちらかというと後者ですけど、「!」は全く使いません。
その他の参照方法 ~ FormsコレクションによるFormオブジェクトの参照例
1 2 3 4 5 6 7 8 |
' ' ' 構文 使用例 Forms!formname Forms!受注フォーム Forms![form name] Forms![受注 フォーム] Forms("formname") Forms("受注フォーム") Forms(index) Forms(0) |
ちょっとは話がズレてしまいますが、上記のように色々な方法がありますが、「Forms("受注フォーム")」のようなスタイルが、"" とか、( )とか、少し文字数は増えてしまうものの基本的にはのちのちの面倒がないので、この書きかたで統一してしまうことを僕個人としてはおすすめします。
テキストボックスや、サブフォームなど、各種コントロールも同じです。
====転載部分ここまで====
なお、Forms("受注フォーム") のようにカッコとダブルクォーテーションを使ったかたちで書くと、下図のような入力支援機能が働かなくなります。
それだけがデメリットなのですが、ただ、コントロール名やフォーム名、レポート名などのあとにくる英単語(命令語めいたもの)は、「実際に使うもの」は、そうは数はないですので、それほど大きなデメリットにはならないと思います。
どんな命令語句が使いたいか調べたくなったら、そのときだけ「!」や「.」を使って調べ、調べ終わったらカッコとダブルクォーテーションの形式に書き換えればOKです。
もしくは、他のコードからコピペしてもいいし、Caption、Value、××Color、など、よく使うものは、「テキストファイルにリファレンス的にメモしておいたもの」を常時開いておいて、そこからコピペしても良いと思います。
注意事項は以上です。
では以降で、いろいろなフォーム部品やレポート部品、その他、等々の参照の仕方をご紹介します。
★ VBE(Visual Basic Editer)上でのコピペ(特に単語単位・コントロール名単位の選択)はテキストエディタよりもラクです。ドラッグ不要でダブルクリックするだけなので。
★ 参照の方法いろいろ
・メインフォームとサブフォームの場合
現在開かれているメインフォームの参照
(メインフォーム=サブフォームを持たないフォームも含まれます。また、フォームビューでもデザインビューでも開かれていさえすれば、参照可能です。閉じているフォームはこの方法では参照できません。といいますか、閉じているフォームは名前くらいしか参照できなかったかもです。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
' ' '▼ メインフォームの参照の方法(書き方) Forms("メインフォーム名") '例 '「顧客入力フォーム」にフォーカスをあてる例 '=「顧客入力フォーム」がアクティブになります。 Forms("顧客入力フォーム").SetFocus '複数のフォームが開かれている場合に、 'イミディエイトウィンドウで1番最初に開かれたフォームの名前を調べる例 ? Forms(0).Name ' |
1番最初に開かれたフォームは、もし名前がわからなくてもForms(0)と番号を指定して参照することができます。2番目に開かれたフォームは、Forms(1)と指定できます。(番号→インデックス番号などとも呼びます。「配列」と呼ばれる仕組みのインデックス、要素数、要素番号、と同じ意味です。)
ですので複数のフォームが開かれている場合に、例えば VBE(VBEditor)のイミディエイトウィンドウで、「? Forms(0).Name」とコピペ(「」除く)してEnterすると、1番最初に開かれたフォームの名前が表示されます。また、「? Forms(1).Name」とコピペEnterすると、2番めに開かれたフォームの名前が表示されます。(コンピュータの場合、数を数えるときに1からではなくて、0から数えることが多いです)
なお、サブフォームを持つフォームの場合、メインフォームの名前だけが表示されます。
※「Forms("xxxxxx")」という形になっているときは必ずメインフォームをさしています。あるいはサブフォームを持たないフォームです。サブフォームがこのかたちで表現されることはありません。
※また、「Forms("xxxxxx")」という形で参照できるのは、今まさに開かれているフォームのことだけをさします。閉じているフォームはこの方法(構文)では参照できません。ただ、開いてさえいれば、フォームビューでもデザインビュー(デザイン画面時)でも参照できます。デザイン画面であってもテキストボックスなども参照できます。ですので、プログラムによっては、「画面の絵の描画・更新を一時ストップさせる→バレないようにデザインビューにしちゃう→デザイン画面でいろいろいじる→上書きして再度フォームビューで開く→何事も無かったかのように画面の絵の描画を再開させる」ということが瞬時にできます。Excelの場合も画面の描画を止めることでこれができますが、デザインビューでもフォームやコントロールがこの式・構文で参照できるため、Accessでも似たようなことが可能です。
初心者の方におかれましては、「へえー、そんなことできるんだあ~」とだけで結構ですので覚えておいてください。このような仕組みは、「Excelユーザーフォームの50倍、効率的なAccessフォームを作る方法(2つのカード形式画面の区別とサブフォームの利用)」でお話させていただいたような、3画面に切り替えられるフォームを作るときに使います。
※ちなみにですが、「Forms」の意味は「s」と複数形になっていますので、「複数のフォームの中の」という意味です。ただ、この場合も「今開かれているフォーム」ということは同じです。そして「開かれてさえいればフォームビューでもデザインビューでもどちらでもいい」ということにも変わりはありません。
なので、「Forms = 現在開かれた1つの・又は複数のフォームの中の・・・、」という意味になります。
といいますか、「Forms」と書いた時点で、「今開かれているフォーム達・・・」のことを指し、そして、開かれたすべてのフォームのうち、「開かれてさえいればフォームビューでもデザインビューでもどちらでもいい」ということになります。(デザインビューであっても「開かれた」モノだ、という意識にします。)
操作対象を 「今開かれているフォーム」「開かれてさえいればフォームビューでもデザインビューでもどちらでもいい」という状態にしてくれているのは「Forms」という単語です。
それに対して「AllForms」(後述します)という単語が出てきた場合は、これも「s」が付いているので複数形ですが、「現在開かれてないものも含め、mdbの中に作られたすべてのフォーム」という意味になります。
なお、「s」がついたものは「コレクション」と呼ばれる「オブジェクト」の一種です。
「コレクション」はオブジェクトの集合体であり、単発オブジェクトを「配列」という仕組みのように扱うことができる・・・そういう仕組み・そういうオブジェクトです。フォームをフォームの名前で参照せずとも「一番最初に開かれたフォーム」・・・、つまり、「Forms(0)」という形で番号(Index)参照できるのも、「Forms」がコレクションであり、開かれたフォームに対して配列のような使い方がきるからです。コレクションにはその他の利点もあります。
「オブジェクト」については、以下の記事を参考にしてみてください。
用語:VBAプログラミングでの「オブジェクト」 について
現在開かれているサブフォームの参照
(こちらも、メインフォーム=親フォームとともに、フォームビューでもデザインビューでも開かれていさえすれば、参照可能です。閉じているサブフォームはこの方法では参照できません。といいますか、閉じているフォームは名前くらいしか参照できなかったかもです。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
' ' '▼ サブフォーム(子フォーム)の参照の方法(書き方) ' Forms("メインフォーム名")("埋め込みコントロール名").Form ' ※一見、「Forms("メインフォーム名")("サブフォーム名")」じゃないの?と '思いがちなんですが、実は、サブフォームを作る際、まず先に自動的に、 '「埋め込みコントロール」という種類の「枠」「入れ物」 '「掘りごたつ的なくぼみ的なもの」みたいなものが自動生成されます。 'そしてサブフォームは実は その中に格納されるので、2段階を経るかたちになります。 'なので、 '「Forms("メインフォーム名")("サブフォーム名")」じゃなくて、 '「Forms("メインフォーム名")("埋め込みコントロール名").Form」という形でないと、 'サブフォームを指定(参照)ができない仕組みになっています。 'なお、「.Form」がサブフォーム本体です。 'また、「.Form.Name」と書くと、サブフォームの名前をゲットできますが、 '埋め込みコントロールの名前がその名前と同じになることがほとんどです。 '意識的に変えない限り、Accessが勝手に「埋め込みコントロール名=サブフォーム名」 'という形で、自動的に埋め込みコントロールの名前を付けてくれます。 'なので、そのあたりと自分の意識において知らないうちにズレが生じていると、 'サブフォームがらみのプログラムコードを実行する時点でエラーになります。 'つまり、埋め込みコントロール名とサブフォーム名が何らかの理由で '異なる内容になってしまっているときがあるのですが '(自分で変えておいて忘れてることもあります)、それを知らずにいると、 'その関係でエラーが出やすいです。 '「埋め込みコントロール名=サブフォーム名」の場合がほとんどだけど、 '明示的に自分が変えた場合や自動的じゃないサブフォームの作成をしたときなどに、 'それらの名前が異なってくるので注意が必要です。 ' |
サブフォームを作ると、下図のように、Accessが勝手に、埋め込みコントロール名とサブフォーム名を同じに設定してくれる場合がほとんどです。(操作ミスすると異なる名前になるかもしれません。意図的に変えた場合は当然異なる名前になります)
これを、プログラムの都合に合わせて、意図的に変えても問題ありません。ただし、変えたいときは埋め込みコントロールのほうの名前だけを変えます。
サブフォーム名は実在するフォームの名前ですので、変えるとそのフォームが表示されなくなってしまいますので、変えてはいけませんが、埋め込みコントロール名は自由に変えられます。
VBAコードを書いていて、サブフォームがらみでエラーが出るときは、まずはここのプロパティを確認して、埋め込みコントロール名(上図の「名前」の部分)とサブフォーム名(上図の「ソースオブジェクト」の部分)が同じか違うのかをチェックしてから、次のチェックへ進みます。
ちなみにですが、サブフォームを手動で作るときは、まず最初にメインフォームに埋め込みコントロールを作って、それからその中に、既存のフォーム(サブフォームとして表示したいフォーム)を表示できるように、プロパティ設定をします。
手順としては、以下のような流れです。
サブフォームの参照の事例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
' ' '▼ 「売上入力画面」メインフォームの中の、「売上明細画面」サブフォームを ' 参照する例 ' '(a)サブフォームを包み込む 埋め込みコントロールの名前が、 ' サブフォーム自体の名前と同じ場合の、 ' 埋め込まれたサブフォームを参照する例(ほとんどの場合がこちらです) ' Forms("売上入力画面")("売上明細画面").Form ' ' '(b)サブフォームを包み込む 埋め込みコントロールの名前を、 ' サブフォーム自体の名前とはあえて異なる名前に変更し、 ' そしてそれに「埋込_明細」という名前を付けた場合の、 ' 埋め込まれたサブフォームを参照する例 ' Forms("売上入力画面")("埋込_明細").Form ' ' '※上記の2つの例は、いずれも、 ' 『埋め込みコントロールの名前さえ分かっていれば、 ' 実際に埋め込まれているサブフォームの名前はわからなくても、大丈夫。 ' なぜならサブフォームは、 ' (Accessにモトから組み込まれている)「.Form」という単語で、 ' 「参照できている」から・・・』、 ' ということになります。 ' '*******以下、補足説明***************************** ' 'イミディエイトウィンドウで以下のように書いてEnterすると、実在のサブフォーム名 'が表示されます。ただし、これは前述の説明tのとおり、埋め込みコントロール名と '異なることもあります。 ' Forms("メインフォーム名")("埋め込みコントロール名").Form.Name ' 'なお、 Forms("メインフォーム名")("埋め込みコントロール名").SourceObject = "サブフォーム名01" 'と書いて実行したあとに、どこか別のタイミングで、 Forms("メインフォーム名")("埋め込みコントロール名").SourceObject = "サブフォーム名02" 'と書いて実行すると、 '最初 埋め込みコントロールの中身として、「サブフォーム名01」というフォームが '表示されていたのが、「サブフォーム名02」というフォームに表示が切り替わります。 'このようなときは「.Form」を使いませんが、このあたりの区別の仕方は 'またどこかで・・・。 |
サブフォームの参照のおさらい
サブフォームを参照するときは、名前として出てくるのはメインフォーム名と埋め込みコントロール名だけです。
純然たるサブフォームの名前は「参照式には出てきません」ので、少し混同しやすく、わかりにくいですね。(下図参照)
「サブフォーム =
メインフォームの中の、埋め込みコントロールの中の、フォーム(.Form)・・・」
(サブフォームのほんとの名前はわかんないけど・・・)
という感じになっちゃってます。
ただ、ウィザードを使ってサブフォームを作ると、Accessが自動的にサブフォーム名と同じ名前を、埋め込みコントロール名に設定してくれるので、その場合に限っては、純然たるサブフォーム名を書けばOK、ということになります。
最終的には、『 埋め込みコントロールのプロパティの、「名前」の内容を書かないと、サブフォームは参照できない・・・』というかたちになります。
閉じたフォームの参照
Access2000では、たしか、閉じたフォームの参照は「できない」ということだったかと思いますが、プロの方に聞けばできる方法をご存知かもしれません。(フォーム名くらいは参照できたかも・・・。「CurrentProject.AllForms」で参照できるものは、閉じているフォームに対しても参照ができたかと思います。)
また、最新のAccessなら、いろんな参照ができるのかもしれません。
なお、フォームが開かれていない状況や見えていない状況で、フォームやその中に配置されている各コントロール(テキストボックスやコマンドボタン等々)に対して何か自動処理をしたいときは、次のような方法があります。
(a)フォームをVBAで自動で「デザイビュー」で開き、そこで普通に参照する。(フォームを介してデータ・値を取得したり集計したりする必要が無いとき)
(b)フォームをVBAで自動で「フォームビュー」の「非表示」モードで開き、そこで普通に参照する。開いていれば非表示でも参照式で参照できます。(フォームを介して、フォームに表示された データ・値を取得したり集計したりしたいとき)
フォーム上のコントロール(テキストボックスやコマンドボタンなど)の参照
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
' ' '▼ 「顧客データ入力画面」フォーム上の「氏名」テキストボックスの値の参照の例 ' Forms("顧客データ入力画面")("氏名") 'もしくは、 Forms("顧客データ入力画面")("氏名").Value ' '※↑「.Value」は省略できます。逆に、テキストボックスやコンボボックスなど、 ' 何らかの値を入力するコントロールの名前のあとに何も書かれていなかったら、 ' 必ず「.Value」が省略されていると思ってください。 ' それ以外の、例えば コマンドボタンなど、「値の入力ができないコントロール」の ' 名前のあとには、何も省略できません。必ず「.Caption」とか「.SetFocus」とか、 ' 「.~~~」といった感じで、何らか英語の語句が続きます。 ' 続けないとエラーになります。 ' '▼ 「顧客データ入力画面」フォーム上の「検索実行」コマンドボタンの横の長さの参照例 ' Forms("顧客データ入力画面")("検索実行").Width ' ' '▼ 複数のフォームが開いている状態で、そのなかで「顧客データ入力画面」フォームが ' 一番最初に開かれたフォームだった場合、その場合の「検索実行」コマンドボタンの ' 横の長さの参照の例 ' Forms(0)("検索実行").Width ' '※↑これは特殊な例ですが、フォーム名で参照するのではなく、フォームが開いた順番で ' そのフォームのコントロールを参照したい場合にこういうこともできます。 ' ほとんど同じような構造のフォームを、種類を変えて、何らかの自動化をしたいときに ' そういうことをする場合があります。 ' ちなみに、もし、二番目に開いていたら「Forms(1)("検索実行").Width」となります。 ' コンピュータは、ゼロから数えることが多いのですが、VBAの場合も、ほとんどが、 ' 0が一番で、1が二番、2が三番目・・・といった感じになります。 ' ' ' |
「("顧客データ入力画面")("氏名")」のように、カッコとダブルクォーテーションで囲まれたところは ぱっと見が、「Forms」とか、「Value」、「Name」、「Docmdac----」、・・・などのようにAccessにもとから組み込まれている命令の単語とは違います。
ですので、プログラミングの初心者にとってみると、その違いが視覚的に「違うと分かる」だけでも、つまり、命令語部分とそうじゃない部分とが視覚的に区別しやすいだけでも、プログラムの記述ミスを発見しやすくなったり、プログラムを読むこと自体も読みやすくなったりすると思います。
サブフォーム上のコントロールの参照
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
' ' '▼ 「売上入力画面」メインフォームの中の、「売上明細画面」サブフォームの ' 「商品ID」テキストボックスの値を参照する例 ' '(a)サブフォームを包み込む 埋め込みコントロールの名前が、 ' サブフォーム自体の名前と同じ場合の例(ほとんどの場合がこちらです) Forms("売上入力画面")("売上明細画面").Form("商品ID") 'もしくは Forms("売上入力画面")("売上明細画面").Form("商品ID").Value ' ' ' '(b)サブフォームを包み込む 埋め込みコントロールの名前を、 ' サブフォーム自体の名前とはあえて異なる名前に変更し、 ' そしてそれに「埋込_明細」というコントロール名を付けた場合の例 ' Forms("売上入力画面")("埋込_明細").Form("商品ID") 'もしくは Forms("売上入力画面")("埋込_明細").Form("商品ID").Value ' ' ' |
※ (a)の場合も、(b)の場合も、埋込コントロール内に埋め込まれたサブフォーム自体の名前が、同じ「売上明細画面」なのであれば、同じサブフォームの「商品ID」テキストボックスの値を見に行っていることになります。
言い換えると、例えばデザインビュー等で2つのサブフォームを比較して見て、かつ、そのプロパティを見たときに、もし2つのサブフォームの間で「名前」の内容が異なっていたとしても、「ソースオブジェクト」の内容が同じなら、同じフォームを「サブフォーム」として埋め込んでおり、「商品ID」テキストボックスも、同じフォームのそれを覗きに行っている、ということです。
このあたりのことを、体で覚えるというか、理解できると、サブフォームとして埋め込むフォームを、プログラミングでくるくると入れ替えることができます。
自分達の都合に合わせて、見せ方を変えたり、サブフォームのソースとなるレコードの入れ替えなどもラクになります。
1つのメインフォームをいくつかの状況にあわせて、見せ方を変化させることができるので、フォームを作り込む数を減らし、管理をラクにすることもできます。
初心者の方におかれましては、言ってる意味がよくわからないとも思いますので とりあえず、「埋め込みコントロール名とサブフォーム名は似て非なるもの なんだな・・・」ということと、その「違い」理解をすることで & 何度か体験することで、「フォームの作り込み量が減らせる=ラクできるんだな・・・」とだけ覚えておいてください。
「Me」キーワードを使っての参照
Access2000にはプログラムを書く場所として、大きく分けて・・・
「Microsoft Access クラス オブジェクト」という場所と、
「標準モジュール」という場所の2か所があります。(下図参照)
「Microsoft Access クラス オブジェクト」という場所には、各フォームや各レポートごとに「モジュール」と呼ばれる単位に切り分けれており、そしてその各モジュールの中に、「イベントプロシージャ」と呼ばれる各プログラムが格納されます。(普通のプロシージャも格納されます。イベントプロシージャと普通のプロシージャの2つが格納できます。)
また、「標準モジュール」は、共通部品といいますか、共通プログラムなどを書くことが多いのですが、個々に自由にモジュール名を決めてモジュールを切り分け作成できます。
そしてそのなかに、イベントプロシージャとは違う、標準のプロシージャを格納しています。
「Me」キーワードでの参照は、「Microsoft Access クラス オブジェクト」のほうだけで使える参照方法です。(標準モジュールでは使えません。)
「Microsoft Access クラス オブジェクト」の中であれば、「イベントプロシージャ」内でも「普通のプロシージャ」内でも使えます。
フォームやレポートの上に配置されたコントロールを参照するのに使います。
例えば、『 「顧客データ入力画面」フォーム上の「氏名」テキストボックスの値 』を参照する場合、標準モジュール(すなわち標準のプロシージャ)では、これまでご説明させていただいたとおり、
1 2 3 4 5 |
' ' Forms("顧客データ入力画面")("氏名") 'もしくは、 Forms("顧客データ入力画面")("氏名").Value ' |
と書かないといけませんが、これがイベントプロシージャの中では、
1 2 3 4 5 |
' ' Me("氏名") 'もしくは、 Me("氏名").Value ' |
と書いてもいいよ!ということになっています。
この例だと、「Meとテキストボックス名だけでいいよ!」ということです。
かなり省略できて、コードが読みやすくなりますよね。
コントロールから見た自フォームというか、親フォームというか、そういうフォームに限ってだけ、「Me」を使って自フォーム名を省略できます。
もちろん、イベントプロシージャの中ででも、
1 2 3 4 |
' Forms("顧客データ入力画面")("氏名") 'もしくは、 Forms("顧客データ入力画面")("氏名").Value ' |
のように書いても問題ありません。
なお、Meを使えるのは自フォームだけで、他のフォームのコントロールを参照する場合は、これまでどおり、
1 2 3 4 5 |
' ' Forms("顧客データ入力画面")("氏名") 'もしくは、 Forms("顧客データ入力画面")("氏名").Value ' |
のように書きます。
これはフォームだけでなく、レポートの場合も同じです。
他のフォームのコントロールを参照する場合に「Me」を使うとエラーになります。
また、標準モジュールでも「Me」を使うとエラーになります。
たとえば、フォームのイベントプロシージャの一部を共通部品化しようとおもって、標準モジュールのどこかにコピペなどをした際に、「Me」を修正し忘れるとエラーになります。
また、サブフォームのコントロールを参照する場合にも もちろん「Me」キーワードは使えます。
サブフォームのコントロールを参照する場合は、長くなりがちなので、以下のように省略できるとやっぱりすっきりしてきます。(サブレポートも同様です。)
1 2 3 4 5 6 |
' ' Forms("売上入力画面")("売上明細画面").Form("商品ID") ' ↓ Me("売上明細画面").Form("商品ID") ' |
「Me」と出てきたら、イベントプロシージャだな、とか、自フォームや自レポートのことだな、とか思えばOKです。
サブフォーム上のコントロールにフォーカスがある場合メインフォームのコントロールの参照
1 2 3 4 5 6 7 8 |
' ' Forms("コントロール名") でOKです。 イベントプロシージャなら、 Parent("コントロール名") でも、OKです。 |
・ アクティブなフォームやコントロールの参照方法(VBEditorのイミディエイトウィンドウにて利用する例。もちろん、通常のVBAコード内でも使えます。)
以下の例は、例えば、名前や値などを参照している例です。
「.name」で終わっているものは、名前を取得します(あるいは、画面に表示させます)
「.value」で終わっているものは、値を取得します(あるいは、画面に表示させます)
なお、「.value」は省略できます。(書かないでおくと、「.value」を書いたとみなされます)
それ以外の「.recordcount」などは、またどこかで、いい説明文が思いついたら ご説明させていただきます。
なお、「アクティブ」とは、フォームやレポートの場合では、フォームビューであってもデザインビューであっても、どちらであっても、「今現在 フォーカスのあるコントロール 、フォーム、レポート」のことをさします。
例えば、フォームやレポートがデザイン画面になっているときでも、イミディエイトウィンドウで・・・、
「? Screen.ActiveForm.ActiveControl.name」
・・・とコピペしてEnterすれば、現在アクティブなフォームのデザイン画面の中で、フォーカスの在るコントロール(テキストボックスやコマンドボタン、サブフォーム、サブレポート、その他)の名前が表示されます。
今はよくわからないかもしれませんが、デザイン画面でも以上のように コントロール名を参照できると、意外と便利です。プログラムコードが書きやすくなる場合があります。また、定型的なプログラムコードなら、プログラムコードそのものを自動生成させることも可能となります。
※記述忘れ。すみません。
フォームのコントロールの何らかのプロパティの値を参照する場合、プロパティによってはデザインビューだとエラーになることがあります。例えばテキストボックスの「Value」プロパティはそうで、フォームビューのときしか参照できません。デザインビューではエラーになります。コンボボックスのcolumnプロパティも同様にデザインビューの時に参照しようとすると「デザインビューではダメ」みたいなエラーになります。Nameプロパティはどのどちらのビューでもダイジョブですが。
プロパティによっては、デザインビューでは使えない場合があることを覚えておいてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
' ' ' '●フィルタがかかったクエリのレコードセットを参照する '(アクティブなクエリ(or テーブル or データシートフォーム)のフィルタがかかった状態での件数チェック) ? screen.ActiveDatasheet.recordset.recordcount '●アクティブなクエリ(or テーブル or データシートフォーム)にて、次のレコードへ移動 ? screen.ActiveDatasheet.recordset.movenext '●アクティブなクエリ(or テーブル or データシートフォーム)の特定の列のアクティブなセルの値を取得。 ? screen.ActiveDatasheet("列名").value '●アクティブなクエリ(or テーブル or データシートフォーム)のアクティブなコントロール(tbxやcbxなど)の値を取得 ? screen.ActiveDatasheet.ActiveControl.value '●アクティブなメインフォームの参照(サブフォームは参照できない) ? Screen.ActiveForm.Name '●アクティブなコントロールの親の参照(メイン、サブフォーム両方とも) ? Screen.ActiveControl.Parent.name '●フォーカスがある場所がサブフォームだった場合の サブフォームコントロール/サブレポートコントロール (埋め込みオブジェクト)の参照 ? Screen.ActiveForm.ActiveControl.name '●フォーカスがある場所がサブフォームだった場合の埋め込まれているサブフォームの参照 ? Screen.ActiveForm.ActiveControl.form.Name '●フォーカスがあるコントロールの参照(メイン、サブフォーム両方とも) ? Screen.ActiveControl.name '●フォーカスがある連結コントロールの連結先の参照(メイン、サブフォーム両方とも) ? Screen.ActiveControl.ControlSource '●サブフォームのフィルタ条件文の参照 ? Screen.ActiveForm.ActiveControl.form.Filter '●アクティブデータシート(テーブル or クエリ or データシートフォーム)のカレントセルの値 ? screen.ActiveDatasheet.Form.ActiveControl 'もしくは ? screen.ActiveDatasheet.ActiveControl.value '●アクティブデータシート(テーブル or クエリ or データシートフォーム)のカレントセルの列名 ? screen.ActiveDatasheet.ActiveControl.name ' ' |
※「カレント」も「アクティブな」とか「フォーカスがある」という意味にとらえてください。本来は「現在の」という意味です。
※「セル」という言葉はほんとうはAccessでは使いませんが、当サイトではそのほうが意味がとりやすく、Excelとの連携時の説明もしやすいので、「セル」という言葉をあえて使っています。あらかじめご了承ください。(こちら もご参照ください。)
※上記は、「Screen」という命令語を使用する場合の例です。Screenを使うと、「現在フォーカスの在るテキストボックスやセル=現在アクティブなそれら」に限りますが、フォーム名やテキストボックス名が分からなくても、その値、あるいはプロパティ設定値の一部を参照・取得することができます。実際のプログラムの中では「どうしても」という場面以外は使わないほうが良いと思いますが、メンテの時など、便利な場面もあるので覚えて損は無いと思います。(特に、オブジェクト名やコントロール名の取得のときなどに便利です。)
・Excelで言う「セル」に相当する1マスの参照(値の取得のみ。テーブル・クエリ両方とも。開いている・閉じている両方とも。フォームやレポートは無関係です。)
Accessには「セル」という概念がありません。なので、1マスを参照(選択、値の取得)をするのに「A1」「C10 」といったような簡単便利な指定ができません。なのでAccessの場合は、例えば「Dlookup関数」などを使います。
Dlookup関数では以下のように1マス(Excelで言う1セル)を参照します。
DLookUp("列名","テーブル名","行を特定する条件式")
「行と列のクロスする部分を指定して1マスを表現する」という概念はExcelと同じなのですが、ただ、実際の指定方法が異なっていて、しかも、ちょっと面倒です。Excelでは「A列の1行目」、のように指定できますが、Accessの場合は「列名」と「行」の「実際の何らかの値」を使わなければなりません。
慣れればそう面倒でもなくなってはくるのですが、慣れるまでがちょっと・・・。
例えば下図のようなテーブルの場合、赤枠の「キャベツ」のセルを参照したい場合を考えてみます。(当サイトでは便宜上、ひとマスのことを「セル」と呼んでいます。理由は→こちら)
このとき、テーブル名が「お買い物日記」だとすると、「キャベツ」セルを参照するには、以下のような参照式になります。Accessの場合だとクエリという機能の中で使ったり、あとはVBA上でもこのままを書いて参照できます。(つまりクエリやVBAの中で使えます)。
1 2 3 4 |
' ' DLookUp("品名","お買い物日記","レシートID=2") ' |
なお、Dlookup関数のほかに、「SQL」というもので参照することもできます。Dlookup関数同様、クエリという機能の中で使ったり、VBA上だとSQL文そのものを書いて参照します。(こちらもクエリやVBAの中で使えるということです。)
「SELECT 列名 FROM テーブル名 WHERE 行を特定する条件式;」といった形で書きます。
↓実際にはこんな感じで指定します。
1 2 3 4 |
' ' SELECT 品名 FROM お買い物日記 WHERE レシートID=2; ' |
また、「DAO」や「ADO」といった「ミドルウェア」と呼ばれるものもありますが、その際もSQLが使えます。(前述の式がまんまで使えます。)SQLのほかには、「まず指定した行へ移動してから、列を指定してクロスする場所のセルの値を参照(取得)する」といったこともできます。
例えばDAOの場合は例えば以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
' ' Option Compare Database ' '============= ' '「SQL」を使う例 Sub test01() Dim db As DAO.Database Dim rs As DAO.Recordset Dim sql01 As String '今開かれているmdbファイルを操作対象とする設定にします。 Set db = CurrentDb 'まずは1つのセルを指定して、セルとしてではなく「表=テーブル」として取り出します。というか、SQLを使うときは常に「表として」取り出されます。セルとしてではなくて。でもここででは表の範囲をものすごく小さくして「1マス」として取り出してしまっているので、「1セル」という表現をしてしまっています。 sql01 = "SELECT 品名 FROM お買い物日記 WHERE レシートID=2;" Set rs = db.OpenRecordset(sql01) '表=セルの値の参照 '1つのみのセルを「表として」取り出した場合は、常に「rs(0)」という決まりきった書き方で参照可能です。(つまり「rs」の列の要素=列としての番号が常に「ゼロ」ということです。) '「rs(0)」は「列名はわからないけどとにかく一列目」という意味です。行移動の命令を書かない場合は必ず1行目の値が取得されます。 Debug.Print rs(0) End Sub ’============= ’「まず指定した行へ移動してから、列を指定してクロスする場所のセルの値を参照(取得)する」例 Sub test02() Dim db As DAO.Database Dim rs As DAO.Recordset Dim jyoukenn01 As String '今開かれているmdbファイルを操作対象とする設定にします。 Set db = CurrentDb 'まず「お買い物日記」テーブル全体を参照します。(=テーブルの中に入り込みます=取り出します) Set rs = db.OpenRecordset("お買い物日記", dbOpenDynaset) 'FindFirst を使う場合は「dbOpenDynaset」を書き忘れるとエラーになります。 'クロスでセルを指定するために、目的の行(レコード)へ移動します。 '「FindFirst」が使えますが、これは、「条件に合う最初の行(=レコード)に移動させる」命令です。 rs.FindFirst "レシートID=2" ' ※補足 ' 「FindFirst」などの行移動の命令を書かない場合は必ず1行目の値が取得されます。 ' 逆に言うと、取り出した表の1行目の値たちしか絶対に扱わないと分かっているときは、 ' 「FindFirst」などの行移動の命令は書く必要が無いということです。 'クロスでセルを指定するために、列(フィールド)を指定します。 Debug.Print rs("品名") End Sub ' ' |
※後者の「test02()」のほうで 行を指定する条件式については、 = のほかに、Or や And 、Like、なども使えます。(詳しくは外部サイトですが→こちら)
※また、「 rs("品名") 」と書いてもよいのですが、
「 rs.Fields("品名") 」とか、
「 rs.Fields(2)」と書いても良いです。(※末尾に「.Value」が省略されています。)
「 rs.Fields(2) 」は、「取り出したレコードセット(取り出した表)の左から3番目の列」という意味です。「ゼロ」から始まるので「Fields(0)」は1列目・・・ということになります。なので、「Fields(2)」は左から3番目の列・・・ということになります。
左から3列目が「品名」の列なので、この例では Fields("品名") でも Fields(2) でも同じです。
いずれにしても、Excelよりは少し面倒くさいです(^^)
・テーブル、クエリ、フォームやレポートが開いている場合のみの、アクティブな画面のフォーカスのあるセルまたはテキストボックス等の値の参照
「screen」を使う場合もご紹介しますが、その場合は、閉じているフォームやには使えません。
また、「Forms(××)・・・」で始まる場合も、例えばテキストボックス(又はセル)の値の参照をしたい場合は、フォームが閉じているときやデザインモードの場合は参照できません。(ただ、セルの値ではなくてテキストボックスなどのプロパティ設定の内容なら、参照できる場合が多いです。)
なお、レポートの場合は、逆にデザインモードでしか、「screen」も「Forms(××)・・・」で始まる参照も使えません。
※記述忘れ。すみません。
フォームのコントロールの何らかのプロパティの値を参照する場合、プロパティによってはデザインビューだとエラーになることがあります。例えばテキストボックスの「Value」プロパティはそうで、フォームビューのときしか参照できません。デザインビューではエラーになります。コンボボックスのcolumnプロパティも同様にデザインビューの時に参照しようとすると「デザインビューではダメ」みたいなエラーになります。Nameプロパティはどのどちらのビューでもダイジョブですが。
プロパティによっては、デザインビューでは使えない場合があることを覚えておいてください。
レポートの場合は逆に、デザインビューしか使えません。
【以下、フォーム上の、「現在フォーカスの在るテキストボックスやセル」に表示された「値」を参照する例】
(「Screen」という命令語を使用する場合の例です。Screenを使うと、フォーム名やテキストボックス名が分からなくても、現在フォーカスの在るテキストボックスやセルなどの値、プロパティ設定値の一部を参照・取得することができます。実際のプログラムの中では「どうしても」という場面以外は使わないほうが良いと思いますが、メンテの時など、便利な場面もあるので覚えて損は無いと思います。特に、オブジェクト名やコントロール名の取得のときなどに便利です。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
' ' 【3つ共通・サブフォームも共通(※以降すべて、「.Value」は省略できます。)】 screen.ActiveControl.Value 【テーブルやクエリの場合】 screen.ActiveControl.Value でもいいし、 screen.ActiveDatasheet.ActiveControl.Value でもいいです。 【メインフォームの場合】 screen.ActiveControl.Value でもいいし、 screen.ActiveForm.ActiveControl.Value でも Forms("フォーム名").ActiveControl.Value でもいいです。 1番目に開いたフォームなら Forms(0).ActiveControl.Value でもOKです。 【サブフォームの場合】 screen.ActiveControl.Value でもいいし、 screen.ActiveForm.ActiveControl.Form.ActiveControl.Value でも Forms("フォーム名")("埋め込みオブジェクト名").Form.ActiveControl.Value でもいいです。 1番目に開いたフォームなら Forms(0)("埋め込みオブジェクト名").Form.ActiveControl.Value でもOKです。 ' ' |
・フォームのコンボボックスのドロップダウンリストの特定の1セル分を参照する(開いているフォームのみ。閉じたフォームには使えません。また、デザインビューでも使えません。レポートは無関係です。)
コンボボックス(ドロップダウンリストの付いたテキストボックス)のドロップダウンリストを開いたときに、2列×10行以上あった場合、2列目の4行目(下図だと「千鳥格子」を参照する例です)
一番メジャーなのは以下のような形です。
「forms("フォーム名")("コンボボックス名").Column(列番号, 行番号)」
(列番号はゼロから始まります。行番号も同じです。例えばゼロが1列目・1行目、1が2列目・2行目です。)
そのほかにもありますので、以下に実例をご紹介しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
' ' 【フォーム名:「商品情報入力」、コンボボックス名:「柄リスト」の場合】 forms("商品情報入力")("柄リスト").Column(1, 3) あるいはイベントプロシージャなら、 Me("柄リスト").Column(1, 3) 【フォーム名は不明だけど、でも、一番最初に開いたフォームの場合】 forms(0)("柄リスト").Column(1, 3) など。 【フォーム名:「不明」、コンボ名:「不明」、でもコンボにフォーカスがある場合】 Screen.ActiveForm.ActiveControl.Column(1, 3) あるいは screen.ActiveControl.Column(1, 3) ※後者はメインフォームにもサブフォームにも全く同じ書き方で使えます。 ' ' |
・Excelで言う「セル」に相当する1マスの値の書き換え
・Excelで言う「A1:C10」に相当する「セル範囲」と同等の参照(値の取得のみ。テーブル・クエリ両方とも。開いている・閉じている両方とも。フォームやレポートは無関係です。)
これも面倒なのですが、Excelのように簡単便利にドラッグでは選択(参照)できないし、VBAでももちろんドラッグはできないので、SQL文で仮想表(仮想表)として取り出します。
ちょうど、Excelの「フィルタ」「フィルタオプション」でのデータの取り出しと同じようなことをします。
面倒と言えば面倒なんですけど、ただ、Accessの場合はExcelのように「特定の隣接するセル範囲の値を操作・加工する」といった場面は少なく、どちらかというと「1列のすべての値」とか「特定期間や各種カテゴリ別に、言わば飛び飛びのセル」を拾い出してきて操作・加工することのほうが多いので、Excelのような「隣接するセルをドラッグで選択する」といったような操作はあまり必要ありません。
Accessに慣れると、むしろどなたも、SQLで仮想表として抽出するほうが便利に感じるようになれると思います。(もちろん、Excelの「A1:C10」という便利な参照方法には敵いませんが(^^))
SQLで仮想表としてセル範囲と同等の参照をする際には、例えばですが、「期間、累計売上の範囲、各種カテゴリ、チェックボックスのON/OFF」等々を条件指定して、操作・加工したいデータ範囲を取り出します。
繰り返しになりますが、Excelの「フィルタ」「フィルタオプション」でのデータの取り出しと同じようなことをします。
############################################################
############################################################
############################################################
「Excelが ”発売されて” 20年以上も経っているのに」、
「ExcelVBAを教える教室やサイトが発売当時の100倍以上も激増しているのに」、
なぜ、いまだに・・・
「ExcelVBAの初心者が自力でエラーが解決できない」、とか、
「いつまでたっても初級の、しかも「 ” 下 ” か ” 中 ” にもいかないレベルのまま」で、「中級」なんて「難しすぎて」「ぜんぜん上がれない」とか
「Q&Aサイトで質問しても、回答者の言っている意味が理解できない」とか、
「有料で習っても全然回収できない」とか、
・・・そういうことが起こっているのでしょうか?
本来なら(もう20年も経っているわけなのですから)、ExcelVBAの初心者教室は、
「変数、オブジェクト式、オブジェクト変数、SQLやそれを使ってのリレーション、ピボット、なんて、そんなのWebでタダで独学できてて、初級教室で習う前から知っててあたりまえ」で、
「シュミレーションやガントチャートやグラフをVBAでバンバン動かして、ちゃちなBIシステムならそんなものいらない」
「こういう仕事やマーケティング、PDCA、仮説と検証、問題点の数値化、の内容の時はこういう機能の使い方で、もしSQLやグラフやピボットをVBAで自動的に動かす使うならこう」
・・・というようなことが「 ”当たり前に” 教えられている状況」になってないといけません。
また、
『MicrosoftQueryとQueryTableオブジェクトの専門書が何冊も刊行されている』
『MicrosoftQuery(QueryTableオブジェクト)+ピボットの合わせ技の本が何冊も刊行されている』
『ピボットとGetPivot関数をExcelVBAで自動的に動かすための本が何冊も刊行されている。』
『SQLをExcelVBAで扱うための本が何冊も刊行されている。』
『SQLをADO・DAO・ExcelVBAで扱うための本が何冊も刊行されている。』
『ADO・DAOをExcelVBAで扱うための本が何冊も刊行されている。』
『Wordへの差し込み印刷・Wordのフィールドとの連携の本が何冊も刊行されている』
『クラスモジュールの使い方、自作オブジェクトの作り方とビジネスへの応用といったテーマの本が何冊も刊行されている。』
『こういう仕事やマーケティング、PDCA、仮説と検証、問題点の数値化、の内容の時はこういう機能の使い方で、もしSQLやグラフやピボットをVBAで自動的に動かす使うならこう、といった、そういう本が何冊も刊行されている』
『グラフとマーケティングなどをからめた本が何冊も刊行されている』
『オートメーションやIE操作の本が何冊も刊行されている』
『VBAヘルプなんか、どんな初心者も ”読めてあたりまえ” 』
『VBAヘルプとオブジェクトブラウザ、デバッグの解説本が何冊も刊行されている』
『そしてそれらの本が売れてて全然減らない』
という状況になってないといけません。
Excelが発売されて「20年以上」もあったんですから。
しかし現実には、
そんな状況は今後も一切来る気配もなく、なぜいまだに、
『シートとセルを操作する本しか無い、と言っても過言ではない』とか、
『 ”Excelデータベース”、と題された本に、SQLという単語やSELECTという単語が微塵も出てこない。ニセのデータベース本が99.8%くらい。そういう単語が出てても、MySQLやSQLServerを扱う本しかない。Excelファイルに接続する事例が満載の専門書(たとえばこちらのような内容の真のExcelデータベースの本)など1冊もない。』とか、
「ExcelVBAの初心者が自力でエラーが解決できない」、とか、
「いつまでたっても初級の、しかも「 ” 下 ” か ” 中 ” にもいかないレベルのまま」で、「中級」なんて「難しすぎて」「ぜんぜん上がれない」とか
「Q&Aサイトで質問しても、回答者の言っている意味が理解できない」とか、
「有料で習っても全然回収できない」
「変数がわかりません」
「オブジェクトブラウザがわかりません」
「ヘルプが読めません」とか、
そんな状況のままなのでしょうか?
体系的にならない原因のひとつは、多くの場合で、オブジェクトモデルの階層構造のことを「最初に」教えないからです。(下図)
たとえば、初心者のみなさんや、初心者レベルのまま・今少し挫折中のみなさんは、以降に書いたようなこと(オブジェクト式の階層構造を省略しない書き方など)、すべて把握していますか?(僕は一応ExcelVBAの初心者ですが、がんばってヘルプ読んだり・本・Web記事を読んだりして、自分なりに、以下のようにまとめてみました。みなさんも是非・少しずつTipsを集めて、ご自分なりに・ご自分がわかりやすいように、まとめてみてください。)
Application.Workbooks("Book1").Worksheets("Sheet2").Range("A1").Value
(=Application.Workbooks.Item("Book1").Worksheets.Item("Sheet2").Range("A1").Value
=Application.Workbooks.Item("Book1").Sheets.Item("Sheet2").Range("A1").Value
=Application.Workbooks("Book1").Sheets("Sheet2").Range("A1").Value)
(まだ「1回目の保存」を完了していない、「Book1」というブックのSheet2のA1セルの値)
※「1回目の保存」の前のExcelファイルには拡張子が付きません。ウィンドウのタイトルバーで、「1回目の保存」の前とあとの表示文言がどう変化するか、確認してみてください。
オブジェクトの階層構造をほぼ省略していないので、本来なら良い書き方になるはずが、でも保存前のときの書き方なので、ほとんど使えない書き方です。
僕もちょっとしたテストや調べものしたいときで、ファイル保存までをする必要も無い、というときくらいしか使いません。
ちなみにですが、「階層構造をほぼ省略していない」と書いてしまいましたが、「Application.」の前に本当は「Excel.」というものが省略されています。
(「Excel.」よりも上の階層は存在しません。「Excel.」が一番上です。)
「Excel.」は「ライブラリ」と呼ばれるもので、オブジェクトブラウザの一番上のドロップダウンリストに出てくるものです。
このドロップダウンリストに出てくるものは、(VBAProject以外は)基本、「参照設定」というものがなされています。「Excel」のほかに「VBA」「Office」などがありますが、それらは全部、それぞれ「Excel」と独立したオブジェクトの階層構造を所持しています。そして、「Excel.」と同じく、各オブジェクト構造の中の「一番上の階層」です。
(なお、「Excel」や「Office」「VBA」などのそれぞれの実体は、EXEやDLLなどの ”ファイル” です。オブジェクトブラウザでそれらをドロップダウンで選べば、下のほうの説明ペインに出てきます。それぞれのファイルの中に、それぞれの階層構造が組み込まれている・・・みたいなイメージです。それが「ライブラリ」です。下図も参照してみてください。)
※オブジェクト変数にも一緒に代入できるっぽので、「ライブラリ」とは言うものの、「オブジェクトの一種」??のような気もしないでもないです。
「Excel.」は複数のファイルを同時に扱うときによく使います。
が、ただ、そのときは(おすすめはしませんが)省略してもエラーにはなりません。でも「Excel.」が省略されている、ということは必ず覚えておく必要があります。「参照設定」がなされている場合・かつ・「他のファイル」がWordのファイルの場合、「Excel.」と同じように「Word.」を使いますので。
僕は複数のファイルを同時に扱う場合は、「Word.」や「Excel.」はプログラムの冒頭部分だけですが、「Set ××× = ・・・」の、オブジェクト変数の代入のところで必ず書くようにしています。 そのほうが可読性がよくなって、メンテもラクなので・・・。(ExcelVBA初心者ですから特に。)
ただし、その際に「New」キーワードを使うときは、変数宣言ではなく、これまた、「Set ××× = ・・・」の、必ず、オブジェクト変数の代入のところで「だけ」書くようにしています。そのように書くほうがこちらのような不具合も起きにくいそうなので・・・
※「Worksheets」と「Sheets」について
Sheetsコレクションは、ワークシート(単一のWorksheetオブジェクト)やグラフシート(単一のChartオブジェクト)など、複数の種類のシートを一括管理するコレクションです。
なので、ワークシート(単一のWorksheetオブジェクト)は、Worksheetsコレクションと、Sheetsコレクションの2つ(両方)のコレクションに含まれて管理されている・・・という格好になります。
グラフシート(単一のChartオブジェクト)も同様です。
そのため、
「・・・・.Worksheets("Sheet2").・・・・」と書いても、
「・・・・.Sheets("Sheet2").・・・・」と書いても、
「Sheet2」を指定したことになります。
「どんなシーンでどちらを使った方がいいのか?」は、僕もExcelVBA初心者なのでわかりませんから、先生や先輩の方々に聞いてみてください。
※「Item」について
Itemプロパティ(あるいはメソッド)は、「コレクション(=コレクションオブジェクト)」なら、「基本的に、どのコレクションも保持・保有・内包」しているプロパティ(あるいはメソッド)です。
逆に言ったら、単一オブジェクトはItemプロパティ(あるいはメソッド)を保持していませんので、そういうものは「単一オブジェクト」、となります。
なお、「Item」には、「Itemプロパティだけでなく、「Itemメソッド」もあります(例えば、「PivotTables.Item メソッド」など。)
深いところは意味が違うようですが、似た動作をします。
つまり、コレクションから単一のオブジェクトを返してくれます。
そのため、オブジェクトブラウザにて、「Item」で、完全一致で検索すると、出てくるオブジェクト(=クラス)は、すべて、コレクションです。
コレクションの一覧を見たかったら、オブジェクトブラウザで「Item」で検索すればOK、ということになります。「Itemプロパティ」や「Itemメソッド」を保持したコレクションオブジェクトたちが、ずら~っと並びます。
「WorkSheets("Sheet2")」と「WorkSheets.Item("Sheet2")」は、最終的には「Sheet2」を指定・選択しているのですが、少し意味が違うっぽいです。なので「Item」を書かないことは「Workbooksを省略するとActiveWorkbookになる」という省略のされかたとそこも意味合いが違う、「単なる省略ではなく」、「別の書き方」・「意味の異なる書き方」、「という意味合いが色濃い」・・・ということを覚えておいたほうがいいかもしれません。
また、ローカルウィンドウでコレクションの中身を調べるときに、その構成要素として・この「Item」がよく出てきて、それぞれの単一のオブジェクトの状況なども表示されますので、このItemのことは、書かないことは多いですけど、「できるだけ短い期間でのVBAの上達」のためには、「絶対に知っておかなければならいもののひとつ」であることを忘れないようにしてください。
=======================
なお、Worksheet(ワークシート)のコレクションは「WorkSheets」、WorkBook(ブック)のコレクションは「Workbooks」と、大抵コレクションは「s」のついた複数形がほとんどです。稀に、単純に「s」がつかず、「・・is」が「es」になったり「・・・y」が「ies」になっているものもあります。
ちなみにですが、「Range」オブジェクトは「Item」プロパティを持っていますので、「複数のセルを保有するコレクションオブジェクト」と言ってもいいのかもしれません。(厳密には違うかもですが、そう考えるほうが色んな場面・Rangeの動きなどを見ても納得できます。)
その証拠(?)に、Rangeオブジェクトに対しては「For Each」文が使えます。
「For Each」文は配列かコレクションオブジェクトに対してしか使えないので。
「Cells」はコレクションじゃないので私たち初心者にとっては紛らわしいのですが・・・。
「セル」のコレクションが「Range」で、
「Range」(セル範囲)のコレクションが「Ranges」(セル範囲たち)・・・という感じになっているのかもしれません。
あと、「Item」はプロパティもメソッドも、基本、その記述を省略できます。
(ただ、「単なる省略」という感じではないことは前述のとおりです。)
つまり、
「WorkSheets.Item("Sheet1")」と書いても、
「WorkSheets("Sheet1")」と書いても同じ、
ということです。
僕も省略して書きます。
ただし、省略するとエラーになるような場合もあるかもしれないので、エラーになったらエラーの原因をつぶすために、一時的にItemを書いたりすることもあるかもしれません。
(「Item」限らず、また、Word、Excel、Accessに限らず、VBAは「省略がもたらすエラー」は思ったよりも多いです。なのでエラーが出た際は、まず「省略した書き方をしてないか?」をヘルプで確認する必要があります。省略しない書き方に変えたら5分で解決できるエラーなのに、それを知らないために何日もWebを調べるなんていうバカなことをする羽目になりませんように・・・。)
最後に、Itemプロパティも、それ以外のプロパティもそうですが、引数を指定できるプロパティは、メソッドと同じように、「名前付き引数」としても指定できるようです。
※「名前付き引数」は「メソッドによく使う」と習っている方もいらっしゃるかもしれませんが、でも、もともとはプロパティやメソッドのためのものではなく「Sub」や「Function」といった「プロシージャ」のためのもののようです。それも「引数」を持つ「Sub」や「Function」といった「プロシージャ」です。
このことは2010のヘルプでも、「名前付き引数と省略可能な引数の概要」というページに書いてあります。
当然、自分が自作した「値やオブジェクトを返す関数」の場合でも、引数を設けていれば「名前付き引数」を使ってのCall(呼び出し)が可能です。
なので、なら、プロパティもメソッドも「もしかしたら関数のようなものなのかもしれない・・・?」という推測ができると思います。そして、実際にそのように解釈すると、合点がいく場面が増えると思います。ヘルプやオブジェクトブラウザも読みやすくなります。
Range("A1:C3").Item(1,1).Value
は
Range("A1:C3").Item(RowIndex:=1,ColumnIndex:=1).Value
とも書けます。
Activesheet.PivotTables.Item(1).name
は
Activesheet.PivotTables.Item(index:=1).name
とも書けます。
Application.Workbooks("Book1.xlsx").Worksheets("Sheet2").Range("A1").Value
(=Application.Workbooks.Item("Book1.xlsx").Worksheets.Item("Sheet2").Range("A1").Value
=Application.Workbooks.Item("Book1.xlsx").Sheets.Item("Sheet2").Range("A1").Value
=Application.Workbooks("Book1.xlsx").Sheets("Sheet2").Range("A1").Value
(1回目の保存を完了した「Book1.xlsx」というブックのSheet2のA1セルの値)
※「Item」については前項参照してください。
※「Worksheets」と「Sheets」について→前項と同様ですが、重要なのでここにも書いておきます。
Sheetsコレクションは、ワークシート(単一のWorksheetオブジェクト)やグラフシート(単一のChartオブジェクト)など、複数の種類のシートを一括管理するコレクションです。
なので、ワークシート(単一のWorksheetオブジェクト)は、Worksheetsコレクションと、Sheetsコレクションの2つ(両方)のコレクションに含まれて管理されている・・・という格好になります。
グラフシート(単一のChartオブジェクト)も同様です。
そのため、
「・・・・.Worksheets("Sheet2").・・・・」と書いても、
「・・・・.Sheets("Sheet2").・・・・」と書いても、
「Sheet2」を指定したことになります。
「どんなシーンでどちらを使った方がいいのか?」は、僕もExcelVBA初心者なのでわかりませんから、先生や先輩の方々に聞いてみてください。
前項と同様、「一番先頭」に、「Excel.」と書くのを省略してます。
長ったらしい書き方ですけど「オブジェクトの階層構造」をほぼ省略していないので、例えば、
・Excelファイル(=ブック)が1つだけ開かれている場合や、
・反面、ブックが複数開かれている場合、
・そのほか、操作したいブックやシートがアクティブじゃない場合、
・・・等々、いろんなシーン・ケースを考えた場合、どのシーン・ケースでも、最もエラーや挙動不審・誤作動の「出にくい」書き方です。(「出ない」ではなく「出にくい」です。基本、シートやブックの名前が変わってしまうとダメですし。変えてしまった場合はちゃんとエラーか挙動不審・誤作動になります。それをできるだけ回避するには、「ブックの保護」の機能で、シートのタブでの名前変更や順序入れ替えなどを禁止すればOKかもしれません。未確認です。すみません。)
この書き方は、長ったらしくて面倒な書き方ですけど、
でもこれこそが、Excelに限らず、「VBA」でのオブジェクト式やコードの書き方の「基礎」「原則」です。
つまり、「オブジェクトの階層構造を省略しない」という書き方が、Excelに限らず「VBAのオブジェクト操作における原則・本当の基礎・スタート地点」、なのです。
(そして、もし短く書きたかったら「オブジェクト変数」を使います。)
基本、VBAのオブジェクト操作は、「オブジェクトの階層構造ありき」なのです。
ヘルプもオブジェクトブラウザも、各種命令も、全部、その前提で、そのルールの上に成り立っています。
つまり、それを意識しないと、ヘルプもオブジェクトブラウザも扱えず、エラーの自力解決なんて夢のまた夢です。
ヘルプなどはその前提ですべて書かれているので、階層構造を理解していない人は絶対に意味がわかりません。(ついでに言うと、値やオブジェクトを返す自作関数のことを理解できていない人もヘルプとオブジェクトブラウザは絶対に理解できません。)
「たかが階層構造」、ではないのです。
「階層構造こそすべて」と言ってもいいくらい、階層構造は重要です。
オブジェクト(オブジェクト式)のオブジェクト変数への代入後にもついてまわります。
(なのにそう教えてくれる講師が少なすぎます。)
「オブジェクトの階層構造を省略しない書き方」の、その「意味・意義」を理解しようとせず、ここをテキトーに済ませてスルーする人は、いつまでたっても、どれだけセミナーでお金を払っても、ExcelVBAが上達しません。
他の書き方は、この書き方を「省略」したり、(他の単語を使って)少し変形させた書き方となっています。
(
しかし、そもそも、「省略」とは「意味がわかっている人」がやることが「省略」であって、「意味がわかってない人」がやるのは「単なる手抜き・いい迷惑」、「頼むから俺には近づくな」」、「頼むから会社のみんなの共有データには近づくな」です。
意味もわからず「省略」あるいは変形をすれば、「バグやエラーの温床」にもなります。
そして「エラーが多い」ことは、「挫折」の原因、「中級へ上がれない」原因にもなります。
(つまり、初心者が、「エラーが多くて挫折が多い」のは、全部、「テキトー」にしか教えられないからです。それが原因のすべてです。)
なのに「そんな風になってしまう方法」=後述する「 Range("A1").Value という書き方」ばかりを、「あえて」「最初から」教えて、「 ” 省略や変形のデメリット ” の但し書きもしない」方法が、蔓延しています。
そしてそれを何の疑いもなく、「そのほうが最初はいいから」という理由・決めつけだけで、あるいは、テキトーで都合のいい理由を口実にして、自分の「頭」で「生徒さんのこと」を考えようとせず、ただ右に倣えでマネするだけの、もちろん但し書きなんかするわけもなく、「思考停止した愚かで質の低いレッスン」がどんどん増えています。
20年もあれば、Webで検索した時に「オブジェクト式の書き方やその省略とエラーの関係」とか「Variant型の変数とエラーの関係」とか、「ヘルプの読み方」とか、そういうサイトやWebページがGoogleのトップページにヒットしないといけないのに、出てきたためしがありません。
「オブジェクト式の書き方とエラーの関係」「よくあるエラーの一覧・どこをチェックすべきか?何を学ばないと解決できないか?」の一覧や本なんて、20年もあれば、だれか作れただろうから、作っとけばいいのに・・・、と思ってしまいます。
もしかしてバカなのかしら?少なくともまとも教える気は無いんだろうなあー。
と、大変無礼とはわかってはいますが、でも、「習う側」としては正直な感想です。
初心者には、「最初は意味がわからなくてもいいので、でも、今は詳しくはやらないけど概要だけ言っておくから絶対忘れないで!と前置きしながら、重要度やナメないこと、難しくなくてもメッチャ簡単でもないこと、でもメッチャ簡単ではないからこそ私たちが導くから安心してとか、目標・どこまで理解しないといけないか?、真実」など、を与えるべきです。
「プログラマになるわけじゃないんだから」という理由で「変数なんか全部Variant型でいいじゃん(でもローカルウィンドウも何も教えない))」というようなテキトーな絆創膏プログラミングを教える、「教科書」を名乗るような書籍とかもありますが、そんな腐った本が出るようになってしまったからこそ、「最初からの詳しい説明」や但し書きは必要だと思います。
長ったらしい書き方で面倒だからこそ逆に、そこで『 オブジェクト変数やオブジェクトのこと・オブジェクト変数を使って短く書くこと 』等々をしっかりと教えればいいのに、それもしません。
オブジェクト変数への代入の場合、一般的な変数の場合の「生データ(ほぼリテラル値)」に相当するものは「オブジェクト式」だ、ということすら教えません。
そしてオブジェクト式をそのまま(変数に代入せずに生のまま)使う方法ばっかり教えます。
オブジェクト変数への代入の重要性も教えないもんだから、オブジェクトを返す自作関数なんて全く作れずに、そのため、ヘルプも読めずにオブジェクトブラウザも扱えません。「初級」の「下か中」の位置にずーっと居たままです。「初級の上」の位置にも上がれません。
エラーが出ないようにする方法なんて最初に言って欲しい、とあとから思わされます。
)
この書き方は、ある意味「絶対的な」書き方・・・という感じです。(それに対して、基本、あまり使わないほうが良い「ActiveSheet」や「ActiveCell」などを使った「相対的な感じの書き方」もあります。)
なお、「.Value」よりも前の「オブジェクト式」を短く書くには「オブジェクト変数」を使い、それに代入します。
(「With」を使うこともできますが、僕は、「With」にまだ慣れてなくて、コードが汚く見えて読みにくくなるため、滅多に使いません。)
(※「オブジェクト変数を使う」というのは一応「原則」です。例えばAccessなどではオブジェクト変数を使うことで原因不明のエラーになる、などのトラブルを僕自身・経験したことがありますが、そのような場合はもちろん原因が判明するまではオブジェクト変数を使いません。Withも、使って全然OKです。ただ、そいうとき以外は原則は守ったほうがエラーや誤作動は間違いなく減ります。)
なお、シートやセルの操作ではなく、ユーザーフォームやその部品(「コントロール」と呼びます)の場合は、Excelとは独立したオブジェクトの階層構造となりますが、こちらでもおおむね同じことが言えると思います。
もちろん、ユーザーフォームにはセルはありませんが、セルを『ユーザーフォームやその部品(=コントロール)』と見立てれば、やはりここでも、階層構造を省略しない書き方が基本で、短く書きたいなら省略やWithを使うよりもオブジェクト変数を使うことが原則です。
ADOやDAOと呼ばれる便利な機能たちも、Excelと独立したオブジェクトの階層構造を持っていますが、考え方・原則は同じです。
ちなみにですが、「Value」プロパティも(例えば2010の場合は)本当は「RangeValueDataType」という「引数」を持っていて、「Value」だけだと「省略した書き方」です(Range.Valueプロパティの2010のヘルプページに書いてあります)。省略によりどんな不都合が起こるか僕にはわかりません。
(※引数がある・ないは、バージョンによっても違うようです。バージョン2000の「Value」プロパティには引数は無いみたいです。ヘルプにも書いてありませんでしたし、ローカルウィンドウにもValueとValue2がちゃんと表示されます。)
なのでこの「書き方」は、「もっともエラーや挙動不審・誤作動が」、「出ない」ではなくて、「出にくいもののひとつ」、とお伝えさせて頂きました。
更にちなみにでですが、「引数」を持っているプロパティは、その値は「ローカルウィンドウ」には表示(リストアップ)されないそうです。
なので、「Value」もリストアップされません。
「value2」は引数を持ってないので表示されます。
(※ここでは2010を想定しています。前述のとおり、バージョン2000では引数を持たないらしく、「Value」もリストアップされます。2003や2007もどのようになるか、テストしてませんのでご自分でもチェックしてみてください。)
Workbooks("Book1.xlsx").Worksheets("Sheet2").Range("A1").Value
(=Workbooks.Item("Book1.xlsx").Worksheets.Item("Sheet2").Range("A1").Value
=Workbooks.Item("Book1.xlsx").Sheets.Item("Sheet2").Range("A1").Value
=Workbooks("Book1.xlsx").Sheets("Sheet2").Range("A1").Value)
(1回目の保存を完了した「Book1.xlsx」というブックのSheet2のA1セルの値)
前項の書き方の「Application.」だけを省略した書き方です。
こちらも長ったらしい書き方ですけど、かなりエラーの出にくい書き方です。
「Application.」だけは省略しても、「どの想定シーン・ケースでもまずエラーにならない」ので。
ExcelファイルやWordファイルを同時に複数扱うようなときは「Application.」自体や「Excel.Application.」「Word.Application.」自体をオブジェクト変数に代入してしまうことが多いですが、その場合は、その『 ××××.Application が代入されたオブジェクト変数 』を省略すると、ちゃんとエラーになることが多いですから逆に省略できません。
以降同上。
僕は、この書き方を一番使います。
特に本番では。
なお、「Application」を使うのは、特にExcel2010以前で、「もうひとつ、別のExcelウィンドウ=Excelのガワ」を表示して、複数のExcelファイルを操作したい時、に使うことがあります。(子ウィンドウに・複数、Excelファイルが表示されてしまうのが都合が悪い時、など。)
また、「Excel.Application」を使うのは、「 ” COMオートメーション ” と呼ばれるファイル操作方法」によって、ExcelからVBAから、WordやAccess等々のファイル(WordやAccessのVBA)も操作をしたいときに使うことがあります。
それは、意味としては、「ExcelファイルやExcelVBAを、WordやAccessなどのそれらと区別するため」に使います。
Worksheets("Sheet2").Range("A1").Value
(=Sheets("Sheet2").Range("A1").Value
=Sheets.Item("Sheet2").Range("A1").Value
=WorkSheets.Item("Sheet2").Range("A1").Value
=ActiveWorkBook.Worksheets("Sheet2").Range("A1").Value
=ActiveWorkBook.Worksheets.Item("sheet2").Range("A1").Value
=ActiveWorkBook.Sheets.Item("Sheet2").Range("A1").Value
=ActiveWorkBook.Sheets("Sheet2").Range("A1").Value)
(アクティブなブックのSheet2のA1セルの値。)
この書き方は、ちょいちょいエラーや挙動不審・誤作動が出ます。
例えばブックが2つ以上同時に開いていた場合は、目的のブックのA1セルの値じゃないこともあります。例えば「Book1」のほかに「Book2」も開いていた場合、もし「Book2」のほうがアクティブだと、間違ってそちらのブックのSheet2のA1セルの値を取得してしまいます。
なので(転記の処理を自動化をしたい等々で)、複数のブックを開いていたときなどに、むやみにこの書き方を使うと、ちょいちょいエラーや挙動不審・誤作動が出ます。ご注意ください。
1つのファイルだけを処理する場合はもちろんこれでもいいですが、大抵はあとになって 作り変えや作り足しの要望が出て、「2つめ以降の他のExcelファイルも同時に開く処理を追加する」ということも多いので、そのような時をあらかじめ想定して、できるだけ「Workbooks(××××).」は省略しないほうが無難です。
短く書きたかったら、オブジェクト変数を使います。
なお、この書き方は、後述する「Workbooks(1).Worksheets("Sheet2").Range("A1").Value」
(=Workbooks.Item(1).Worksheets.Item("sheet2").Range("A1").Value)
というような「Workbooks(1).・・・」という書き方と違って、Personal.xlsb(or xls)つまり、「個人用マクロブック」が自動生成されてしまったとしても、「ActiveWorkBook.Worksheets("Sheet2").」と書いたり、「Worksheets("Sheet2").」とBookの部分を省略して書いても、エラーにはならないことはならないです。
ブックが1つだけしか開いていない場合、「ActiveWorkBookの使用やBookの指定の省略」をしたときは、「今開いているブックを指定した」と自動的にみなされるからです。
つまり、「個人用マクロブック=Personal.xlsb(or xls)」の存在は基本、無視されるようです。
しかし、それはあくまでも、ブックが1つしか開いていない場合だけです。
2つ以上のブックを同時に開いたときは、エラーになりやすいので僕はあまり使いません。
なお、複数のブックのうち、どれが「1回目の保存が完了しているか」はこの場合は無関係です。
Range("A1").Value
(=ActiveWorkBook.ActiveSheet.Range("A1").Value)
(アクティブなブックのアクティブなシートの、A1セルの値。)
この書き方は、ここまで書いてきた中ではもっともエラーや挙動不審・誤作動が出やすいです。
前項の書き方と同様、ブックが2つ以上同時に開いていた場合は目的のブックのA1セルの値じゃないことも多いです。例えば「Book1のSheet2のA1セルの値を取得したい」という場合、基本、「目的のブック」の「Sheet2」までも、が、アクティブになってないと正しい値が取得できません。つまり、もし目的のブックがアクティブだったとしても、「Sheet2」ではなくて「Sheet1のほうがアクティブだった場合」は、間違って「Sheet1」のA1セルの値を取得してしまい「Sheet2」のA1セルの値は取得できません。
その際、もし「Sheet1」のA1セルの値が空白だったら、そのせいで何らかのプログラムがエラーになる場合もあります。
また、標準モジュールやThisWorkbookモジュール、イミディエイトウィンドウに「Range("A1").Value」と書いた場合は・・・、
『 現在アクティブなブックのアクティブなシートの「A1」セルの値 』
・・・が取得できますが、そうではなくて、例えば シートモジュールの「Sheet1」のモジュールのプロシージャに「Range("A1").Value」と書いた場合は、そうはなりません。
たとえ「Sheet2」や「グラフシート」がアクティブになっていたとしても、Sheet1のA1セルの値が取得されてしまいます。
「Sheet2.Activate」という命令を書いて、Sheet2を明示的・強制的・明確にアクティブにしたとしても、Sheet1のA1セルの値しか取得できません。「Range("A1").Value」ではどうあがいても「Sheet2」のA1セルの値は取得できないのです。
Sheet1のモジュールに書いた「Range("A1").Value」では、
・現在アクティブなブックの、現在アクティブなシートの、A1セルにはならず、
・どのシートがアクティブになっていようが・いまいが、
いかなる時もそのシートが存在するブックの、絶対にSheet1のA1のみ しか、
取得できない。
のです。
つまり、「相対的、とか、流動的、なプログラムは書けない・・・・」、ということになります。
そのような挙動なので、もしかしたらですが、ThisWorkbookモジュールに書いたときやフォームモジュールに書いたときも、(僕が知らないだけで)何かドツボにハマるようなことが起こってくるかもしれません。
結局のところ、「Range("A1").Value」という書き方は、いろんなシーン・ケースを想定した場合、ここまで書いてきた中ではもっともエラーや挙動不審・誤作動が出やすい書き方です。
(でも一番、市販書籍・Webサイトその他で紹介される書き方です。一番エラーが出やすい書き方ばっかり教えて「あくまでサンプルだから、自分のプログラムでは本番はもちろんテストやプロトタイプでも階層の省略はしないでね」といった但し書きもしないなんて意味がわかりません。)
なぜそうなるかは、実際にたくさんプログラムを書いたり、テストを繰り返すとわかります(失敗してほしくないので、ここでは使用をおススメしていませんが)。
テスト方法は先生や先輩に聞けば教えてくれます。
僕の場合はこの書き方は、
「テスト用」
「値や構造を調べたい時だけ」
「Webに載せるサンプル作成」
「自分しか使わない他人は絶対に使わないすぐ捨てるプログラム」のときに使うことが多い書き方です。
「お仕事としての本番」では使うことは基本、あまりありません。
特に「他人も使うプログラム」の時は使用頻度が落ちます。ほとんど使わないかも・・・。
なお、この書き方の場合も、複数のブックのうち「どれが1回目の保存が完了しているか」は無関係です。
Application.Workbooks(1).Worksheets(2).Range("A1").Value
=Workbooks(1).Worksheets(2).Range("A1").Value
=Workbooks.Item(1).Worksheets.Item(2).Range("A1").Value
(1つめのブックの左から2つめのシートのA1セルの値)
この書き方は、ブックやシートを、「Nameプロパティの値(俗名)」ではなく、「インデックス番号」で指定していくやりかたです。
基本、あまり使いません。
(コレクションを使っての「全オブジェクトへの一括ループ処理」をしたいときなどは、このような「インデックス番号」で指定する方法を使うことがありますが・・・。ただ、この「まんま」ではなく、多少変えますし、頻度もそう多くはありません。)
基本、この方法は、どのブックやシートが(1)になったり、(2)になったりするかわからないので、エラーや誤作動が多いから、です。(特に作り変えや作り足しをしたとき)
オブジェクトの階層構造をほぼ省略していないので、本来なら良い書き方になるはずですが、そのようなエラー・不都合が多いので、実務ではほとんど使えない書き方です。
何らかのテストをするときや「どうしてもやむを得ない時」くらいしか使いません。
例えば、「新規作成」として開いたブックは、もし「個人用マクロブック=Personal.xlsb(or xls)」が生成されていなければ「Workbooks(1).」という書き方で特定できます。
が、しかし、個人用マクロブックが、「マクロの記録」機能を使って自動生成されたり、手動で設置された瞬間から、次回以降は、「新規作成」したブックは「Workbooks(1).」ではなく「Workbooks(2).」になってしまいます。
次回以降は「新規作成したExcelファイルは、” 必ずWorkbooks(2)になる ” 」のです。
(もしプラスで、「参照設定したExcelファイル」があると、さらにWorkbooks(3)とか(4)になってしまうかもしれません。)
もちろん、「新規ファイル」だけなく、既存のファイルも同じで、個人用マクロブックが無ければ、一番最初に開いたブックは「Workbooks(1)」で、そのままの状態で追加で2番目に開いたBookは「Workbooks(2)」となります。
個人用マクロブックがあれば、一番最初に開いたブックは「Workbooks(2)」で、そのままの状態で追加で2番目に開いたBookは「Workbooks(3)」となります。
ただ、既存のファイルでも逆の順序で開けば、「Workbooks(2)」や「Workbooks(3)」はその内容が入れ替わってもしまいます。(だからブックの指定自体が、仕組みを良くわかっていなければメチャクチャになってしまいます。)
シートについても、例えば「Sheet2」をドラッグで一番左に入れ替えてしまうと、「Worksheets(2)」ではなくなります。
「Worksheets(1)」と書き換えないといけなくなってしまいます。
ドラッグで入れ替えた瞬間から「Worksheets(2)」は他のシートになってしまいます。
そのことを知らないとエラーだらけになります。
だから、使いません。
どうしても使いたい場合は、まず個人用マクロブックを自動生成させるか自分で作っておいて、ブックについては最初のブックを「Workbooks(2)」からスタートし、その後、シートについてはシートを動かしたりリネームしたりができないように「ブックの保護」をかけるなどをします。(まだほかにも対策は必要かもしれません。)
あるいは、「ブックの保護をかけたくない」という場合は、「1つだけのファイルしか絶対に開かない」、という「ケース限定」での処置であれば、その場合に限っては、例えば代わりに次項の「VBAProject.Sheet2.Range("A1").Value」や「Sheet2.Range("A1").Value」を使ってもOKです。
(※もちろん、一番長い書き方をしてブック保護するかタブを非表示にするほうがより安全です。)
あ、今思い出しましたけど、そのような利用シーン以外の利用シーンもあるにはありますね・・・。
それは例えば、「データ管理の世界標準の基礎(複式簿記と同じくらい有名)」を知らない人・使えない人が、「データを大量のフォルダごと(取引先ごととか)に分割して保管してしまっているような場合や、同じフォーマットの請求書のシート(でもシート名はぐっちゃぐちゃとか)を作ってしまっている場合とか、そういった場合に、それらのデータを一気にループ処理でまとめあげたりするときにはよく使ったりするかもしれません。
ただ、ExcelVBA講師たちは、そういう「無駄なデータ管理の手法にまったく無頓着」な人も多いので、「取引先データの場合は、そもそもフォルダごとに取引先ごとに分ける行為 自体が、原則としては ” 無駄・かつ・超非効率データ管理手法 ” です。 だからできるだけやめましょうね?」と教えてもらえないのです。
書籍を出している人も出していない人もそういうことを教えない講師たちばっかりで、その責任は重いです。
正直、彼らが、「日本のデータ管理」を軽く10年は遅らせたと思います。
だから「僕ら習う側」が知らなくても仕方なく、基本、ExcelVBA講師たちの怠慢です。
だから無駄なVBAや無駄な関数が増える。
「数十もの取引先のフォルダのや売り上げのフォルダのデータをまとめるプログラム」だなんて、「データ管理の基礎(SQLやMicrosoftQueryやピボットなど)」からしっかり教えていれば、もともとフォルダごとに分ける必要なんてないわけですから、もともと書く必要のない無駄なプログラムなのです。(ExcelVBA講師たちがテキトーなことしか言ってないので、僕もテキトーなことを言っています。)
僕は「データ管理の世界標準の基礎(複式簿記と同じくらい有名)」を、多少ですけども守っているので、そいういう無駄なデータ管理の方法は モトからしなくなりましたからそういう無駄なVBAは使わずにいられるのでその意味ではまだラクです。
なお、前述しましたが、「ActiveWorkbookの使用やBookの指定の省略」をした場合は、「個人用マクロブック=Personal.xlsb(or xls)」の存在は無視されるようですので、前述したような個人用マクロブックがらみのエラーは出ません。
といって、「ActiveWorkbookの使用やBookの指定の省略」自体も、「2つ以上のブックを同時に開いたりして行う処理(例えば転記処理)」ではエラーが出やすいのでおススメはしません。
あと、この書き方の場合も、複数のブックのうち「どれが1回目の保存が完了しているか」は無関係です。
※ちなみにですが、データをお取引先ごとに分けたり・売り上げを月ごとにシートごとにわけたりすること自体は、大変残念ながら、『ダメなデータ管理、データ管理の基礎を無視したやり方』なのですが、そういったことさえ、ExcelVBA講師の人たちは教えてくれません。(VBAがあるからとタカをくくって、「無駄なことなんだ」と教えないのです。教えれば「本来書く必要のないExcelVBA」自体の無駄を減らせるのに。)
さらに悪いことに、一部の「教科書」を名乗るVBA関連の愚かな市販書籍には、そんな無駄を自慢げに「すごいだろ」とばかりに教えている本もありますのでご注意ください。
僕は、データ管理の基礎を守らないとあとで面倒くさいことになるから、もとから取引先ごとのフォルダなんて作らないし、データを月ごとにシートに分けたりとかそういう無駄なこともしていないので、なのでそもそも、そういう無駄な処理(たくさんのデータをWorkbooks(1)とかWorkSheets(2)とかを書いてまとめる・転記するような処理)をすることはありません。
みなさんも、取引先のフォルダをわける、とか、売上を月ごとにシートに分ける、というようなことは「本来はデータ管理の基礎を無視した無駄な処置」と、どうか・ぜひ、お知りになっていただき、「リレーショナルデータベース」の基礎を、Excelにて、MicrosoftQueryやこちらのサイト、などで学んでみてください。
業種や職種にもよりますが、無駄なVBAや関数が激減することも少なくないです。
そして、ほとんどのダメ講師たちに「もっとExcelでやれるSQLの話とかリレーショナルデータベースの基礎を教えろ!そしてそれをVBA操作する方法を教えろ!」と言ってやってください。
ActiveWorkBook.Worksheets(2).Range("A1").Value
(=ActiveWorkBook.Worksheets.Item(2).Range("A1").Value)
ActiveWorkBook.ActiveSheet.Range("A1").Value
(アクティブなブックやシートのA1セルの値)
これまでの流れからもお分かりになると思いますし、少し前にも書きましたので繰り返しになってしまいますが再度、書かせていただきます。
この書き方も、ブック名やシートを、「Nameプロパティの値(俗名)」で決め打ちしてないので、作り変えや作り足ししたときにエラーになりやすいので、「やむを得ない場合、か、それじゃないとダメという特殊な時」以外は使いません。
「今のこの瞬間での ” ActiveWorkBookやActivesheet ” が何なのか?どのブックやシートなのか?」を判断・分岐させて、それによって色々と動きを変えていくようなプログラムを動かしたい場合とかは使います。
(逆に、そのような判断で、動きを止めたいとか。)
なお、この書き方の場合も、複数のブックのうち「どれが1回目の保存が完了しているか」は無関係です。
VBAProject.Sheet2.Range("A1").Value
(=Sheet2.Range("A1").Value)
(CodeNameプロパティの値が「 ” Sheet2 ” 」になっているシートの、A1セルの値。)
これも(「相対的」ではなく)「絶対的な感じ」の、書き方です。
また、エラーや不都合がそこそこは少ない書き方です。
ただし、「複数のブックを同時に開いて転記処理をするようなケース」では「使えない」という感じです。(だから「そこそこ少ない」とお伝えしました。エラーが出ないのは1つのブックしか開いてない時だけです。後述します。)
なので、後述しますが、「あくまでも1つのブックしか開かない」かつ、「どうしてもシートをドラッグで動かしたりリネームしたりしたい場合」以外は、基本、使いません。
普通、シートは、「WorkSheets("Sheet2")」「Worksheets.Item("sheet2")」みたいな感じで、シートの「Nameプロパティの値」で特定することが多いのですが、ここでの書き方のように「CodeNameプロパティの値」を「まんま」で使うことでもシートやブックなどを特定できます。(「Worksheet.Sheet2」みたいに書くのではなく)
たとえばシートの場合は、「Sheet2」とだけ「まんま」で書くことで、「WorkSheets("Sheet2")」を意味します。
このとき、「CodeNameプロパティ」は、「コード名」と呼んだりもします。
「CodeNameプロパティ(=コード名)」とは、VBE(=VBAプログラムを書く画面=VisualBasicEditor)の、プロパティウィンドウの「(オブジェクト名)」の欄にて付ける・書き換えることができる「名前」です。
シートのタブで付ける名前が芸名だとすると、コード名は本名、みたいな感じです。
例えば、「Sheet2.Range("A1").Value」と書いた場合は、Sheet2の「シートのタブ側で付けた名前」を「何に変えようとも」、1回書いた「Sheet2.Range("A1").Value」というプログラムの記述を、ずーっと書き換えずに、Sheet2のA1セルの値を取得できます。
また、「WorkSheets(2).Range("A1").Value」「Worksheets.Item("sheet2")..Range("A1").Value」のような書き方をした場合は、「左から2番目のシートのA1セルの値」という意味になりますが、「Sheet2.Range("A1").Value」とコード名で書くと、これも、シートがどの位置に入れ替わろうが、ちゃんとSheet2のA1セルの値を取得できます。
なお、「VBAProject.ThisWorkbook.Sheets("Sheet2").Range("A1").Value」と書くこともできますが、この場合は、シートのタブの名前を変えてしまうとSheet2は操作できなくなります。
あと、例えば前述した『 プロパティウィンドウの「(オブジェクト名)」の欄 』で、「Sheet2」を「SheetTest02」という名前に変更した場合は、タブで付けた名前にかかわらず、「Sheet2」ではなく、「SheetTest02 とか、VBAProject.SheetTest02」と書き換えないといけなくなります。
ちなみにですが、「VBAProject」はオブジェクトブラウザでも、「VBAProject」として、一番上のドロップダウン(ライブラリの選択ドロップダウン)にてカテゴライズされています。
コード名を使った「Sheet2」という書き方でどんなプロパティやメソッドが使えるかも、そこから分かります。(Sheets("Sheet2")という書き方の場合、つまり、Worksheetオブジェクトと比較してみましたら、コード名を使った「Sheet2」という書き方の場合は、プロパティとメソッドはWorksheetオブジェクトと基本・同じらしく、イベントが全部含まれていませんでした。)
なお、ユーザーフォームやその部品(「コントロール」と呼びます)には、CodeNameプロパティは無いっぽく、「Nameプロパティ=CodeNameプロパティ」みたいな感じになっているようです。なので、ユーザーフォームがらみでは意味がない=使えない、ということになりそうです。
なお、この書き方・このシートの操作方法は、「自ファイル」にしかできません。
といいますか、複数のExcelファイルを開いていた時は、「シートやブックの側がアクティブになっている・なっていないにかかわらず」、『 ” VBEのプロジェクトエクスプローラの画面の中 ” で現在アクティブになっているファイル(=プロジェクト)のシートとThisWorkbook 』しか扱えないようです。(NewもCreateObjectもできないようなので)
なので、エラーは出にくいといえばそうなんですが、利用シーンが、「一番長い基本の書き方」よりも限定されてしまいます。
今のところ、調べた限りでは、「複数のファイルを同時に開いて転記処理をするようなケース」では「使えない」という感じです。
※:もしかしたらプロの先生なら切り替え方法をご存知かもしれません。
一応当方でも切り替える方法を見つけられはしましたが、かえってエラーや誤作動が増えそうであまり実用的ではありませんでした。
VBEのモジュールのコードペインをコードペインのCaptionをキーにアクティブにすることで、アクティブなVBAProjectを切り替えられるっぽいです。でも事前にそのコードペインが開かれていることが前提です。一度開いたコードペインは、次回のファイルオープン時も自動的に開かれるようです。
でもそんなことを裏方でやるのもエラーが頻出しそうで諦めました。
よって、この「コード名」を使っての書き方は、「1つのファイルを開いている時だけの」「シート操作やThisWorkbook操作」、「限定」、と言えそうです。
※プロジェクト名を、例えば「VBProject」から「PrjTest01」といった感じで書き換えて「参照設定」すれば、参照設定した側からだけ、「PrjTest01.Sheet2.Range・・・」という形でセルを指定できますが、動きがちょっと変なので、トラブルの原因になりそうなのであまりお勧めの方法ではありません。(参照設定するとそのファイルが絶対に開いてしまうし、また、そのファイルを非表示設定にすると閉じるときにめんどくさいし・・・。)
Application.ActiveWindow.ActiveCell.Value
=ActiveWindow.ActiveCell.Value
=ActiveCell.Value
=ActiveCell
(アクティブなウィンドウのアクティブなセルの値)
この書き方も、「もっともエラーや誤作動が出やすい書き方のひとつ」です。
「Range("A1").Value」の書き方よりも出るかもしれません。
「Book1のSheet2のA1セルの値を取得したい」という目的からすると、
アクティブなブックがたまたま「Book1(xls、xlsm、xlsx)」で、
かつ、アクティブなウィンドウのアクティブなシートがたまたま「Sheet2」で、
かつ、たまたまA1セルがアクティブセルだった場合に限り、
この書き方が使えます。
あるいは、ユーザーが手動で、「Book1のウインドウ」の「Sheet2」の「A1セル」を完全にクリックしてからか、もしくはVBAで自動的に、それらを明確に「Select」や「Activate」してからなら使えます。
「ケース限定」なので、基本、エラーや挙動不審・誤作動になりやすいです。
ただし、もちろん、この書き方が便利になるケースもあると思います。
なお、この書き方はユーザーフォームには使えません。
ユーザーフォームにはアクティブセルは無いので・・・。
僕の場合はこの書き方も、
「テスト用」
「値や構造を調べたい時だけ」
「Webに載せるサンプル作成」
「自分しか使わない他人は絶対に使わないすぐ捨てるプログラム」のときに使うことが多い書き方です。
「お仕事としての本番」では、
ActiveCell.CurrentRegion をどうしても使いたい時、
ユーザーにアクティブセルを指定させたい時、
ActiveCellを使うことでなんかのエラーや不具合が回避できる場合、
「今この瞬間の ActiveCell がどのセルなのか?」で条件分岐処理をしたい時、
等々以外は、使うことはあまりありません。
(が、こんなケースは僕の場合はほとんどありません。シュミレーションなどの場合は多いのかも?)
なお、ActiveCellプロパティは、「Worksheet」オブジェクトや「Workbook」オブジェクトには属しません。
つまり、階層構造的に、WorksheetやWorkbookの中には含まれていない=組み込まれていません。
なので、
「ActiveSheet.ActiveCell.・・・」とか、
「Worksheets("Sheet1").ActiveCell・・・」
「Workbooks("Book1.xlsx").ActiveWindow.ActiveCell.・・・」
「ActiveWorkbook.ActiveSheet.ActiveCell.・・・」
などと書いても、全部、エラーになります。(僕もよくやります)
例えば、
「オブジェクトが必要です(そんなオブジェクトにActiveCellは属しとらんから、ちゃんとしたオブジェクト持ってこい!)」とか、
「オブジェクトは、このプロパティまたはメソッドをサポートしていません(あなたが書いたオブジェクトの中には、あなたが書いたプロパティやメソッドはもともと含まれていませんよ?ちゃんとオブジェクトのそもそもの決まりを勉強しなおしてそれを守って書いてください。)」
といった感じのエラーになります。
「ActiveCell」を内包している=保持しているオブジェクトは「ActiveWindow」と「Application」しかないので、
「ActiveWindow.ActiveCell.・・・」と書くか
「Application.ActiveCell.・・・」と書くか
「Application.ActiveWindow.ActiveCell.・・・」と書くか、
全部省略して「ActiveCell.・・・」と書くか、
しかありません。
僕なんかExcel初心者なので、まだしょっちゅう「Worksheets(×××).ActiveCell」と書いてエラーになってしまうのですが、それはExcelの階層構造にはもともと存在しない「ルート」となりますので、当然エラーになりますからご注意ください。
なお、『「ActiveCell」を内包している=保持しているオブジェクトは「ActiveWindow」と「Application」しかない』、ということは、オブジェクトブラウザで「ActiveCell」で完全一致で調べれば、わかります。「Worksheet」や「Workbook」は出てきませんから。そこで、「Worksheet.ActiveCell・・・というルートも存在しない」、と判断できます。
「ActiveCell.・・・」と書くのが一番エラーが少ないと言えばそうですが、にしても、ActiveCellを使うと、「しっかりユーザーがセルを選択するか、Selectメソッドなどで明示的に選択しないと誤作動する」ので怖いですから、僕は「やむを得ない場合・特殊な場合」以外はまったく使いません。
番外01:複数シートの一括選択01:すべてのシート:
Application.Workbooks("Book1.xlsx").Worksheets
=Application.ActiveWorkbook.Worksheets
何らかの「すべての××××××」を一括で同時に指定するには、「コレクション」を使います。
が、その際は上記のように カッコや引数(名前やインデックス番号)は書かずに、「コレクション名」だけ・「1つの単語だけ」を書きます。
逆に言うと、「コレクション名」だけ(単語だけ)が書かれていて カッコやシート名などが書かれていなかったら、
「あ!これは、すべての×××××× のことだな!」と思えばいい・・・
ということになります。
ここではワークシートだけの事例を示しましたが、グラフシート(Chartsコレクション)や図形(Shapesコレクション)などのときも同じです。
全てのワークシートを同時選択する
Application.Workbooks("Book1.xlsx").Worksheets.Select
Application.ActiveWorkbook.Worksheets.Select
全てのワークシートの数を数える
Application.Workbooks("Book1.xlsx").Worksheets.Count
Application.ActiveWorkbook.Worksheets.Count
※注!!01
「Sheets」コレクションを使うと、グラフシートやその他のシートを含め、ワークシートだけでなく全てのシートやを同時選択できます。
ただし、もしワークシートしか作ってなければ、すべてのワークシート「だけ」を選択することになります。
Application.Workbooks("Book1.xlsx").Sheets.Select
Application.ActiveWorkbook.Sheets.Select
※注!!02
コレクションが変わると、「同じような動きをする命令」でも単語の綴りが異なってくる場合も多いです。
例えば、ワークシート上の図形たちを「Shapesコレクション」を使って一括選択するには、「Select」という命令が使えないので「SelectAll」という命令を使います。(以下の式のようになります。。)
Application.ActiveWorkbook.ActiveSheet.Shapes.SelectAll
「Shapesコレクション」では、「すべて選択」という意味の命令が「Select」ではなく、「SelectAll」なのです。
「Select」も「SelectAll」も、「メソッド」と呼ばれる「命令」ですが、「メソッド」は「それぞれのオブジェクトに、独自に紐ついた命令」です。
「メソッド」は、あるオブジェクトでは使えても、あるオブジェクトでは使えません。
なぜそうなるかというと、それぞれのオブジェクトには、それぞれの命令(メソッド)やプロパティが、すべてそれぞれのオブジェクト「独自に」、「最初から決められて作られているから」です。
それを誰が決めて作ったのかというと、マイクロソフト社です。
エンドユーザーからすれば「一緒にしとけばいいじゃない!めんどくせ~!」と感じると思うんですが、大変残念ながら、それは言ってもそうはならないので、「仕方のないこと」になってしまいます。
番外02:複数シートの一括選択02:すべてではないけれど、部分的な複数一括選択:
Application.Workbooks("Book1.xlsx").Worksheets(Array("Sheet1","Sheet2"))
=Application.Workbooks("Book1.xlsx").Worksheets.Item(Array("Sheet1","Sheet2"))
=Application.ActiveWorkbook.Worksheets(Array("Sheet1","Sheet2"))
=Application.ActiveWorkbook.Worksheets.Item(Array("Sheet1","Sheet2"))
すべてではないけれど、部分的に・・・、例えば「3つあるうりの2つのシートを一括選択したい!」という場合などは、「コレクション」に「Array関数」を使います。
「Array関数」は「配列変数に対して直接、複数の値を同時設定できる機能」を有しています。
それとコレクションを組み合わせると、複数のオブジェクトを複数一括同時指定ができるようになります。
以下の例は、(Book1.xlsx・あるいはアクティブなブック上の)、「Sheet1とSheet2」という2つのワークシートを同時選択します。
Application.Workbooks("Book1.xlsx").Worksheets(Array("Sheet1","Sheet2")).Select
Application.ActiveWorkbook.Worksheets(Array("Sheet1","Sheet2")).Select
こちらも、ワークシートだけのことを書きましたが、グラフシート(Chartsコレクション)や図形(Shapesコレクション)などのときも同じです。
なお、
Application.ActiveWorkbook.Worksheets(Array(1,2)).Select
といった感じで、Array関数のところでシート名ではなく、インデックス番号を使うこともできます。
※補足:たくさんあるうちの、3つだけの図形を同時選択する例
図形の場合、まんまでShapesとArray関数だけでは「部分的一括選択」ができません。
さらに、下位のオブジェクトの「Range」との併用をしないといけないっぽいです。
【インデックス番号で複数指定する例】
Application.ActiveWorkbook.ActiveSheet.Shapes.Range(Array(1,3,4)).Select
【名前で複数指定する例】
Application.ActiveWorkbook.ActiveSheet.Shapes.Range(Array("Freeform 5","Rounded Rectangle 1","Straight Arrow Connector 3")).Select
・・・というわけで、「Book1のSheet2(Sheet1ではなく)のA1セルの値を取得したい」という場合、ざっと思いつくだけでも、以上のような、(オブジェクト式というか)コードの書き方がありますが、ほとんどの教室で最初に教えてもらうのは、「Range("A1").Value」という書き方ですよね?
でも、以上を全部お読みになっていかがでしょうか?
(多少間違いがあるかもしれませんが、おおむねこんな感じです。)
使う気します?
「Range("A1").Value」。
初心者の方は『 書き方としては一番簡単だけど、でも「 ” 実務では ” 一番エラーが出やすい」』、って習いました?
(もしくは初心者向けの書籍に 但し書き、そう書いてありました?)
ファイルが一つだけ開いている場合・かつ・目的のシートがアクティブになっている場合だけなら、「Range("A1").Value」というだけでもいいかもしれませんが、それ以外の場合・・・、たとえば・・・
「複数のファイルを開いてそのファイル間で転記処理などをする」場合は、「Range("A1").Value」という書き方だけしか知らないと「転記ミスだらけ、エラーだらけでグッチャグチャになる可能性がある」・・・・、となんとなくでも想像がつきますよね?
だって、「Range("A1").Value」だけでは、「どのブックのどのシートかは決め打ちできないまま」「たまたまアクティブなシートの」A1セルの値を取得するわけになるんですから・・・。(プログラムの実行中にユーザー側で目的のブックやシートをクリックするなんて不可能ですし。)
そして、「複数のファイルを開いてそのファイル間で転記処理などをする」というケースは、VBAが分かってくればくるほど、増えてくるかもしれません。
もう一回、おたずねします。
「Range("A1").Value」、ばっかりを、使う気します?
階層構造のことは深く学ばなくていい、と、そう感じますか?
「いや、だってBookやSheetの名前を書き足せばいいだけだろ?」というご意見もあるでしょう。
そのとき「じゃあなんでBookやSheetの名前を書き足さないといけないの?なんでBook名やSheet名を指定すんの?」という、その質問にすぐさま答えられますか?
例えば「だって、Excelのオブジェクトモデルの全図でそういう階層構造になってるじゃん。見りゃわかるじゃん。その構造の順序 守らないとエラーになるに決まってんじゃん。マイクロソフトがそういう構造にきめちゃったからしょうがないじゃん。Worksheetオブジェクトが一つ上でWorkbookオブジェクトがそのまた一つ上の階層のオブジェクトでしょ? 見なくたってわかるじゃん。上位のオブジェクトなら多くの場合は、TypeName関数とParentプロパティでイミディエイトで調べれば誰でもすぐわかるじゃん。そんなの。」みたいな風に。
そういう風に数秒で答えられないなら、自力でエラー解決などぜんぜんできません。
「だって本にもそう書いてあるから。」とか、「だってそういう決まりだから。普通みんなそうするじゃん。」と、そいういう答え「だけ」で、「みんながそうするからって理由になる?」ということも考えず、『 結局 よく意味もわからずに逃げていたら 』、いつまでたってもこれまた自力のエラー解決できませんし、いつまでたっても初心者の「下の下」の位置のままです。
そういう人は、VBAで他人のファイルを「絶対に」触らないでください。
VBAを使うなら、絶対に自分のファイルだけにしてください。
他人のファイルをVBAで扱いたいなら、基本的には、「何かを知らなくても ” Webを頼らずに ” 、自分で調べられる術を知っている、だいたいの構造をわかっているからそれができる」というスキルが求められるのです。
それができない人は、VBAで他人のファイルを絶対に触らないでください。
「必ず」「シートを指定忘れ、指定ミス、ブックを指定忘れ、指定ミス」などの、「事故を起こして」、「データをメチャクチャにしてしまいます」から・・・。
こちらも もう一回、聞いちゃいます。
バックアップしてない、かつ、みんなの共用のファイル・データでそれやったらどうなります?
あなたの立場は?
そしてこれまでに書いてきたような「VBAのオブジェクト操作の基礎」をないがしろにしてもいいと感じますか?
講師たちに習う必要などない、というお考えのままですか?
「講師たちが隠している、ウソを教えている、ムダを教えている、肝心なことを教えてくれない」と疑うことは一度もしませんか?
そしていつまでたっても、WebのVBAコードのコピペしかできず、Webには書いてない機能を自分で調べて自分で構築していく、なんてことはできないままでしょう。
で、テキトーなWeb情報をコピペして、どんどんどんどん「エラーの温床」を自分で作り、「自分で自分のクビをしてめていく」ことになってしまうのです。
そのほかにも、『 関数バンバン使う系の ” 愚かな・初心者本の著者 ” がよく書く、” ピボットテーブルは要らない ” という愚かな文章を信じてしまい 』、ピボットテーブルはもちろん、SQLやMicrosoft Queryにも全く目がいかず、本来書かなくてもいい無駄な関数と無駄なVBAをどんどん書く羽目になるのです。( 関数バンバン使う系の愚かな著者がよく、但し書きもせずに ” ピボットテーブルは要らない ” というテキトーなウソを書くことが多いので、僕もしかえしに ” 愚かな彼らから見ればテキトーなこと(でも彼らとは違い・真実) ” を書いています。)
こういうことを、たとえば「変数の型」や「オブジェクト変数」「値やオブジェクトを返す自作関数」などについても、「省略」「省略」「省略」で、ぜんぜん「最初に」「一度に」、「最重要な基礎だよ!!」と、教えてくれなかったのがExcelVBAのこれまでの教育方法です。
で、それを、自分の頭で考えないで、マネするだけの質の悪いレッスンが増殖中です。
ExcelVBAが上達するわけがない、と思いませんか?
もちろん、こういった細かいことは、「エラーが出てから学べばいい」という考え方もあります。
もちろんそれでもOKです。
でも、それならそれで『 今は細かいこと言っても混乱してしまうから敢えて言わないけど、必ず一読だけはして。「Range("A1").Value」だけじゃあ、全然対応できないからね。そのつもりでいて。上達したかったらそれ以外の詳しい書き方ももっともっと学ばないとね!概要をある程度把握できて、VBA全体に慣れて来たらまた詳しく学びましょうね!」と自著に書かないといけないはずです。
「エラーが出るまではこれだけ知っていればいいよ。でもエラーが出たらこのようなことは全部確認しないといけないので、そのとき、また少しずつ、詳しく教えるね。挫折しないように頑張って教えるね。だから、絶対に "これさえ知ってればOK" だなんて手抜きしないでね?」と教えなければなりません。
なのに現実には、「これだけ知っていればOK!ねっ!?簡単でしょ?」と「しか」「言わない」、まったく「但し書き」をしない「最低」な教え方をしているのが実情です。
どうでしょうか?
みなさんはエラーがでたとき、上記のこと全部、ちゃんと教えてもらえてます?
そもそも、
『 最初のうちに、わからなくてもいいから、理由・原因はともかく、現象だけでも・よくあるエラーパターンだけでも、ある程度体系的に全体的に、最初に、教わる 』のと、
『 エラーが出たそのときに。そのエラーのことだけテキトーに、エラーが起こるごとにバラバラに教わり、モレもある 』のと、
どっちがいいですか?(僕は前者の方が幸せだと思ってますけど・・・)
難しいから、最初には教えてもらわないほうがいいですか?
都度、教えてもらえばいいですか?
「ここに全部まとめて書いてあるから、最初のうちはわからないかもしれないけど、エラーの度に、何度でも、ここに戻ってきて何度も読み返してみて。必ずわかるようになるから。」という文書は必要ありませんか?
ちなみにですが「Value」プロパティには「引数」すらあります。
(2003以前は無いみたいです。2000にはありませんでした。)
私たちはそれを「省略」して使っていただけだったのです。
ご存じでしたでしょうか?
そのためか、ローカルウィンドウには値が表示されません。
そんなことも最初に教えてくれません。
あるいは、(敢えて教えてくれないなら)それを示唆すらしてくれません。
「無知」による「省略」=エラーや誤作動のもと。です。
僕はVBAはAccessのVBAから入ったのですが、Accessも似たような状況といえばそうですが、でも、
ExcelVBA教育界ほど
「変数の型なんて全部Variant型でいい」とか、
「オブジェクトもしくは階層構造その他省略だらけ」とか、
「オブジェクトの階層構造すら教えない」とか、
そういったメチャクチャ・かつ・いい加減なことは少ない気がします。
「ExcelVBAの挫折者が20年も経ったのにぜんぜん減らないわけだ。初級コースの内容もいっこうに上がらないわけだ。教え方が悪いもんなあ・・・。エラー解決なんてこんなんじゃ絶対自力じゃムリだよね?」と感じてしまいます。
「特にエラーの出ない誤作動解決なんて、もっとムリかも!」とも感じてしまいます。
「Accessのほうがオブジェクト構造は簡単で整理されているかも」と思うので、最初は「Excelのオブジェクト構造、難しいなあ」と感じてましたけど、学びが進むうちに、「そうではない」ことが分かってきました。
「オブジェクト構造が難しい」のではなくて、「 ”ほとんど” のサイトや本で教え方が下手くそ」「ぶっちゃけ教える気がまるでない」「テキトーすぎる」ということに、ようやく気が付きました。
VBA初心者を、「テキトーすぎる」ようにわざと教えて、混乱させ、有料セミナーに習いにこさせているのでは?と勘繰りたくなるくらいです。
いずれにしても、多くの場合で、「最低限の必要なこと・基礎、を ”わざと教えない” からオブジェクト構造を理解できない・しにくい」んだな、と分かってきました。
ついでなのでここで、「ExcelVBAがいつまでたっても上達しない人」の特徴をあげてみたいと思います。(これは、実際に自分でオブジェクトについて調べてみたり、Q&Aサイトでのやりとりを眺めて見たり、僕自身、他人からの質問に少し教えてみたりして、わかってきたことです。
ちなみに僕は以下の項目のことがわかるようになった時点から、急激にWebで調べる回数が1/10以下くらいに減りました。マクロの記録である程度の骨格がわかれば、あとはヘルプに書いてあるからです。まずは都度、オブジェクトブラウザやヘルプでそのプロパティやメソッドや関数がどんな型のデータを返すかなどから調べるほうが、Webや書籍のテキトーな情報に惑わされることも減り、長い目で見れば早いことがわかってきました。最近はマクロ記録もできるだけ使わずに、ヘルプのみで、ということにも少しずつ挑戦しはじめています。どっかで面倒くさくなってやめるでしょうけど。)
※重要・関連記事
Access2000VBA・Excel2000VBA独学~VBAプログラミングとはどんなプログラミング方式なのか?(簡易版)
=====================
Access2000・mdbファイルが壊れる場面と回避方法・解決方法
Access2000・mdbの動作速度をネットワーク越し利用でも速くする方法~結構重要~:★ ダミーテーブルの連結フォームを非表示で常時開いておく
Access2000 100MbpsLAN Pentium3 の「ネットワーク越しのリンクテーブル」の開く速度が遅いときの対処法(Access2000のときからあった既知の問題)
>Access2000・100MbpsLAN Pentium3 でクエリが遅い場合の対処方法(データベース自体が遅い場合にもチェックしてみます。)
Excelが遅くなる場合の対処法~Accessや他のソフトからデータを貼付けした時
Access2000VBA・Excel2000VBA独学~VBAプログラミングとはどんなプログラミング方式なのか?(簡易版)
Access2000VBA・Excel2000VBA独学~用語:VBAプログラミングでの「オブジェクト」 について
ExcelでもAccessでも、顧客台帳(顧客マスタ)を作るときのヒント(できるだけ細かくしてしまう)