サポンテ 勉強ノート

サポンテの勉強ノート・読書メモなどを晒します。

コピー元の領域を取得する【Excel/VBA】【裏技編】

はじめに

 Excel でコピーや切り取りカットをしたときに、そのコピー元になる範囲を VBA で取得したいケースが出ました。

 すでになにかソリューションがないか、ネットで検索してみます。

VBA コピーされたセル範囲を取得する方法 - Excel | ホームページ制作のサカエン Developer's Blog

 ありました。

Worksheet_SelectionChange イベントと API を利用する必要があります。

 めんどいw

 API 使用すると macOS で使えないんですよ。あとワークシートイベントを使うと、アドイン化するときにまた手間なんですよ。

 それに、自分のプロジェクトに組み込みたいスニペットはもっと短くしてほしいんですよ。できれば 30 行程度の関数やクラス一つで。

 Office クリップボードVBA で取得する方法はないでしょうか。

Office クリップボードをマクロで操作する(MSAA) | 初心者備忘録

 ありました。

以前書いたコードは、OfficeやOSのバージョンが変わると動作しませんでしたが、今回はバージョンの差異も一応考慮しています(Excel 2007,2010,2016で確認)。

 これも API 使うんですね。

結局作った

 こういうときはアレですよ、裏技。裏技で良いんですよ、裏技で。

 以下の条件で作りました。

  • API を使用しない
  • 関数ひとつ
  • Range を返す(返せないときは Nothing

使い方

 セル範囲を選択して、コピーまたはカットをします。

 この状態で関数を実行すると、コピー元の範囲の Range オブジェクトを返します。選択された状態の範囲がなければ Nothing を返します。

ソースコード

Option Explicit

Function GetCutCopyRange() As Range
    ' カット・コピー状態でなければ Nothing を返す
    Set GetCutCopyRange = Nothing
    If Application.CutCopyMode <= 0 Then Exit Function
    
    ' 現在の状態を保持する
    Dim savedCondition As Boolean
    savedCondition = ActiveWorkbook.Saved
    
    On Error GoTo ERROR_EXIT
    ' 表示更新を一時停止する
    Application.DisplayAlerts = False
    Application.ScreenUpdating = False
    
    ' リンク図としてペーストする
    Dim dummy As Variant
    Set dummy = ActiveSheet.Pictures.Paste(Link:=True)
    
    ' リンク図からリンク先を取得する(リンク図は不要になるので削除する)
    Dim f As String
    f = dummy.Formula
    dummy.Delete
    
    ' リンク先からアドレス他を取得する
    f = Replace(f, "=", "", 1, 1)
    
    Dim wb As Workbook, ws As Worksheet
    Set wb = ActiveWorkbook
    Set ws = ActiveSheet
    
    ' 別のワークブックか
    Dim bracketPos As Long, bracketPos2 As Long
    bracketPos = InStr(f, "[")
    bracketPos2 = InStr(f, "]")
    If bracketPos > 0 Then
        Set wb = Workbooks(Mid(f, bracketPos + 1, bracketPos2 - bracketPos - 1))
        f = Mid(f, bracketPos2 + 1)
    End If
    
    ' 別のワークシートか
    Dim exclamationMarkPos As Long
    exclamationMarkPos = InStr(f, "!")
    If exclamationMarkPos > 0 Then
        Set ws = wb.Sheets(Replace(Mid(f, 1, exclamationMarkPos - 1), "'", ""))
        f = Mid(f, exclamationMarkPos + 1)
    End If
    
    ' Range を取得して返す
    Set GetCutCopyRange = ws.Range(f)
ERROR_EXIT:
    ActiveWorkbook.Saved = savedCondition
    Application.DisplayAlerts = True
    Application.ScreenUpdating = True
End Function

 30 行にはなりませんでした、すみません。

どこが裏技か

 ソースコードを追っていただければわかりますが、コピー範囲を一旦「リンクされた図」にペーストし、リンク先を取得してすぐに消しています。ペーストした図が見えないように、画面更新を一旦停止しています。また、保存済みのワークブックが「編集された状態」にならないように、状態を書き戻しています。

 あまりスマートなやり方とは言えませんが、まあ自分のプロジェクトにはこれで十分です。

Excel マクロ&VBA やさしい教科書 [2021/2019/2016/Microsoft 365対応] (一冊に凝縮)

夏を乗り切るための社畜ハック

はじめに

 サポンテは社畜なのでクールビズの奴隷です。そしてそれは良いことです。

 しかしながら近年は暑さが猛々しくなってきているのでつらい。そんなときに役に立った簡単なライフハックをご紹介します。

やりかた

 最近は、汗を拭いたり洗顔の代わりとなるようなウェットティッシュが薬局に並んでいます。とくに夏になると、店頭に山のように置かれています。

 その中でも、メントール成分を使って冷感を謳うものがあります。以下のようなものですね。サポンテは香料が苦手なので、無香を使っています。

続きを読む

Git の「ステージング」はなんのためにある?【git/add/ステージ】

不思議な手順「ステージング」

 Git には、変更点を記録する「コミット」__他の VCSバージョン管理システム だと「チェックイン」と呼称される場合もあります__の前に「ステージに追加」という不思議な手順があります。

 他の VCS を経験してから Git に入門すると、このひと手間ワンクッションが、まったく不思議なのです。なぜ直接コミットできないのか。この手順が一体なんのためにあるのか、どんな場合に有用なのか。

 Git の入門的な書籍やサイトには、腑に落ちるわかりやすい具体的な説明がなぜか少ない。サポンテがかつて読んだ入門的なテキストにも納得できる説明はありませんでした。

 そのような訳で、わりと長い間の疑問でした。

続きを読む

チェック項⽬2-2 1シートに複数の表が掲載されていないか【Excel/総務省の統一ルール】

< 目次へ

例4

 (これまでの経緯を見ると「例1」でいいのでは?)

続きを読む

チェック項⽬2-1 データが分断されていないか【Excel/総務省の統一ルール】

< 目次へ

例1

 例1については、とくにコメントないので割愛します。どうしてこんな表を作るのか...。なにかしら分けたい気持ちがあるなら、罫線を太めにするとか、見出しの背景色を変えるとかで対応できるのに。

例2と例3

 一つの表が、複数に分割されています。

 このようなことをしたくなる動機としては、以下の2つが考えられます。

  • 表が広くなってくると、スクロール時に見出しが隠れてしまう
  • 印刷時、複数ページにわたって見出しを出力したい

 それぞれで解決法があるので、参考にしてください。

続きを読む

チェック項⽬1-12 地域コード⼜は地域名称が表記されているか【Excel/総務省の統一ルール】

< 目次へ

 以下の例に続く本文に「標準地域コードを併記すべし」と書かれています。

続きを読む

チェック項⽬1-11 e-Stat の時間軸コードの表記、⻄暦表記⼜は和暦に⻄暦の併記がされているか【Excel/総務省の統一ルール】

< 目次へ

 和暦をそのまま文字列として入力するのはアンチパターンです。編集しづらく、機械による読み込みにも向いていません。資料の「修正後」にあるように西暦を併記するのも有効です。

 別解として、データは汎用性の高い日付値として入力し「セルの書式設定」で見た目だけを和暦表示にする事もできます。以下に手順を詳述します。

続きを読む