• ベストアンサー

VBAのシートイベントで教えてください

シートのN4以下で、既に同じ番号があれば「既に同じ番号があります」 と表示するようにしたく、下のように書きましたが、肝心な部分 の、どのように同じ番号をみつけるようにすのかわかりませんでした。 教えていただけないでしょうか。宜しくお願いします。 Private Sub worksheet_change(ByVal target As Range) Dim 範囲左 As Integer Dim 範囲右 As Integer Dim 範囲上 As Integer 範囲左 = 1 範囲右 = 16 範囲上 = 4 With target 'if '指定した範囲の列Nに既に同じ番号や文字列があれば MsgBox "既に同じ番号があります。" End If End With End Sub

  • newme
  • お礼率54% (218/400)

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

  • ベストアンサー
  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.4

A No.1です。既にA No.3の方が述べられていますが、ご指名もいただいているので、遅ればせながら回答させていただきます。 For Each myCell In Sheets(1).Cells If myCell.Address <> target.Address Then If target.Value = myCell.Value Then 処理 Exit Sub End If これだと、ほとんど全てのセルに対して、アドレスのチェックと、値のチェックを行っています。値が同じ時だけ、アドレスのチェックをすれば、チェック回数は、約1/2になります。 加えて、No.3の方のご指摘通り、Sheets(1).UsedRange.cellsにすれば、チェック対象は格段に減ります。 それでも、遅ければA No.1の、Microsoft製のfindが優秀なアルゴリズムか否か試してみてはいかがですか。

newme
質問者

お礼

ご回答ありがとうございました。 なかなかうまくいきません。。。 少し時間をかけて勉強してみようと思います。 お付き合いありがとうございました。

その他の回答 (3)

  • izmlz
  • ベストアンサー率55% (67/120)
回答No.3

 いまいち、実際におやりになりたいことがよくわかっていないので、ご希望のものではないかも知れませんが...  ↓はN4:N65536にデータを入力した際に、N列に入力されているデータと重複している場合、メッセージを表示させるものです。 Private Sub Worksheet_Change(ByVal Target As Range)  Dim Rng As Range  Dim InputRng As Range    Set Rng = Columns("N:N") '重複チェックする範囲を指定  Set InputRng = Range("N4:N65536") '入力する際に重複チェックしたい範囲を指定    If Intersect(Target, InputRng) Is Nothing Or Target.Count > 1 Then Exit Sub  With Application.WorksheetFunction   If .CountIf(Rng, Target.Value) > 1 Then    MsgBox "この番号は既に存在しています。", vbOKOnly + vbExclamation   End If  End With End Sub >無理のあるコードなのでしょうか。 気のついたところを何点か、指摘させていただくと、 >For Each myCell In Sheets(1).Cells  「Sheets(1).Cells」とありますが、N列のデータとの重複チェックではなくて当該シートの全データとの重複チェックなのでしょうか?もし、そうだとしても「Sheets(1).Cells」とするのではなく、「Sheets(1).UsedRange」といったようにするのが良いと思います。ついでにいうと、「Sheets(1).UsedRange」よりも「Worksheets(1).UsedRange」の方が良いかも。  それから、For Each ~ Nextも良いですが、この場合には提示したマクロのようにワークシート関数のCOUNTIFを使う方が効率が良いんじゃないかと思いいます。 >If .Column >= 範囲左 And .Column <= 範囲右 _ >And .Row >= 範囲上 Then  行や列を変数にすることもありますが、それはその方が処理がしやすい場合に限りそうするべきじゃないかと思います。そうでなければ、可読性が格段に良いので、私の提示したコードのように、「Set InputRng = Range("N4:N65536")」といった感じでセル範囲をセットする方が良いと思います。

  • okormazd
  • ベストアンサー率50% (1224/2412)
回答No.2

ただ、それだけでよければ、N列のデータ範囲に未入力セルがないとして、 Private Sub Worksheet_Change(ByVal Target As Range) With Sheets(1) r = 4 ndat = .Cells(r, 14) 'N4 While ndat <> "" If Target <> ndat Then r = r + 1 ndat = .Cells(r, 14) Else MsgBox "既に同じ番号があります。" Exit Sub End If Wend End With End Sub

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.1

