• ベストアンサー

マクロが動きません

以下のようなプログラムでC3の値が変わるたびにA10の値に1を加えていきG3,H3が両方0になったらA10の値も0にする。C5の値が変わるたびにA15の値に1を加えJ3,K3が共に0になったらC5も0にするようにしました。 しかし、動作しません。 このシートの3行目は=シート名!セル番号 という形でほかのシートのセルの値が表示されるようになっています。G3、H3、J3、K3に手動で数値を入力した場合 は動作します。 ほかのシートのセルの値を表示させたセルの値が変化しても動作させる方法はないでしょうか> Private Sub worksheet_change(ByVal target As Range) With target If .Count > 1 Then Exit Sub If IsNumeric(.Value) = False Then Exit Sub If IsEmpty(.Value) = True Then Exit Sub If Not .Row = 3 Then Exit Sub Select Case .Column Case 3 Range("A10").Value = Range("A10").Value + 1 Case 5 Range("A15").Value = Range("A15").Value + 1 End Select End With If Range("g3").Value = 0 And Rang("h3").Value = 0 Then Range("A10").Value = 0 If Range("j3").Value = 0 And Rang("k3").Value = 0 Then Range("A15").Value = 0 End Sub

質問者が選んだベストアンサー

  • ベストアンサー
  • Musaffah
  • ベストアンサー率36% (37/101)
回答No.4

#2、#3さんの言うように、確かに深く考えずにシンプルにしたほうがいいでしょうね。 ちなみに条件付ではありますが、こんなんはどうでしょうか? 結果を表示させるワークシートを"Sheet1"、"リンク先(実際の値を入れている)ワークシートを"Sheet2"として説明します。 また、#1さんのコメントは反映させてください。 (1)リンク先のセル位置を同じにする。 つまり、"Sheet1"ワークシートのC3セルのリンク先は必ず"Sheet2!C3"セルとします。 (2)作成された関数をPublic関数にする。また関数名も独自なものにする。 Public Sub Recal(ByVal target As Range)   ・   ・ (質問者さんが作成されたコード)   ・ End Sub (3)Sheet2にchangeイベントを作成する。 こんな感じで作成します。 Private Sub Worksheet_Change(ByVal Target As Range) Call Worksheets("Sheet1").Recal(Target) End Sub これで条件付(同じセルをリンクしなければならない)ではありますが、お望みのものができると思いますよ。 どうでしょうか?

その他の回答 (4)

  • matsu_jun
  • ベストアンサー率55% (146/265)
回答No.5

