私の初めてのマクロ

私の初めてのマクロ

今さらながら、私とVBAとの出会いについて書いておこう。

VBAとの出会い

きっかけは、

番号入力セルに番号を入力してプリントアウト、次の番号を入力してプリントアウト、次の番号を入力してプリントアウト……を150回ぐらい繰り返す、という業務との出会い

であった。

ちょうどWordの差込印刷のような作業。

Excelに差込印刷機能はないようだ。しかし、Wordで出来ることをExcelで実現しているやつがいないはずがない!」との確信をもとにインターネッツを調べ、

tech.nikkeibp.co.jp

このページにたどり着いたのが始まりであった。

このページに載っていたコードが次のもの。

リスト1
Option Explicit

Sub 個人票印刷()
Range("個人番号") = Range("自")
Do While Range("個人番号") <= Range("至")
    Sheets("個人票").PrintOut
    Range("個人番号") = Range("個人番号") + 1
Loop
End Sub

たとえば、

f:id:akashi_keirin:20190929181459j:plain

このような「個人票」というシートがあり、「個人番号」欄(A4セル)に番号を入力したら、

f:id:akashi_keirin:20190929181502j:plain

このシートからデータを引っ張ってきて「名前」欄(B4セル)とか、「実数」欄(B7~B10セル)に表示する、というふうになっていると思ってほしい。

個人票」シートでは、

f:id:akashi_keirin:20190929181506j:plain

f:id:akashi_keirin:20190929181513j:plain

f:id:akashi_keirin:20190929181516j:plain

このように、それぞれセルに名前を付けている。

で、上掲のコード。

なかなか壮絶なコードであるw

しかしながら、こいつのおかげで

番号入力セルに番号を入力してプリントアウト、次の番号を入力してプリントアウト、次の番号を入力してプリントアウト……を150回ぐらい繰り返す、という業務

があっという間に片付いたのである。

当時、ほぼこの作業のためだけに休日職場に出て行って、「昼までに終わるかなあ……」と思っていた私は驚きましたね。

エディケア、すごい…

と。

これがまさに、私とVBAとの出会いであった。

そして、一発でハマったのであった。

せっかくなので書き換える

それにしても、である。

世話になっておいてアレだが、リスト1のクソっぷりは何だ?!

今ならこう書く、というのを記念に残しておこう。

スト2 シートモジュール

※「個人票」シートのモジュールです。

Option Explicit

Private Property Get StartNumber() As Long
  Dim ret As Variant
  ret = Me.Range("J3").Value
  If Not IsNumeric(ret) Then ret = 0
  If ret > 2 ^ 31 - 1 Then ret = 0
  StartNumber = ret
End Property

Private Property Get EndNumber() As Long
  Dim ret As Variant
  Dim rng As Range
  Set rng = Me.Range("J4")
  ret = rng.Value
  If Not IsNumeric(ret) Then ret = 0
  If ret > 2 ^ 31 - 1 Then ret = 0
  If ret < StartNumber Then _
    ret = StartNumber: rng.Value = ret
  EndNumber = ret
End Property

Private Property Get NumberCell() As Range
  Set NumberCell = Me.Range("A4")
End Property

Private Sub insertionPrint()
  Dim startNum As Long
  startNum = StartNumber
  If startNum = 0 Then Exit Sub
  Dim endNum As Long
  endNum = EndNumber
  If endNum = 0 Then Exit Sub
  Dim n As Long
  n = startNum
  With Me
    NumberCell.Value = n
    Do
      Call .PrintOut
      If n = endNum Then Exit Do
      n = n + 1
      NumberCell.Value = n
    Loop
  End With
End Sub

シートモジュールにプロパティとメソッドを生やす形にした。

元のコードよりもずいぶん記述が増えたが、この方が良いと思う。

元のコードのイマイチなところ

リスト1を再掲する。

リスト1 再掲
Sub 個人票印刷()
Range("個人番号") = Range("自")    '……(1)'
Do While Range("個人番号") <= Range("至")    '……(2)'
    Sheets("個人票").PrintOut
    Range("個人番号") = Range("個人番号") + 1    '……(3)'
Loop
イマイチその1

(1)の

Range("個人番号") = Range("自")

は何だ!?

ハダカのRangeとか、めちゃくちゃ気持ち悪い!

.Valueの省略も気持ち悪い!

イマイチその2

(2)の

Do While Range("個人番号") <= Range("至")

は何だ!?

.Valueの省略が気持ち悪いのはともかく、Range("個人番号")の値が不適切だったら処理をしない、と言うのなら、そもそも入り口でハネておくべきで、ループの継続条件と一緒くたにするべきではない。

多少冗長になっても、一つのステートメント(でいいのか?)には一つの役割、というようにすべきだ。

イマイチその3

(3)の

Range("個人番号") = Range("個人番号") + 1

は何だ!?

もはや.Valueの省略については何も言うまい。しかし、1ループごとにRange("個人番号")を評価して代入、というのは気持ち悪いぞ。

イマイチその4

そもそも、インデントの仕方が気持ち悪い。

以上、異論は認める。

実行

ちなみに、上記のマクロは、リスト1、リスト2ともに、

f:id:akashi_keirin:20190929181519g:plain

このように動作する。

もちろん、実際にプリントアウトしても仕方がないので、リスト1、リスト2ともに、PrintOutメソッドのところをPrintPreviewメソッドに置き換えてあります。

おわりに

他人の書いたマクロでも、自分の書いたマクロでも、かつてお世話になったものを見返すと、なかなか感慨深いものです。