セル範囲の変化によって日付が入るマクロ

このQ&Aのポイント
  • Excelのマクロを使用して、セル範囲に変化があったときに日付が入るプログラムの作成方法について質問します。
  • 以前、A1からS19までのセルに変化があったときに日付けが入るマクロについて質問しましたが、このマクロではセルの値を変更した場合だけでなく、列を挿入または削除した場合にも日付が入ってしまいます。
  • 列の挿入または削除の場合には日付が入らないようにする方法について教えてください。
回答を見る
  • ベストアンサー

セル範囲に変化があったときに日付けが入るマクロ

お世話になっております。 以前、A1からS19までのセルに変化があったときに日付けが入るマクロについて、 この掲示板で質問させていただいた者ですが、さらに伺いたいことがあります。 そのときは、以下のプログラムを教えていただきました。 private sub Worksheet_Change(byval Target as excel.range)  dim h as range  on error resume next  for each h in application.intersect(target, range("A1:S19"))   application.enableevents = false    cells(h.row, "T") = date   application.enableevents = true  next end sub しかし、質問の時点でご指摘のあったことではあったのですが、このプログラムだと 値を変更したとき、セルをダブルクリックして編集可能にしたときだけではなく、 A列からS列に列を挿入したとき、又は列を削除したときも一斉にT列に日付け が入ってしまいます。 列の挿入・削除の場合は、日付けが入らないようにすることは可能でしょうか? 教えていただけると幸いです。よろしくお願いいたします。

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

  • ベストアンサー
回答No.7

あるとき例えば 1 列を挿入したら、その後は T 列ではなく、U 列に日付を記入するようになっていてほしいということですよね? 列を挿入したとき、シート上にある何かの数式中のセル参照は、絶対参照と相対参照のどちらであっても、自動的に番地が変化していきますね。なので上のお話をされているのであれば、絶対参照云々とはちょっと違う気もしますが…。絶対参照にすると動かないというのは、数式を記入してあるセルをコピーして他所に貼り付ける場合などですね。 Excel という機械であれ人間であれ、1 列挿入したらその後は U 列に記入すべきなんだということが判断できるためには、何らかの基準を持っていないといけませんね。基準となり得る情報は様々考えられると思いますが、一例としては、近くにある特定のセルを見て、それが T 列から U 列に動いたので、今は U 列に記入すればいいんだなと分かるとか。 例えば T1 セルに「日付」という文字列があり、それが U 列なり S 列に動いても、その新しい位置を探して日付データを記入させるなら、例えば下のような感じで書けるでしょう。(今回 Range("A1:S19") を Range("A2:S19") と書き換えてあります) 必要であれば、Range("A2:S19") という範囲も同様にして目印を探すことにより、可変にすることもできるでしょう。 Private Sub Worksheet_Change(ByVal Target As Range)   Dim r0 As Range, r1 As Range, r2 As Range   Set r0 = Rows(1).Find(what:="日付", lookat:=xlWhole)   Set r1 = Intersect(Target, Range("A2:S19"))   If r0 Is Nothing Or r1 Is Nothing Or Target.Address = Target.EntireColumn.Address Then Exit Sub   For Each r2 In r1     If r2.Value <> "" Then  '「ユーザーがセルをクリアした場合」であっても日付を記入したければ、この行を削除       Application.EnableEvents = False         Cells(r2.Row, r0.Column).Value = Date       Application.EnableEvents = True     End If  '「ユーザーがセルをクリアした場合」であっても日付を記入したければ、この行を削除   Next r2 End Sub

qazxcvfr4
質問者

お礼

ありがとうございました。 この度は親切に教えていただき、大変助かりました。

その他の回答 (6)

回答No.6

