|
▼かず さん:
>▼β さん:
質問を再度整理しました。
コピーしたセルの挿入時、挿入行の行番号
を把握するための方法について教えてください。
1.業務要件
(1)建設プロジェク(=案件と呼ぶ。)の案件名、担当社、売上、利益
などを1行にまとめて月次でメンテしています
(2)大元のマスタリストがあり、それを月に一回、10人の担当者に配布。
担当者は自分の担当案件の追加や、案件の売上や利益の変化を、配布
された表に記載して返信。
(3)各担当から返信されたリストを大元のマスタに反映させています
2.担当者が案件情報をリストに反映する際の記載ルール
▼(更新):
リストの各行に対し変更ががある場合、行の1列目に▼印をつける。
削除は行削除ではなく、案件の進捗を示すセルを用意して、
失注として表す。リストの行の削除は考慮不要。
★(挿入):
リストに対し、案件=行を追加する場合1列目に★印をつけて、行
ごと追加する
2.ワークシートのイメージ
(1) 最初にマスタ側リスト作成時、リスト右端余白で今は使われていない
部分に以下の作業列を追加
列 作業列1 作業列2 作業列3
番号 日時時刻 シーケンスNo 枝番
A/1 (略) BL/64 BM/65 BN/66 現時点の枝番号の計算式
行 --------------------------------------------------------------------------------
10 ␣ (略) 2016/3/26/ 18:23 1 1 =COUNTIF($BM$10:$BM709,BM10)
11 ␣ 略
12 ␣ 略
13 ★ (単純な空行の挿入) ・␣・ 1 =COUNTIF($BM$11:$BM709,BM11)
14 ␣
15 ・・ ・2016/3/26/ 18:23・・6・・1 =COUNTIF($BM$15:$BM15,BM15) (A)
16 ★・(15行目をコピー挿入) 6・・2 =COUNTIF($BM$16:$BM16,BM16) (A)
17 ␣ 略
18 ␣ 略
19 ★・(20行目をコピー挿入)・ 9・・2 =COUNTIF($BM$18:$BM709,BM18) (B)
20 ␣・・・・・・・・・・・・ 9・・2 =COUNTIF($BM$19:$BM709,BM19) (B)
709 ・・・・・・・・・・・・・697・ 1 =COUNTIF($BM$10:$BM709,BM709)
【説明】
行の挿入には、単純な空行の追加とコピーした行の挿入の2種類がある。
どちらの場合も、井川はるき著 VBA裏ワザ大辞典Sample31_1のコードを
参考にして行が挿入されたことは添付のコードで検知可能。
業務要件から1列目に★印をつけたいが、コピー元はそのままで
コピー先にだけ★印をつけたい。
⇒ 単純空行の挿入の場合は、本来はシーケンスNoとしているBM列に空白が
できるのでそこをFind文で探して 行番号を取得可能。
・ただしコピーして挿入の場合は、BM列の値は同じ値の行が複数できてしまう。
BN列に枝番号や重複有無を示す計算式を入れる方法、(上記(A)(B)あるがいずれも
うまくいかない)では重複していることはわかるがどの行が挿入されたかわからない。
・コピーして挿入なので タイムスタンプではコピー前とコピー後の区別がつかない
【質問事項】
Q1 コピーした行を挿入のイベントが発生した場合に、イベント処理の中で
どの行が挿入されたか枝番やタイムスタンプか、他の方法で特定する方法
をご存知の方は教えてください。
Q2 上記のイベント処理では、ブックを開いて閉じるまでのイベントをタイマ
監視しているが何かの理由でイベントの監視ができなくなった場合、
イベント処理をあきらめて手動でワークシートを記載してもらえればよい
ようにするにはどうしたらよいでしょうか
既定のイベントでは Application.EnableEvents = False を発行すれば
イベントが発生しなくなるので、自作イベントでもそのようにするにはど
すればいいいでしょうか?
イベント監視処理は中止します。修正が終了したら1列目に▼や★を書くの
を忘れず記入してくださいとメッセージがだせれば十分です。
3.イベントプロシジャを使うコード
井川はるきさんおサンプルコードを一部改変して作成しました。
私には少し難しい方法のようです
' 井川はるき さんのサンプルコード
' ★印の行は 投稿者 かずが改変した部分
’***************************************
' サンプル解説の?@ クラスモジュール clsRowsInsertEvent
' ***************************************
Public Event RowsInsert(Cancel As Boolean, InsRow As Long) ’★ InsRowを追加 by かず
Public Sub CheckRowsInsert(ByVal mySht As Worksheet)
Static myRow As Range
Dim myInsRow As Long '★ 行を挿入した行番号を格納するための変数
Dim myCancel As Boolean
Dim w_FndRng As Range
Const TopRow As Integer = 29 '★ 作業列2の最初の行番号の
Const SeqCol As Integer = 65 '★ 作業列2の列番号
Const EdaNum As Integer = 66 '★ 作業列2 枝番を格納するための行
Dim i As Long '★ 制御変数
If mySht Is Nothing Then Exit Sub
With mySht
If Not myRow Is Nothing Then
On Error Resume Next
myInsRow = myRow.Row
If Err().Number <> 0 Then
’★単純な行の挿入の場合、SeqCol列の空白を探す
Set w_FndRng = Range(Cells(TopRow, SeqCol), Cells(Rows.Count, SeqCol).End(xlUp)).Find("", , xlValues, xlWhole, xlByRows, xlNext) '★
If Not w_FndRng Is Nothing Then ’★
' ★単純に行挿入された場合 SeqCol列は""空白のセルがある
myInsRow = w_FndRng.Row ' ★
Else
'★ コピーして挿入の場合、作業列2には元の行と同じ値が入る
i = TopRow '★
Do While (i < Rows.Count) '★
If Cells(i, EdaNum) > 1 Then '★
myInsRow = i '★
Exit Do '★
End If '★
i = i + 1 '★
Loop '★
End If '★
RaiseEvent RowsInsert(myCancel, myInsRow)
If myCancel Then
Application.Undo
End If
End If
End If
Set myRow = .Rows(.Rows.Count)
End With
End Sub
'***********************************************************
' ?A 標準モジュール
'***********************************************************
Sub TimerProc(ByVal Hwnd As Long, ByVal uMsg As Long _
, ByVal idEvent As Long, ByVal dwTime As Long)
On Error Resume Next
ThisWorkbook.RowsInsertEventClass.CheckRowsInsert Sheet3 ’★引数Sheet3をかずの環境にあわせて設定
End Sub
’***************************************
' ?B ThisWorkbook
' ***************************************
Private Declare Function SetTimer Lib "user32" ( _
ByVal Hwnd As Long, ByVal nIDEvent As Long _
, ByVal uElapse As Long, ByVal lpTimerFunc As Long) _
As Long
Private Declare Sub KillTimer Lib "user32" ( _
ByVal Hwnd As Long, ByVal nIDEvent As Long)
Private WithEvents myRowsInsertEventClass As clsRowsInsertEvent
Private myTimerId As Long
Private Sub myRowsInsertEventClass_RowsInsert(Cancel As Boolean, myInsRow As Long)
'
'★ 作業列1 時刻取得して タイムスタンプをとる(予定)
'★ 作業列2 シーケンシャル番号を格納する(予定)
MsgBox myInsRow & "行に挿入されました" ’★ 現状 挿入行を確認するため MsgBoxを出力
Cancel = MsgBox("行が挿入されました。" & vbCrLf _
& "キャンセルしますか?", vbInformation Or vbYesNo) = vbYes
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim myRes As VbMsgBoxResult
If Not Saved Then
myRes = MsgBox("'" & Name & "' への変更を保存しますか?" _
, vbExclamation Or vbYesNoCancel)
If myRes = vbYes Then
Save
ElseIf myRes = vbNo Then
Saved = True
Else
Cancel = True
Exit Sub
End If
End If
KillTimer 0&, myTimerId
Set myRowsInsertEventClass = Nothing
End Sub
Private Sub Workbook_Open()
myTimerId = SetTimer(0&, 0&, 0&, AddressOf TimerProc)
End Sub
Public Property Get RowsInsertEventClass() As clsRowsInsertEvent
If myRowsInsertEventClass Is Nothing Then
Set myRowsInsertEventClass = New clsRowsInsertEvent
End If
Set RowsInsertEventClass = myRowsInsertEventClass
End Property
|
|