ClipBoard操作のコード見つけたんで、ためしに使って作ってみました。
解決済みっぽいけど、自己満足ってコトデ。
WindowsAPIに抵抗ある場合は、コード前半は無視してMyCopyFuncをコメント解除して使用。Copy処理もマクロ化することでコピー元を保持します。Ctrl+Shif+C/Pとかキー割り当てれば、案外使えるかなと。
こんな感じで「絶対参照を無視してコピペ」とか作ると便利かも。
'--> ClipBoard操作する場合ここから
'マクロの使用はペースト時のみでOK
'※アドレス取得まる写し。takanaさんに感謝(-人-)
'ttp://hpcgi1.nifty.com/MADIA/VBBBS/wwwlng.cgi?print+200910/09100010.txt
Private Declare Function MultiByteToWideChar Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByRef lpMultiByteStr As Any, ByVal cchMultiByte As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long) As Long
Private Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
Private Declare Function RegisterClipboardFormat Lib "user32" Alias "RegisterClipboardFormatA" (ByVal lpString As String) As Long
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
'コピー元アドレス取得
Public Function GetCopyAddress() As String
Dim lngFormat&, hMem&, lngSize&, strData() As Byte, i&
OpenClipboard 0
hMem = GetClipboardData(RegisterClipboardFormat("Link"))
If hMem = 0 Then
CloseClipboard: Exit Function
End If
lngSize = GlobalSize(hMem)
ReDim strData(0 To lngSize - 1)
MoveMemory(VarPtr(strData(0)), GlobalLock(hMem), lngSize)
GlobalUnlock hMem
CloseClipboard
For i = 0 To lngSize - 1
If strData(i) = 0 Then strData(i) = Asc(" ")
Next i
GetCopyAddress = AnsiToUnicode(strData())
End Function
Private Function AnsiToUnicode(ByRef strAnsi() As Byte) As String
On Error GoTo ErrHnd
Dim lngSize&, strBuf$, lngBufLen&, lngRtnLen&
lngSize = UBound(strAnsi) + 1
lngBufLen = lngSize * 2 + 10
strBuf = String$(lngBufLen, vbNullChar)
lngRtnLen = MultiByteToWideChar(0, 0, strAnsi(0), lngSize, StrPtr(strBuf), lngBufLen)
If lngRtnLen > 0 Then AnsiToUnicode = Left$(strBuf, lngRtnLen)
ErrHnd:
End Function
'※まる写しココマデ
'コピー元Range取得
Private Function GetCopyRange() As Range
Dim re, mt, adr$
adr = GetCopyAddress
Set re = CreateObject("VBScript.RegExp")
re.Pattern = "Excel .*\[(.+)\](.+) ([RC0-9:]+)"
Set mt = re.Execute(adr)
If mt.Count <> 0 Then Set GetCopyRange = Workbooks(mt(0).submatches(0)).Sheets(mt(0).submatches(1)).Range(Application.ConvertFormula(mt(0).submatches(2), xlR1C1, xlA1))
End Function
<-- ClipBoard操作ここまで
'--> WindowsAPIに抵抗あるならコチラ(要コメントアウト)
'コピー操作はMyCopyFuncで。コピーついでにコピー元を保持。
''(名前定義コピペ) コピー処理
'Function MyCopyFunc()
' GetCopyRange Selection: Selection.Copy
'End Function
''Range保持/取得用@グローバル変数でもいいんだけど
'Private Function GetCopyRange(Optional ByVal rng As Range) As Range
' Static target As Range
' If Not (aRng Is Nothing) Then target = rng
' Set GetCopyRange = target
'End Function
'<-- WindowAPIナシ版ここまで
'--> 以下、共通
'(名前定義コピペ) ペースト処理
Sub MyPastFunc()
Dim nmlist(1 To 100), rng As Range, i&, n&, o
ActiveSheet.Paste
'セルコピー以外終了
If Application.CutCopyMode <> xlCopy Then Exit Sub
Set rng = GetCopyRange 'コピー元取得
If rng Is Nothing Then Exit Sub
'コピー範囲に含まれる名前を取得
On Error Resume Next 'Range.Nameは有無不明
For Each o In rng
Set nmlist(n + 1) = o.Name
If nmlist(n + 1) <> Empty Then n = n + 1
Next
On Error Goto 0
If n = 0 Then Exit Sub
Dim dr&, dc&'位置ズレ取得
dr = Selection.Cells(1, 1).Row - rng.Cells(1, 1).Row
dc = Selection.Cells(1, 1).Column - rng.Cells(1, 1).Column
'名前定義の挿入/差替え
For i = 1 To n
ActiveWorkbook.Names.Add nmlist(i).Name, "=R" & (nmlist(i).RefersToRange.Row + dr) & "C" & (nmlist(i).RefersToRange.Column + dc)
Next
End Sub
お礼
No.1のお礼から先にお読みください。 >「シート間の"名前"の移動は、コピー範囲内で"名前"が使われている場合のみ、かと。ANo.1の1(×J3,○J~L列でした)も、J~L列に、名前つきセルと、名前使用セルを含むことが前提です。」 ↑ このことも今回初めて知りました。 たいへん勉強になりました。 この質問を後から参照なさる検索者のために、一応私が書いたコードも記録しておきます。 名前を付けたセル5つの名前を 結果1~結果5 としました。 質問で書いた J3を基準とする ということを、 「基準点」という値をセルに書き込むことで解決させました。 したがって、新しいブックでL3を基準としたければ L3に「基準点」という値を書き込む 他のセルには「基準点」という値は書き込まない というルールを設けております。 あまりスマートではありませんね。 でも実運用上は、「基準点」という値を書き込む作業は、 コピペで終わっているので、後はマクロを一度動かすだけで 名前の付け直しが終わるので、まあまあ解決かな、と思っております。 どこか邪魔にならない適当なセルに (文字列、数値両方対応) =結果1&結果2&結果3&結果4&結果5 (数値のみの場合) =結果1+結果2+結果3+結果4+結果5 と書き込んでおきます。 書き込まなくても良いです。 どうせ後でマクロで新規に名前を付け直すのですから。 でもまあ一応、 結果1~結果5を使っているセルがあると、コピペのときに名前のついたセルも同じ座標にコピーされる ということで、コピー忘れを防止しています。 以下コード (Dim など宣言を省いてすみません。) (J3 などではなく、実際に用いた座標を記しているので、解読しづらかったらすみません。) Sub sample2() 左上起点を探す: With Range("A1:BA100") 'A1:BA100 よりも検索範囲を広げるなら適当にいじってください。 'この範囲に「基準点」と書かれていないとダメです。 Set p = .Cells.Find(what:="基準点", Lookat:=xlValue) End With If p Is Nothing _ Then MsgBox ("""基準点""というセルが見つかりません") Exit Sub End If OX = p.Column OY = p.Row 'O はOrigin, 原点のつもりです。 Set p = Nothing ShNm = ActiveSheet.Name メイン: 'K=11 'L=12 'M=13 'R=18 '下記の右端のコメントは、R32C11(K32)を起点とした場合の絶対座標。 '32と11を引き算して相対座標をマクロ内に書き込まざるを得ません 'でした。RefersToRange を用いれば、マクロに数値を書き込む必要も 'なくなると思われます。 'D はΔ(デルタ), 差異(オフセット)のつもりです。 Nm = "結果1": DY = 6: DX = 1 '38,12 GoSub 名付け Nm = "結果2": DY = 1: DX = 7 '33,18 GoSub 名付け Nm = "結果3": DY = 1: DX = 2 '33,13 GoSub 名付け Nm = "結果4": DY = 5: DX = 1 '37,12 GoSub 名付け Nm = "結果5": DY = 5: DX = 0 '37,11 GoSub 名付け '(参考:定義された名前の一覧表、R32C11(K32)起点) '"結果1" ='シート1'!$L$38 '"結果2" ='シート1'!$R$33 '"結果3" ='シート1'!$M$33 '"結果4" ='シート1'!$L$37 '"結果5" ='シート1'!$K$37 Exit Sub 名付け: ActiveWorkbook.Names _ .Add Name:=Nm, _ RefersToR1C1:="='" + ShNm + "'!R" + CStr(OY + DY) + "C" + CStr(OX + DX) Return End Sub 以上でコード終わりです。 かなりヘタクソですみません。 実は、あまりネットにアクセスできなかったので、先にこのコードを書いてしまったのです。 でも、ap_2さんの n = Selection.Cells(1, 1).Column - Range("J1").column 'コピー元とのズレ ↑ これかなり良いですね! 自分のコードに生かしていなくて、(ご回答を読めなかったので「質問する意味がない!」と言われそうです。)本当に申し訳ないです。 「基準点」というセル自体がいらないですね。 RefersToRange の使い方、初めて勉強になりました! 精進します。 また、別の質問に回答することで恩返ししようと思います。 本当にありがとうございました。