何度も申し訳ありません。 「Target.Count >= Rows.Count」という条件を「Target.Address = Target.EntireColumn.Address」と書き換えても、複数の列の挿入・削除のケースを処理対象から除外できますね。EntireColumn は、Target が属する列全体という意味です。このほうがセル数に関係ないので、ベターかもしれませんね。 こちらも修業中の身ですので。すみません。 Private Sub Worksheet_Change(ByVal Target As Range)   Dim r1 As Range, r2 As Range   Set r1 = Intersect(Target, Range("A1:S19"))   If r1 Is Nothing Or Target.Address = Target.EntireColumn.Address Then Exit Sub   For Each r2 In r1     If r2.Value <> "" Then  '「ユーザーがセルをクリアした場合」であっても日付を記入したければ、この行を削除      Application.EnableEvents = False        Cells(r2.Row, "T").Value = Date      Application.EnableEvents = True     End If  '「ユーザーがセルをクリアした場合」であっても日付を記入したければ、この行を削除   Next r2 End Sub

qazxcvfr4
質問者

お礼

ありがとうございます。 ところで、1点伺って良いでしょうか。 「Cells(r2.Row, "T").Value = Date」の部分についてですが、 T列を絶対参照にすることはできますか? 今の状態だと、列を挿入・削除してもT列のままになってしまいます。 通常の関数であれば「$」をつければ絶対参照になりますが、VBAの場合は どのように記述すれば良いか、ご存知でしょうか。

回答No.5

No.4 です。度々すみません。書き漏らしたことを。 複数セルにコピペするという場合も、ループしないといけませんね。 >お手数おかけしますが、よろしくお願いいたします。 単にコード教えてくださいというよりも、むしろこのようなご質問のほうが回答者としてはモチベーションが高まります。

qazxcvfr4
質問者

お礼

ありがとうございます。 親切な対応、感謝します。

回答No.4

>「Target.Count >= Rows.Count 」とはどういう意味なのでしょうか?rowは行のことだと思いますが、この記述で列の挿入・削除に対応できているということでしょうか。 まず Target について。VBE(Visual Basic Editor)画面が開いているときにキーボードの F1 を押すと表示されるヘルプで、Worksheet.Change イベント(セルの値の記入・クリア、列の挿入・削除といった変更)を検索すると、パラメータ Target は、Range 型の変数であり、「変更された範囲」(シートに変更があった瞬間に選択されているセル範囲)を表すと書いてあります。 続いて range を検索すると、Range オブジェクトや Range オブジェクト メンバ(オブジェクトに用意されているメソッドとプロパティ)のページが見付かります。そして、Range.Count プロパティ(セル範囲中にあるセル数)というものがあることが分かります。 VBA において、Rows と Row のような単数と複数の単語は、異なるオブジェクトを表します。厳密に区別してください。 Row は、Row オブジェクト(単一の行)。Rows オブジェクトは、Row のコレクション(集合)です。Worksheet.Rows プロパティにより特定されるオブジェクトです。そのヘルプにも説明があるとおり、「そのシートの全ての行」を表します。Worksheet が ActiveSheet である場合は、「ActiveSheet.」という記述を省略し、単に Rows と書くことができます。 Rows(1) というふうにインデックスを付けると、Rows オブジェクトではなく、「行番号 1 の行」という Row オブジェクトを表します。Rows("1:2") のようにアドレスを付ければ、2 行のオブジェクトですね。単数で Row(1) と書くのは、誤りです。 Rows.Count プロパティは、シートの(セル数ではなく)全ての行数を表します。Excel 2003 以前では 65,536、2007 以後では 1,048,576 という数値です。 以上により、ご質問の不等式は、「選択している範囲中のセル数がシートの行数以上」、すなわち「挿入・削除などのために 1 列以上の全体を選択している状態」(通常の操作の場合)かどうかを判定しようとしていることが分かります。条件に該当すると、Exit Sub(残りのコードを実行せずにプロシージャを終了)することになります。 なお r1 Is Nothing は、Target と Range("A1:S19") に重なりがないことを意味します。 >r2については、範囲指定(定義)していないように見えるのですが、どういった役割を持つ変数なのでしょうか。 r2 は、r1 中の各セルを表します。なぜこれが出てくるのかと改めて問われると困るのですが、For Each ... Next の構文を使うには必ず、型の合った適当な変数を用意してあげる必要があるということです。インターネット上に無数の情報が転がっているとは思いますが、例えば参考 URL でお勉強してみてください。 >また、r1に続き、繰り返しの処理をする理由はなんでしょうか。 セルへの値の記入などを行ったとき、選択している範囲が 1 セルのみであった場合は、r1 と r2 が同じセルを表すことになります。1 回のみのループとなるので、ループする必要はありません。複数のセルを選択した状態で値をタイプし、Ctrl を押しながら Enter すると、選択していた全セルに同じ値が記入されますね。その場合は r1 中の各 r2 について T 列への日付の記入という処理を繰り返すため、ループにしています。 >なお、前に答えてくださった方は、エラー発生のケースも説明してくださいましたし、その場合もコードも書いてくださいました。 なるほど。

