適材適所

パソコン作業の自動化・効率化のための情報を発信するブログ(VBA,PowerShellなど)

挫折した人のためのVBAクラスモジュール入門_その1

はじめに

VBAで一通りのことができるようになると、だんだんと色々なことに手を出したくなってくるのが人間の性。

名前は聞いたことがあるけれど、なんだかよくわからないクラスモジュール。ネットで調べてみたけど、よくわからない。

マスターしようと勉強してみたけど、だめっだった。そんな人に向けて、クラスモジュールの入門編をハンズオン形式で書いていきたいと思います。

対象 * 過去にクラスモジュールを学ぼうとしたが挫折した人 * VBAについて、ある程度分かるが、クラスモジュールはよく分からんという人

実務に落とし込めるように

具体例から使用方法がイメージできた方が応用が利くかと思います。

特に

オブジェクトってなんだよ、色々ネットの情報見たけど、どうやって実務に応用するんだよ!!

って思ったことがある人も多いのではょうか。

そういう人に向けて、役に立つような視点で書いてみたいと思います。

クラスモジュールについて学び始めた当初の私も
「クラスモジュールか・・・ふむふむ、クラスにはプロパティとメソッドがあるんだな。

なになにPersonクラスか・・・。名前と性別というプロパティがあるのか・・・、なんとかというメソッドがあるのか・・・。

わかった、プロパティとメソッドあるんだな!!

で、何ができるんだ、これ?」 といった具合でした。

書いてあることは理解できるのですが、それがプログラムを作る上で何の役に立つのかが理解できなかったのです。

どうやって使えるプログラムに落とし込むのか。知識と現実の橋渡し。それができなかった。

今回この入門編を書こうと思ったのは、その橋渡しをしたいと思ったからです。そのため実際に作りながら学べるよう、一つのクラスモジュールを完成させていくスタイルで進めていきたいと思います。

題材は「ネ申エクセル」

今回、例としてとりあげるのは、2016年頃にExcel界隈を騒がせた、役所のネ申エクセルです。知らない人はググってみてください。

ユーザーの入力欄が一文字ずつ区切られており、データベース化がとても困難だということで、神エクセルや紙エクセル(紙に出すことしか考えてない)などと揶揄され、色々と批判の的にされた、あれです。

それを参考に作ったものを今回の題材とします。

f:id:shinmai_papa:20190711144335p:plain

こんな感じ。入力項目が一文字ずつになっておりますね。これは入力するのも、VBAでデータを取得するのも面倒ですね。

今回、これを例にして、クラスモジュールやオブジェクトについて説明していきたいと思います。

ネ申エクセル⇒「実際に遭遇する可能性がある」

なぜこれを取り上げるかというと、このように構造化されていないエクセルは実務で遭遇する可能性がある一つの好例だからです。

みんながみんな、プログラムでデータを処理することを考えてエクセルを作るわけではありません。見栄えがよければいい、という考えで作られたエクセルが沢山あるはずです。

そして、それをプログラムで集計しようとすると大変なわけです。でもそういったシチュエーションはあるはずです。多分。ここまでの例は中々ないかも・・・。

では、このブックから情報を取得して、データベース化するにはどうしたらいいでしょうか?

シートの情報をオブジェクト化する

クラスモジュールの使い方の一つに、シートの情報をオブジェクト化する、というものがあります。

シートの情報とは、今回の例でいうと、「(1)フリガナ(カタカナ)」や「2 生年月日」といった項目の情報になります。

オブジェクトとは、構造化された「もの」です。オブジェクト化とは「もの化」です。構造化とは、意味のある形と言い換えてもいいかもしれません。「意味のある形のもの」。ちょっと話がややこしくなってきました。

ここで視点を変えてみましょう。クラスモジュールを知らない人がこのシートの情報を取得しようとするとどんなコードになるでしょうか。例えばこんなコードになるかもしれません。

Option Explicit

Const NAME_FURI_RNG As String = "B6:U6"
Const NAME_KAN_RNG As String = "B8:U8"
Const BIRTH_Y_RNG As String = "B12:E12"
Const BIRTH_M_RNG As String = "F12:G12"
Const BIRTH_D_RNG As String = "H12:I12"
Const POST1_RNG As String = "B16:D16"
Const POST2_RNG As String = "F16:I16"
Const ADR_RNG As String = "B18:U19"
Const MAIL_RNG As String = "B22:U23"
Const WORK_PLACE_RNG As String = "B26:N26"
Const PROFFESION_RNG As String = "P26:U26"

Sub example1()
   Debug.Print getItem(Range(NAME_FURI_RNG))
   Debug.Print getItem(Range(NAME_KAN_RNG))
   Debug.Print getItem(Range(BIRTH_Y_RNG))
   Debug.Print getItem(Range(BIRTH_M_RNG))
   Debug.Print getItem(Range(BIRTH_D_RNG))
   Debug.Print getItem(Range(POST1_RNG))
   Debug.Print getItem(Range(POST2_RNG))
   Debug.Print getItem(Range(ADR_RNG))
   Debug.Print getItem(Range(MAIL_RNG))
   Debug.Print getItem(Range(WORK_PLACE_RNG))
   Debug.Print getItem(Range(PROFFESION_RNG))
End Sub

Function getItem(aRng As Range) As String
    Dim recString As String
    Dim i As Long
    For i = 1 To aRng.Count
        Dim r As Range: Set r = aRng.Item(i)
        recString = recString & r.Value
    Next i
    getItem = recString
End Function

単純にデータを取得するだけなら、これでも十分かと思います。

では、これに加えて例えば住所は都道府県名を別にして集計したいから別項目として取得したいという要望や生年月日は西暦と和暦どちらも取得したいなどの要求が出てきたらどうしましょう?

メインコードに色々な処理が追加され、たちまちスパゲッティ(ぐちゃぐちゃ)なコードになってしまうこと請け合いです。

このコードはシートの値を書き出しているだけ

なぜぐちゃぐちゃになるか。それは、このコードはシートの情報をオブジェクト化しているわけではないからです。オブジェクト化していないというのは意味のある構造にしていないという意味です。

このコードは、ただシートの値を書き出しているに過ぎないのです。値だけを書き出しているので、その文字列を変更してほしいといわれたときにメインコード上で編集作業をするか、またはサブルーチンに別出しするかです。それはつまり全ての責任がプログラマーにある状態です。

ではどうやって意味のある形にするか。それがここでいう「シートの情報をオブジェクト化する」ということです。シートの情報をオブジェクト化することでシートの情報を構造化し、情報へのアクセスを容易にするのです。

ここまでで説明が長くなってしまったので、ここで一旦終わりにしたいと思います。

次ももう少しうんちくを話していくのでお付き合いをいただければ。

www.tekizai.net