まずは訂正から 1) 現状のソースでは、C3とE3の変更時に反映されることになっています。   質問文が間違っているのなら良いのですが、そうでないのならば、   ソースの6行目、7行目の「.Row」と「.Column」は逆ですよ。 2) Wendy02様もご指摘のとおり、冒頭に   Application.EnableEvents = False   最後に   Application.EnableEvents = True   が入るべきです。そうでないと、ソース内部でセルの値を変更した時   再度このルーチンに入ってしまうからです(再帰処理が発生してしまう)。   今回の例では無限ループ(呼び出すたびに同じルーチンを呼び出しなおして、処理が終了しないこと)は   発生しませんが、worksheet_changeイベント利用時には、常におまじないとして入れておきましょう   実際は、念のために、以下のように記述するくせを付けるとよいかと存じます。   Private Sub Worksheet_Change(ByVal Target As Range)     On Error GoTo ERRHND  'ルーチン上エラーが発生したら下のラベル行ERRHND:以下へジャンプ     Application.EnableEvents = False  'イベント発生の抑止。これでイベント内でセルの値を変更しても再帰しない。     'ここに実際の処理を記述     'Exit Sub は利用しない、処理を中止したい場合は GoTo ERRHND と記載する     'さもないと次回から(ブックの開きなおしまで)イベントが発生しなくなります   ERRHND:     Application.EnableEvents = True  'イベント発生の復活   End Sub 3) これもWendy02様ご指摘ですが、14、15行目、Rangeの「e」が抜けています。 4) セルG3、H3、J3、K3をチェックするルーチンに届かないケースが大半になっています。   現状ソースの14、15行目を実行する条件として、   条件1) 変更した行が3行目(元のソースが間違っていないとして)である   条件2) 変更後のセルの値が数値である   条件3) 変更後のセルが空白でない   以上3条件を全て満たしている場合のみしか届かなくなっています。   最終的に他からのリンクによりG3、H3、J3、K3の値が変更されることになると、場合によっては   全くチェックがされないことになりますね。これを避けるためには、14、15行目の上にラベルを付け、   現在 Exit Sub と記述してある部分を、 GoTo (ラベル名) と記述するとよいでしょう。 さて、以上踏まえた上で、解答を。 「Workbook_SheetChangeイベントを利用すれば万事OKです」 ThisWorkbookオブジェクト内のWorkbook_SheetChangeイベントであれば、どのシートのセルが 変更されても発生するイベントですから、あとからどう数式や参照シートを変更しても 常に参照できることになります。当然このイベントには、ターゲットのシートオブジェクト およびターゲットが引数として引き渡されるので、イベント内でシート名も簡単に参照できます。 詳しい説明は、tkoo様のスキルであれば不要と思いますので、とりあえず以下にコードだけ記載します。 Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)   Application.EnableEvents = False   On Error GoTo ERRHND   If Sh.Name = "Sheet1" Then   'ここに目的のシート名が入る     With Target       If .Count > 1 Then Exit Sub       If IsNumeric(.Value) = False Then GoTo DATCHK       If IsEmpty(.Value) = True Then GoTo DATCHK       If Not .Row = 3 Then GoTo DATCHK       Select Case .Column       Case 3         Sh.Range("A10").Value = Sh.Range("A10").Value + 1       Case 5         Sh.Range("A15").Value = Sh.Range("A15").Value + 1       Case Else         GoTo DATCHK       End Select     End With   End If DATCHK:   With Sheets("Sheet1")      'ここにも目的のシート名が入る     If .Range("G3").Value = 0 And .Range("H3").Value = 0 Then .Range("A10").Value = 0     If .Range("J3").Value = 0 And .Range("K3").Value = 0 Then .Range("A15").Value = 0   End With ERRHND:   Application.EnableEvents = True End Sub

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.3

読み落としていました。 >ほかのシートのセルの値を表示させたセルの値が変化しても動作させる方法はないでしょうか 自シートを開いている限りは、他シートからのリンクしたセルは、他シートを開いて操作しなければ、変わらないのでは?他シートは閉じている限りは、NonActiveです。 自シート開いた時点で、チェックする方法はあるけれど、それよりは、papayukaさんのご指摘のとおりだと思いますね。

  • papayuka
  • ベストアンサー率45% (1388/3066)
回答No.2

質問のポイントは、他のシートへリンクされているセル値の変更を捕らえたいって事? 難しく考えずに、リンク元になっている他シートの Worksheet_Changeで処理すれば良いだけじゃない?

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.1

ただ、見た感じだけですけれども、基本的なことですが、イベントで、こういうコードを置く場合は、 >Range("A10").Value = Range("A10").Value + 1 ◎ Application.EnableEvents =False '*ワークシートへ記入するコード '**ワークシートへ記入するコード ◎ Application.EnableEvents =True それと、最後の部分は、タイプミス?一度は、ワークシートで行ってみたのかな? Rang("h3").Value = 0 Then Range("A10").Value = 0   ↓ Range("h3").Value Rang("k3").Value = 0 Then Range("A15").Value = 0   ↓ Range("k3").Value 後は、 Select Case .Column で、Case 3 と、Case 5 はありますが、Case Else がないようなので、そのまま、その下のコードを実行していくのですか?もし、それで良いのでしたら、たぶん、大丈夫だと思います。