適材適所

システム屋のくらげが気ままに書いているブログです。PowerShellやVBAなどプログラミング系の話をメインに書いています。

MENU

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

はじめに

f:id:shinmai_papa:20210925224204p:plain クラスモジュール、気になって調べてみたことありませんか?

名前は聞いたことがあるけれど、なんだかよくわからないクラスモジュール。初心者の頃は、「とりあえずコードは標準モジュールに書くものだ」と、そう機械的に理解されていた方も多いのでは?

ある程度VBAに親しんでくると、興味が沸いてくるクラスモジュール。しかしネットで調べてみたけど、よくわからない。そんな経験はありませんか?

わからないなりにマスターしようと勉強してみたけど、だめっだった。そんな人に向けて、クラスモジュールの入門編をハンズオン形式で書いていこうというこのシリーズ。全部で10回の長編シリーズです。

対象 * 過去にクラスモジュールを学ぼうとしたが挫折した人

  • VBAについて、ある程度分かるがクラスモジュールはよく分からんという人

  • クラスモジュール!?何それ?おいしいの?という人

現場で使えるようなものを作っていきます

クラスモジュールは、話が抽象的になりがちです。そのため、文法はわかったけど結局どのように実務で使えるのかがわからない、という状況になっている人が多いような気がします。

そのため、このシリーズでは、具体例から使用方法をイメージできるよう1つのクラスモジュールを作り上げることを目的としてます。

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

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

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

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

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

どうやって使えるプログラムに落とし込むのか。知識と現実の橋渡し。それをすることがこのシリーズの最大の目的です。

題材は「ネ申エクセル」

このシリーズで例として取り上げるのは、2016年頃にExcel界隈を騒がせた、役所の「ネ申エクセル」です。知らない人はググってみてください。

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

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

f:id:shinmai_papa:20190711144335p:plain

入力項目が一文字ずつになっておりますね。これでは、このシートに文字を入力するのも、VBAで処理をするのも大変です。

このシリーズでは、これを題材に、クラスモジュールやオブジェクトを紐解いていきたいと思います。

なぜネ申エクセル?

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

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

考えてみてください。形式が整ってない、ワークシートを集計する大変さを・・・。

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

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

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

シートの情報とは、今回の例でいうと、「(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