XL2000のVBEのヘルプから、findの使用例です。CopyRight Microsoft... With Worksheets(1).Range("a1:a500") '検索範囲の指定の仕方は、ここで分かりますね。 Set c = .Find(2, lookin:=xlValues) 'この例では、指定範囲に2が見つからないと、cはNothingになります。 '下記は、複数存在する全てを拾っていますので、省略可です。 If Not c Is Nothing Then firstAddress = c.Address Do c.Interior.Pattern = xlPatternGray50 Set c = .FindNext(c) Loop While Not c Is Nothing And c.Address <> firstAddress End If End With

newme
質問者

お礼

mitarashiさんこんにちは。いつもご回答見させていただいております。ご回答いただいていることも知らず、自分で試行錯誤していました。アドバイスいただいておいて、 自分の作ったコード(といってもネットで参考にしたものですが・・・) のことを聞くのは恐縮ですが、下のようにつくりました。 一応・・・動くのですが、パソコンの性能のせいか、 続けて入力すると砂時計が出て、何分経っても戻らず、Escなど 押してもどうしようもなくなるときがあります。 無理のあるコードなのでしょうか。 Private Sub worksheet_change(ByVal target As Range) Dim 範囲左 As Integer Dim 範囲右 As Integer Dim 範囲上 As Integer Dim myCell As Range 範囲左 = 14 範囲右 = 14 範囲上 = 4 With target If .Column >= 範囲左 And .Column <= 範囲右 _ And .Row >= 範囲上 Then For Each myCell In Sheets(1).Cells If myCell.Address <> target.Address Then If target.Value = myCell.Value Then MsgBox "この番号は既に存在しています。", vbOKOnly + vbExclamation Exit Sub End If End If Next End If End With End Sub

