- ベストアンサー
認識するイベントの範囲を制限したい。(VBA)
エクセルのVBAではchangeイベントやselection_changeイベントでは、シート全体に対するイベントが実行されると思うのですが、それを自分の決めた範囲のみに対するイベントのみをとりたいのですが、どうしたらいいでしょうか? 便利な何かがあればいいのですが、取りあえず原始的に、ある範囲のrowやrows.count、columnやcolumns.countを使ってtargetがその中にあるかどうかとゆう方法でやりました。もっと簡単にできないでしょうか? よろしくお願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
>取りあえず原始的に、ある範囲のrowやrows.count、columnやcolumns.countを使って >targetがその中にあるかどうかとゆう方法でやりました。 >もっと簡単にできないでしょうか? 当然、rowやcolumnを使って範囲を特定することも行いますが、範囲の形状で面倒になったりします。 普通行っているのは、 自分の決めた範囲を定義する。離れた範囲や複雑な範囲は『Union』で定義すると効果的。 ↓ Targetを単一セル単位で処理 ↓ 単一セルが自分の決めた範囲にあれば処理を行う。『Intersect』を使い、判定を行う。 範囲の行数・列数の計算や判定回数が減り、分かりやすく書ける気がします。。 こんな感じで書いています。 Private Sub Worksheet_Change(ByVal Target As Range) Dim rg As Range '変更したセル Dim myArea As Range 'この範囲で何かを行う Set myArea = Union(Range("B2:B5"), Range("C6:C9"), Range("D10:D13")) For Each rg In Target If Not Intersect(myArea, rg) Is Nothing Then MsgBox "Hit!!" End If Next End Sub
その他の回答 (3)
- nishi6
- ベストアンサー率67% (869/1280)
Intersectメソッドの使用例(Help)には、 Worksheets("Sheet1").Activate Set isect = Application.Intersect(Range("rg1"), Range("rg2")) If isect Is Nothing Then MsgBox "共通部分がありません。" Else isect.Select End If とあります。 この、『isect Is Nothing』は、Is演算子で2つのオブジェクト変数(isect と Nothing)を比較して、 2つが同じならTrueが返ってきます。『=』の代入の意味ではありません。 この場合、片方がNothingなので、式がTrueならisectもNothingになり、共有セル範囲が存在しないことになります。 ここで気になるのが、『Nothing』って何?ということですが、DimステートメントのHelpに、 『・・・宣言したオブジェクト変数にオブジェクトが代入されるまでは、その変数には Nothing という 特殊な値が設定されます。Nothing は、その変数がオブジェクトの特定のインスタンスを参照していない ことを示します。』とあります。 個人的には、『Is Nothing』はIntersectやFindで『共有部分がない、見つからない』の意味で使っています。 上のような書き方を、個人的には下のように書いています。 If Not Intersect(myArea, rg) Is Nothing Then 日本語表現では『共有部分がないということでなければ』でしょうか。 この式の『Not Intersect(myArea, rg) Is Nothing』を考えます。 Not演算子は式の論理否定を求めます。 従って、Notに対応する式は Intersect(myArea, rg) Is Nothing になります。 この式の意味はHelpと同様、Intersect(myArea, rg) と Nothing を比較して 一致したらTrue(と言うことは、Intersectした結果がNothing=何もない)です。 Intersect(myArea, rg) で2つのセル範囲の共有部分を求める ↓ Intersect(myArea, rg) Is Nothing で共有部分がなかったら式はTrueになる で共有部分ががあれば式はFalseになる ↓ Not Intersect(myArea, rg) Is Nothing で共有部分がなかったら式はFalseになる で共有部分ががあれば式はTrueになる 分かりやすく書くと Not(Intersect(myArea, rg) Is Nothing) です。 ↓ 結局、共有部分があれば、Ifの判別式はTrueになります。
お礼
有難うございました。大変わかりやすかったです!! よくわかりました。いろんなところで使えそうですね。行と列をそれぞれみるより断然こっちの方が読解性がありますね。 ほんとにお世話になりました。有難うございました。
補足
あ~ほんとに何回も申し訳ありません。rgとゆうのはどの部分のことでしょか? Targetが一つのセルではなく広い範囲だとして、その中のセルを一つずつみるとゆうことで、For文でセルの数だけまわしているのでしょうか? 私は範囲が一列と31行だったので、For文を使わずに Public Function M_isArea(ByVal target As Range) Dim my_area As Range M_isArea = False Set my_area = Range("入社退社")←31行1列です。 If Not Intersect(target, my_area) Is Nothing Then M_isArea = True End If End Function としてみましたが、大丈夫ですか?動かした感じは大丈夫そうなのですが・・・ rgとはなんだったのでしょうか?申しわけありません。よろしくお願いします。
- TAGOSAKU7
- ベストアンサー率65% (276/422)
えーとですねー Hook=引っ掛ける ですよね? VBやVBAにはそれぞれイベントがあります。 それはなぜ起こるかというと、OSとアプリケーションとの間でメッセージのやり取りがあるからです。 それをアプリケーションが現状を認識しチェンジイベントなどを起こします。 そのOSとアプリケーションとのやりとりのメッセージを盗み見たり、変更させてしまうのです。 それが俗にHookと呼ばれています。 ここの質問掲示板にもHookを使用した例をいくつか載せてますので、見てみると面白いかもしれませんね ^^
お礼
なるほど~。そんなマニアックな技が存在するのですね~。とても私にはできそうにもないですね。有難うございました。
- TAGOSAKU7
- ベストアンサー率65% (276/422)
>自分の決めた範囲のみに対するイベントのみをとりたい 無理と思われます。 イベント発生はエクセル内部のシートオブジェクトで行われている物です。 イベントはオブジェクト単位で発生します。 一度エクセルシートをHookさせようとしたことがあるのですが、共有メモリ部分を参照しようとすると、EXCELが以上終了を連発しました。 もしこの方法が成功しても明らかに面倒な方法です。おすすめできません。 >ある範囲のrowやrows.count、columnやcolumns.countを使ってtargetがその中にあるかどうか それが最適な方法です。 範囲にあるかどうかをチェックするロジックを作っておき、その関数がTRUE/FALSEを返す仕組みにしておくことが、一番簡潔な方法だと思います。
お礼
有難うございます。やはり無理なのですね。それがわかっただけでも良かったです。そうですね、TAGOSAKU7さんの教えてくださったようにやっていましたので、それを自分の関数としてあちらこちらで使いまわししたいと思います。 ところで、Hookとは何でしょうか?プログラム初心者(パソコン自体初心者です)なもので、よくわかりませんでした。
お礼
有難うございます。聞きなれないUnionやIntesectとゆうのがでてきたので、早速調べてこの方法でプロトタイプを作ってみようと思います。
補足
補足ではないのですが、どうしてもわからないことがありましたので・・・ > If Not Intersect(myArea, rg) Is Nothing Then この一文なのですが、Is Nothingがよくわかりませんでした、いろいろ調べてみましたが、参照しなくなるとか利用できなくなるとか書いていました。Intersectは共通部分と書いていましたので、Not Intersect(myArea, rg) だとmyAreaと rg の共通部分ではないところとゆう感じでしょうか? のIs Nothing とはどのような意味になるのでしょか?