参考URL:
http://officetanaka.net/excel/vba/statement/ForEachNext.htm
qazxcvfr4
質問者

お礼

親切に詳しく教えていただき、ありがとうございます。 何度も拝読して、ようやくわかってきた感じがします。 すっきりしました。

  • keithin
  • ベストアンサー率66% (5278/7940)
回答No.3

とりあえず >セルをダブルクリックして編集可能にしたときだけではなく… というお話なので、先のご相談への回答で何回か出てきたのを一部盛り込んで応用し private sub Worksheet_Change(byval Target as excel.range)  dim h as range  if target.count > 1 then exit sub  on error resume next  for each h in application.intersect(target, range("A1:S19"))   cells(h.row, "T") = date  next end sub ぐらいしておけば十分です。 まぁ繰り返しにはなりますが「列・行の挿入」も「編集」という意味では一緒なので、今回ご質問の状況のようにマクロは同様に動作します。 「この編集」はOKで「こういう編集」は対象外にしたいと使いながら見えてきたら、そのようにマクロを改修していけば良いというお話です。 #余談ですが 教わったマクロを元に新たなご相談が発生した際は、「教わった回答からコピペして質問」するんじゃなくて、「それを元にいま実際にあなたのエクセルで動かしてるマクロ」の方をご自分のエクセルからコピーして掲示し、情報提供してください。回答を元にあなたが勝手にどこか書き換えたのが原因で、新たなご相談の状況が発生している可能性だってあるのですから。

qazxcvfr4
質問者

お礼

前回に続き、ありがとうございます。 複数のセルを操作した場合はマクロが起動しない、という記述を加えたのですね。 勉強になりました。 >#余談ですが 以後、そのようにいたします。

回答No.2

No.1 です。すみません、「複数の」列の挿入・削除に備えて「=」を「>=」に書き換えたので、次のコードに差替えをお願いします。 Private Sub Worksheet_Change(ByVal Target As Range)   Dim r1 As Range, r2 As Range   Set r1 = Intersect(Target, Range("A1:S19"))   If r1 Is Nothing Or Target.Count >= Rows.Count Then Exit Sub  '列の挿入・削除への対策を追記   For Each r2 In r1     If r2.Value <> "" Then  '「ユーザーがセルをクリアした場合」であっても日付を記入したければ、この行を削除       Application.EnableEvents = False         Cells(r2.Row, "T").Value = Date       Application.EnableEvents = True     End If  '「ユーザーがセルをクリアした場合」であっても日付を記入したければ、この行を削除   Next r2 End Sub

qazxcvfr4
質問者

お礼