関連するQ&A

  • セルの値を消すとVBAエディタ画面でエラーが出てしまいます。

    セルの値を消すとVBAエディタ画面でエラーが出てしまいます。 "特定の列"に、"特定の値"を入力したとき、(下記実例では1列目に値6) 次の行からその値に24を足し続けるというプログラムを作りました。 実行すると動くことは動くのですが、シートに移ってそれらの数字を消すと 「実行エラー、方が一致しません」とVBAエディタ画面に戻りエラーになってしまいます。 このエラーを出さなくするにはどうしたらよろしいでしょうか? その他、これ以外に改善点などございましたらご教授願います。 Private Sub Worksheet_Change(ByVal Target As Range) Dim 列番号 As Integer Dim 行番号 As Integer Dim 時間 As Integer If Target.Column = 1 Then If Target.Value = 6 Then 行番号 = ActiveCell.Row 列番号 = ActiveCell.Column For 時間 = 30 To 2046 Step 24 Cells(行番号, 列番号).Value = 時間 行番号 = 行番号 + 1 Next 時間 End If End If End Sub

  • エクセルVBAのイベントで質問です。

    ダブルクリックイベントで、G12:G31の範囲の文字列をB10:B27の範囲(最下行)に入れていくものを使っていますが、新たにH12:H31にある文字列もダブルクリックするとC10:C27の範囲(最下行)に入れていけるようにしたいと思います。 どのようにすればいいでしょうか。 ご存知の方いらっしゃればお教えいただけると助かります。 Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Excel.Range, _ Cancel As Boolean) Dim i As Long Dim flg As Boolean If Intersect(Target, Range("G12:G31")) Is Nothing Then Exit Sub If IsEmpty(Target.Value) Then Exit Sub With Worksheets("シートA") For i = 10 To 27 If .Range("B" & i).Value = "" Then .Range("B" & i).Value = Target.Value flg = True Exit For End If Next i If flg = False Then MsgBox .Name & " がいっぱいです。" End If End With Cancel = True End Sub

  • VBA:Callステートメントでいつでもイベント発生可能な準備をしたい。

    タイトルどおり、Callステートメントでいつでもイベント発生可能な準備ができるようにしたいと考えています。しかし、Sub 実行準備SUBでエラーが出ています。どこをどう直せばよいのか教えて頂きたいです。 Private Sub Auto_Open() MsgBox "Ctrl + t でイベント実行準備を行います。" Application.OnKey "^{t}", "実行準備SUB" End Sub '--------------------------------------------------- Sub 実行準備SUB() Dim Target As Range Target = Range(Cells(1, 1), Cells(100, 100)) Call Worksheet_Change(ByVal Target) End Sub '--------------------------------------------------- Private Sub Worksheet_Change(ByVal Target As Excel.Range) Dim r As Range For Each r In Target If r.Column = 2 Then r.Offset(0, -1).Value = Now End If Next r End Sub イベントは、シートの2列目のセルに変更があれば、1列目に日付時刻を記入するというものです。宜しくお願い致します。

  • VBAについて

    以下のプログラムは、1年間の価格合計を求めるプログラムです。 これを実行するとうまくいくこともありますが、エラーが起きることもあります。 どうやら下記コードが原因のようなのですが、間違いがわかりません。 Target.Offset(0, 1).Value = run * (13 - month) どこが間違っているのでしょうか。 また最終的に、A行かB行のどちらかが更新されたときにこのプログラムを 実行させたいのですが、方法がわかりません。 無知な質問ではありますが、どなたか教えてください。 --------------------------------------------------------- Private Sub Worksheet_Change(ByVal Target As Range) Dim month As Integer Dim run As Integer If Intersect(Target, Range("A25:A35")) Is Nothing Then Exit Sub Else If Target.Offset(0, -2).Value <> "" Then month = Target.Offset(0, -2).Value month = month - 3 If month = -2 Then month = 10 ElseIf month = -1 Then month = 11 ElseIf month = 0 Then month = 12 End If run = Target.Offset(0, 0).Value Target.Offset(0, 1).Value = run * (13 - month) End If End If End Sub

  • Changeイベントに指示を加えたい

    こんにちは 現在ワークシートで下記マクロにて、日付・時間の履歴を自動入力しています。 3行目以降のC列のセルに何か入力すると、そのとなりのD列のセルに日付と時間が返されるものです。 Private Sub Worksheet_Change(ByVal Target As Range) Dim r As Integer, c As Integer r = Target.Row c = Target.Column If c < 3 Or c > 3 Or r < 3 Then End If Cells(r, c) <> "" Then Cells(r, c + 1) = Format(Now, "yyyy/m/d h:mm") Else Cells(r, c + 1) = "" End If End Sub この同一シートに、下記マクロの指示を加えたいのですが、うまくいきません。 3行目以降のE列のセルに "chcl" とすると、B列のセルに "機能回復" と自動入力されるものです。 Private Sub Worksheet_Change(ByVal Target As Range) Dim r As Integer, c As Integer r = Target.Row c = Target.Column If c < 5 Or c > 5 Or r < 3 Then End If Cells(r, c) = "chcl" Then Cells(r, c - 3) = Format("機能回復") Else Cells(r, c - 3) = "" End If End Sub まとめると・・・・・・ 3行目以降のC列のセルに何か入力すると、そのとなりのD列のセルに日付と時間が返され、 且つ、 3行目以降のE列のセルに "chcl" とすると、B列のセルに "機能回復" と自動入力される、 というシートが欲しいのです。 上記マクロ、それぞれ単発だと機能するのですが、一緒に出来ません。 どなたか、解決方法をご教授下さい。 よろしくお願いします。

  • 列が対象のChangeイベントの入力セル選択

    Private Sub Worksheet_Change(ByVal Target As Range) Dim myrang As Range 'K列に入力した時 If Target.Column = 11 And Target.Count = 1 Then With Workbooks("システム.xlsm").Worksheets("台帳").Columns(7) Set myrang = .Find(what:=Target.Value, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=False, matchbyte:=False, searchformat:=False) End With If myrang Is Nothing Then Dim intret As Integer       '☆ intret = MsgBox("入力エラーです!", vbCritical + vbOKOnly, "エラー発生") Else      処理2のコード End If Target.Offset(2, 0).Select End If     End sub 以上のコードがあります。 ’☆のメッセージボックスを出し、OKを押したとき、入力したセルを選択して終了させたいのですが、 今のままでは、最後の Target.Offset(2, 0).Select を選択してしまいます。 どのようにすればいいのでしょうか?

  • VBA シートプログラムでRangeエラー

    いつもお世話になっております。 Excel2003を使用しております。 シートに直接プログラムを書いています。 (例として、Sheet1とします) シートの内容が変わったときに、色々プログラムを実行していこうと思っているのですが、 Private Sub Worksheet_Change(ByVal Target As Range) のTargetが上手く取得できていない気がします。 今までは上手く動いていたのですが、 急にTargetの値に数値(セルに入力した値)が入ってしまうようになり 上手く組めなくて困っています。 Private Sub Worksheet_Change(ByVal Target As Range) Dim 開始1 As Range Dim 終了1 As Range Dim 開始2 As Range Dim 終了2 As Range Set 開始1 = Range("D5:D63") Set 終了1 = Range("E5:E63") Set 開始2 = Range("F5:F63") Set 終了2 = Range("G5:G63") If ThisWorkbook.ActiveSheet.ProtectContents Then '保護かかってたら End '強制終了 End If If Not Application.Intersect(Target, 開始1) Or Application.Intersect(Target, 実績日開始2) Is Nothing Then Call 開始(Target, 開始1, 開始2) ElseIf Not Application.Intersect(Target, 終了1) Or Application.Intersect(Target, 終了2) Is Nothing Then Msgbox "テスト!" End If End Sub '----------------------------------------------- Sub 開始(ByVal Target As Range, 開始1 As Range, 開始2 As Range) If Not Application.Intersect(Target, 開始1) Is Nothing Then MsgBox Target.Row End If If Not Application.Intersect(Target, 開始2) Is Nothing Then MsgBox Target.Row + 1 End If End Sub 全部シートに書いています。 まだ、テスト段階のため適当なプログラムしか書いておりません。 (指定範囲が変更された場合に、Msgboxを出したりなど 単純なことしかしていません) どこが悪いのか、教えて頂けないでしょうか? よろしくお願い致します。

  • エクセル マクロ 初心者です

    エクセルマクロ初心者です。 以下の2つの Private Sub Worksheet_Change(ByVal Target As Range)を1つのシートで実行させたいのですが、 当方、初心者なので組み合わせ方が分かりません。 よろしくお願いします。 ===No1=== Private Sub Worksheet_Change(ByVal Target As Range) Application.EnableEvents = False Target = StrConv(Target, vbUpperCase) Application.EnableEvents = True End Sub ===No2=== Private Sub Worksheet_Change(ByVal Target As Range) Dim Ans As Integer If Target.Count = 1 Then Ans = MsgBox("コピーは禁止!!", vbCritical) MsgBox "データを消去します。" With Application .EnableEvents = False .Undo .EnableEvents = True End With End If If Target.Count = 1 Then Exit Sub Else MsgBox “複数セルのコピー禁止!" With Application .EnableEvents = False .Undo .EnableEvents = True End With End If End Sub ------------ 上記の2つを1つのシートで動作させたいのですが、うまくいきません。 単体では、動作します。

  • WorkSheet_Changeを2つ反映させる

     下記のコードをWorkSheetで2つ反映させるにはどうしたらいいでしょうか?どちらか一つなら反映するのはわかりますが、どう名前を変更すればいいのかお教え願えませんでしょうか? windows7・SP1 Office2010 Private Sub WorkSheet_Change(ByVal Target As Range) If Intersect(Target, Range("C1")) Is Nothing Then Exit Sub '検査範囲 Application.EnableEvents = False '再帰実行の停止 If Range("C1").Value <> Sheets("祝祭日").Range("A1").Value Then MsgBox ("祝日の設定を反映するため年度を同じにしてください。") End If Application.EnableEvents = True End Sub Private Sub WorkSheet_Change(ByVal Target As Range) Dim MyRow As Long Dim MyCol As Integer MyRow = Target.Row MyCol = Target.Column With Worksheets("メイン・1").Select If MyRow = 1 And MyCol = 7 Then If Target = 4 Then 'または If Target = 1 Then メインデータの復元 '動かしたいマクロ名 End If End If End With End Sub

  • エクセルで、こうやっても反応なしです。

    よろしくお願いします。以下のように組んで見ました。 Private Sub Worksheet_Change(ByVal Target As range) Dim clm As Integer Dim row As Integer clm = Target.Column row = Target.row If Worksheets("発注指示").Cells(row, clm) = "不足" Then MsgBox "在庫不足", vbOKOnly, "注意" End If End Sub どうして動かないのでしょう。 本当にわからないので、教えてください。 これで一日つぶれました。

専門家に質問してみよう