親切にありがとうございます。 しかし、VBAの初心者でしてわからない点があるので、教えていただけると助かります。 >  If r1 Is Nothing Or Target.Count >= Rows.Count Then Exit Sub   '列の挿入・削除への対策を追記 「Target.Count >= Rows.Count 」とはどういう意味なのでしょうか? rowは行のことだと思いますが、この記述で列の挿入・削除に対応できているという ことでしょうか。 >  For Each r2 In r1         Application.EnableEvents = False         Cells(r2.Row, "T").Value = Date       Application.EnableEvents = True    Next r2 r2については、範囲指定(定義)していないように見えるのですが、 どういった役割を持つ変数なのでしょうか。 また、r1に続き、繰り返しの処理をする理由はなんでしょうか。 お手数おかけしますが、よろしくお願いいたします。

回答No.1

あまりお勧めしにくいというか、わざと?手を抜いたコードを採用されたのですね。On Error Resume Next は、原因の特定が困難なエラーが発生しそうな場合に、仕方なく使うといった感じが望ましいです。つまり、なるべく事前に原因をつぶしておき、それらに対応するための処理をコードに含めるのが基本です。 Private Sub Worksheet_Change(ByVal Target As Range)   Dim r1 As Range, r2 As Range   Set r1 = Intersect(Target, Range("A1:S19"))   If r1 Is Nothing Or Target.Count = Rows.Count Then Exit Sub  '列の挿入・削除への対策を追記   For Each r2 In r1     If r2.Value <> "" Then  '「ユーザーがセルをクリアした場合」であっても日付を記入したければ、この行を削除       Application.EnableEvents = False         Cells(r2.Row, "T").Value = Date       Application.EnableEvents = True     End If  '「ユーザーがセルをクリアした場合」であっても日付を記入したければ、この行を削除   Next r2 End Sub

qazxcvfr4
質問者

お礼

書いてくださって、大変ありがとうございます。 なお、前に答えてくださった方は、エラー発生のケースも説明してくださいましたし、 その場合もコードも書いてくださいました。

関連するQ&A

  • 日付を入れるとセルがおかしくなります。

    http://okwave.jp/qa/q7495702.html 以前の質問で、空白になった行を詰めていくような マクロをおしえていただき、mt2008さんのコードを利用しているのですが、新たにB列に、C列に何かが入力されたら日付を挿入する以下のマクロをいれました。 Private Sub worksheet_change(ByVal Target As Excel.Range) Dim h As Range On Error Resume Next For Each h In Application.Intersect(Target, Range("C:C")) If h <> "" Then Cells(h.Row, "B") = Date End If Next End Sub このマクロはちゃんと動いたのですが、実はここで困ったことが発生しました。空白行を詰めた時、 日付が詰めた日付に更新されてしまうのです。これは、B列の文字列が変わるのでしょうがない現象なのですが、詰める時に、どうしても日付だけはそのままにして上に詰めたいのです。 そんなことは可能でしょうか・・

  • 指定範囲のセルが変更されたら

     下記のコードで1つのセル(A1)が変更されたら入力前の元データを別シート(A1)に保存できるようにしたのですが、指定範囲(I10:CW42,2行3列を一升)のセルが変更されたら別シートの指定範囲(I10:CW42)に保存できるようにしたいのですが方法がありましたらお教え下さい。お願いします。 Windows7・SP1 Office2010 Private Sub Worksheet_Change(ByVal Target As Range) If Target.Address <> "$A$1" Then Exit Sub Application.EnableEvents = False Application.Undo Sheets("Sheet2").Range("A1").Value = Range("A1").Value Application.Undo Application.EnableEvents = True End Sub

  • このマクロあっていますでしょうか?よろしくお願いいたします。

    ★sheetA Private Sub Worksheet_Change(ByVal Target As Range) If Target.Address <> "$C$14" And Target.Address <> "$C$19" _ And Target.Address <> "$F$19" Then Exit Sub If Target.Address <> "$R$14" And Target.Address <> "$S$14" _ And Target.Address <> "$T$19" Then Exit Sub Application.EnableEvents = False With Sheets("B") .Range("F14").Value = Range("C14").Value .Range("F17").Value = Range("C19").Value .Range("F20").Value = Range("F14").Value .Range("F23").Value = Range("F19").Value End With With Sheets("C") .Range("F13").Value = Range("R14").Value .Range("F14").Value = Range("S14").Value .Range("F18").Value = Range("T19").Value End With Application.EnableEvents = True End Sub ★sheetB Private Sub Worksheet_Change(ByVal Target As Range) If Target.Address <> "$F$14" And Target.Address <> "$F$17" _ And Target.Address <> "$F$23" Then Exit Sub Application.EnableEvents = False With Sheets("A") .Range("C14").Value = Range("F14").Value .Range("C19").Value = Range("F17").Value .Range("F19").Value = Range("F23").Value End With Application.EnableEvents = True End Sub ★sheetC Private Sub Worksheet_Change(ByVal Target As Range) If Target.Address <> "$F$13" And Target.Address <> "$F$14" _ And Target.Address <> "$F$18" Then Exit Sub Application.EnableEvents = False With Sheets("A") .Range("R14").Value = Range("F13").Value .Range("S14").Value = Range("F14").Value .Range("T19").Value = Range("F18").Value End With Application.EnableEvents = True End Sub

  • 個数入れた隣のセルに日付したい

    Excel2000です。05-06-17に QNo 1455706でセルをクリックして日時を入れる方法をおそわりました。 No1manyu-manyu さまの 『ctrl』+『;』で日付、 『ctrl』+『:』で時刻を入れられるのは便利でしたが、一つのセルに両方を入れると2005/7/268:34の様につながってしまいます No2Wendy02 さまの以下のVBAはセルをクリックすると決定書式で入るのですが、これを K列(K4:K1000)に入荷個数の数値を入れたときL列(L4:L1000)のセルに表示するようにしたいのです。お助け ご教授ください。 Private Sub Worksheet_SelectionChange(ByVal Target As Range) If Intersect(Target, Range("L4:L1000")) Is Nothing Then Exit Sub  'L4:L1000"の範囲外は除外  If Not IsEmpty(Target.Value) Then Exit Sub '上書きはしない  Application.EnableEvents = False  Target.Value = Format$(Now, "mm/dd AM/PM hh:mm")  Application.EnableEvents = True End Sub

  • マクロに詳しい方!エクセルの日付入力について

    エクセルの日付入力について、例えばB列に何か入力したら自動的にA列に入力した日がB列に表示されるようにする方法(TODAY関数のように常に現在の日付ではなく、入力した日のまま固定にする方法)について検索したところ、下記の通り、マクロをつかった回答がありました。 http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1413916824 B列に入力し、A列に日付を書き込む場合 B1→A1 B2→A2 B3→A3 … -------------------- Private Sub Worksheet_Change(ByVal Target As Range) If Target.Column <> 2 Then Exit Sub Application.EnableEvents = False Target.Offset(, -1).Value = Now Application.EnableEvents = True End Sub -------------------- 小生はマクロが分かりませんが、上記のコードをコピペ入力すると、その通りになりました。 そこで、みなさんにご相談ですが、これをA列に入力→B列に日付、C列に入力→D列に日付、E列に入力→F列に日付・・・・・というようにしたいのですが、そのコードを教えて頂けないでしょうか。 何卒お知恵をお借りしたくお願い致します。

  • マクロ 複数のシートに適用する記述がわかりません

    いつも皆様方にはたいへんお世話になっております。 下記のマクロをシート3~33(同じ構造です)まで、適用したいのですが、一つ一つのシートに貼り付けていけばよいのですが、なんとか一つの記述で出来ないかと、以前この質問コーナーでの回答を寄せ集めて、記述したのですが、コンパイルエラーばかりで、どうにもなりません。 こんな初歩的なことは、最小限の勉強で解決出来るのかも知れませんが、どうにもなりません。 誠に恐縮ですが、下記の記述の「どこを」「どの様に」修正したらよいか、どなたか解る方、教えて頂けないでしょうか。 どうぞ、よろしくお願いいたします。 Private Sub worksheet_change(ByVal Target As Excel.Range) Dim sheetno As Integer          ←この3行を当てずっぽうで挿入してみました><; For sheetno = 3 To 33 Worksheets(sheetno).Select h As Range Set Target = Application.Intersect(Target, Range("E5:N12, E14:N22, E24:N28, E30:N34")) On Error Resume Next For Each h In Target If h <> "" Then Application.EnableEvents = False h = Application.VLookup(h.Value, Worksheets("マクロリスト表").Range("A:B"), 2, False) Application.EnableEvents = True End If Next End Sub

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

    エクセルマクロ初心者です。 以下の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つのシートで動作させたいのですが、うまくいきません。 単体では、動作します。

  • このマクロを訂正できますでしょうか?

    private sub worksheet_change(byval Target as excel.range) dim h as range on error resume next for each h in application.intersect(target, range("C:C")) if h <> "" then cells(h.row, "A").formular1c1 = "=COUNTA(R1C[2]:RC[2])" cells(h.row, "B") = date else h.offset(0,-2).resize(1, 2).clearcontents end if next end sub このマクロはC列に入力すると、A列に番号、B列に入力した日付が入力されるマクロです。 現状の問題として、 (1)A列に計算式が入ってしまうこと (2)C3セルに品名という項目が入っているために、C4から品目を入力していく上で、最初の割り振られるNOが2番からになってしまう の2つの問題が生じています。これを解決するにはどのように訂正すればよいかご教授いただければ助かります。

  • Excel VBAでの日付の表示形式指定について

    以下のサイトを参考に、B列に入力するとC列に自動で日付が挿入されるようなVBAを作成し、日付を「07/19」という表示形式にしたかったので、Format関数で指定しました。 http://hpcgi1.nifty.com/kenzo30/b_cbbs/cbbs.cgi?mode=al2&namber=34979&rev=&no=0&P=R&KLOG=226 -----VBA------------ 'B列入力で日付自動挿入 Private Sub Worksheet_Change(ByVal Target As Range) Dim RR As Range Dim R As Range Set RR = Intersect(Target, Range("B:B")) If RR Is Nothing Then Exit Sub Application.EnableEvents = False For Each R In RR If R.Value <> "" Then R.Offset(, 1).Value = Format(Date,"mm/dd") Else R.Offset(, 1).ClearContents End If Next Application.EnableEvents = True End Sub --------------------- うまく日付が挿入されるのですが、なぜか表示形式が 「7月19日」と日本語表記になってしまいます。 「セルの書式設定」で「mm/dd」と設定すればいいのかもしれませんが、VBAで設定する方法はないのでしょうか?

  • マクロで指定した文字以外にも入力出来るようにしたい

    いつもお世話になります。 今回は以前に教えてもらったマクロで数字をセルに入力しると、マクロ表シートであらかじめ決めている項目の文字に変わるという構文を教えてもらいました。 下記に記します。 Private Sub worksheet_change(ByVal Target As Excel.Range) Dim h As Range Set Target = Application.Intersect(Target, Range("D4:K34, M4:U34, W4:AA34, AC4:AG34")) On Error Resume Next For Each h In Target If h <> "" Then Application.EnableEvents = False h = Application.VLookup(h.Value, Worksheets("マクロリスト表").Range("D:E"), 2, False) Application.EnableEvents = True End If Next End Sub さて、このマクロでは決めた数字以外の文字や数字を入力すると「#N/A」というエラーが返って来ます。 そこで、このセルに文字を入れたり、他の数字を入れられる様にしたり、データの入力規制でドロップダウンリストを付けて他の項目を選んで入力したりしたいのです。 そういう事がもし出来るなら、上記の構文の「どこ」に「どのような」記述を入れたら良いか、ズバリ教えて頂けないでしょうか。 厚かましい、質問ですが、 どうぞ、よろしくお願い致します。

専門家に質問してみよう