関数に汎用性を持たせる、共通に使える関数作り

[VBA系メニューへ] [質問掲示板] [バックナンバー目次]
どうも、三流プログラマーのKen3です。

前回は、プログラムは水の流れのように、、、なんて説明してました。
今回は、関数を分割して汎用性を持たせる案を説明します。
*たいしたことじゃないのですが、、、

今回作成したテストプログラム
http://www.ken3.org/p/lzh/off004.lzh
に
Book-004.xlsが保存されてます。
ダウンロードして、動きをチェックして見てください。

/* * 1.汎用性? */

プログラムが組めるようになってくると、修正のしやすさや(労力をかけたくない)、 流用の効くプログラムの書き方、、、などで差がでてきます。 私もあまり将来流用可能なプログラムを組んでないので、 偉そうなこと言えないんだけど(笑) 前回、フォルダー名を貰い、そのファイル名をセルにセットする。 なんて処理を作りましたよね。 '引数(パラメータ)でフォルダー名をもらい、 'データをA列にセットする
Sub setFILELIST(strFolder As String)

    Workbooks.Add   '新しいブックを追加

    Dim strFileName As String  'ファイル名
    Dim nYLine      As Integer '行カウンタ

    '最初のファイル名を取る
    strFileName = Dir(strFolder & "\*.*", vbNormal)
    
    'ファイルが見つからなくなるまでループしてデータをセットする
    nYLine = 1
    Do While strFileName <> ""   ' ループを開始します。
        Cells(nYLine, 1) = strFileName 'セルにファイル名をセットする
        Cells(nYLine, 2) = strFolder & "\" & strFileName
        nYLine = nYLine + 1      ' カウントアップする
        strFileName = Dir        ' 次のファイル名を返します。
    Loop

End Sub
ざっと見ると、できてるんだけど、変更が来た時、流用が効きにくいです。 えっ、どこが? まぁまぁ、これから書くので、あせらないで。

/* * 2.1つの考え方、固定処理をパラメーターにする */

フォルダーからファイル名を取得して、データをセットしてました。 *.jpg や *.xls とファイルの指定をして取出したくなったら? 1つの考え方は、 '最初のファイル名を取る strFileName = Dir(strFolder & "\*.*", vbNormal) この部分を、"\*.*""\*.xls"と指定ファイルに変える方法があります が、 そんなことやってたら、*.bmpがほしい、*.htmlが、、、 と 種類別に関数が増えてしまいます。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ そんな時は、フォルダーと一緒にファイルパターンもパラメーターで 貰うようにします。 Call setFILELIST(strFolder, "*.*") 'データのセット ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ とファイル名とパターンで関数を呼ぶようにします。 ※関係ない話だけど、\*.*←が顔文字に見えたアナタ、重症だよ って書くってことは、Ken3がそんな風に感じたんだよね  ギクっ、、バレたか・・・ '引数(パラメータ)でフォルダー名とファイルの種類をもらい、 'データをA列にセットする
Sub setFILELIST(strFolder As String, strPattern As String)

    Workbooks.Add   '新しいブックを追加

    Dim strFileName As String  'ファイル名
    Dim nYLine      As Integer '行カウンタ

    '最初のファイル名を取る
    strFileName = Dir(strFolder & "\" & strPattern, vbNormal)
    
    'ファイルが見つからなくなるまでループしてデータをセットする
    nYLine = 1
    Do While strFileName <> ""   ' ループを開始します。
        Cells(nYLine, 1) = strFileName 'セルにファイル名をセットする
        Cells(nYLine, 2) = strFolder & "\" & strFileName
        nYLine = nYLine + 1      ' カウントアップする
        strFileName = Dir        ' 次のファイル名を返します。
    Loop

End Sub
たんに、 setFILELIST(strFolder As String, strPattern As String) と関数の受け取りのパラメータが増えて、 strFileName = Dir(strFolder & "\" & strPattern, vbNormal) で、指定してるだけなんですね。

/* * 3.関数の機能を少なくしてシンプルにする */

もう一つのアプローチ方法として、 関数の機能を少なくしてシンプルにして 汎用性を持たせる方法があります。 ^^^^^^ なんか回りくどく説明してますが、 余計な機能がついていないほうが、 組み合わせで使える幅が増えます。 '引数(パラメータ)でフォルダー名とファイルの種類をもらい、 'データをA列にセットする setFILELIST(strFolder As String, strPattern As String) この関数、 ・フォルダー内をパターンで検索して、 ・ファイル名を新規のブックに保存します。 と、検索とデータセット、2つの機能が入ったお得な関数です。 どこが得なんだよ、、 オレは、ファイル名だけほしいのに、、、なんて時ありますよね。 ※セットじゃなくて、単品がほしいんだよ、単品が。 新規ブックに保存する処理がジャマなんですねとても。 その通り、携帯は通話だけできれば十分、えっ写メールは必要だって? まぁ、1つで何でもできるのもいいけど、 プログラムの場合、組み合わせの時邪魔になるときがあります。 あまり分割し過ぎも、バラバラで組み合わせや管理が大変なのですが、 よく使う共通関数は、1関数、1機能、なんてシンプルに作ってみると、 利用し易いです。※最低限を作成して、足りないところに外側から肉付けする。 試しに 配列にファイル名をセットする関数を作ってみます。 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ '引数(パラメータ)でフォルダー名とファイルの種類をもらい、 'データを受け取った配列にセットする
Sub setFILELIST(strFNBOX() As String, _
                strFolder As String, strPattern As String)

    Dim strFileName As String  'ファイル名
    Dim n As Integer           '配列の要素数

    n = 1              '初期化
    ReDim strFNBOX(n)  '配列の数を動的に変える

    '最初のファイル名を取る
    strFNBOX(n) = Dir(strFolder & "\" & strPattern, vbNormal)

    'ファイルが見つからなくなるまでループしてデータをセットする
    Do While strFNBOX(n) <> "" ' ループを開始します。
        n = n + 1              ' カウントアップする
        ReDim Preserve strFNBOX(n) ' 配列の数を動的に変える
        strFNBOX(n) = Dir      ' 次のファイル名を返します。
    Loop

End Sub
見なれない書き方ですが、まず配列を受け取ってます。 Sub setFILELIST(strFNBOX() As String, _ strFolder As String, strPattern As String) strFNBOX()と数を指定しない受け取り方です *ファイル名がいくつになるか不明なので。 次のポイントが ReDim strFNBOX(n) ReDim Preserve strFNBOX(n) ' 配列の数を動的に変える です、これは、普通はDim A(10)など配列の数を指定するのですが、 動的に好きな数に配列のサイズを取ります。 Preserveのキーワードは、前のデータを残してサイズを拡張する、 ^^^^^^^^ 今回のような処理の時に使います。 ※サイズを増やしながらデータを追加していくイメージなので、  サイズ変更前のデータを残しながら処理してます。 Do While strFNBOX(n) <> "" ' ループを開始します。 n = n + 1 ' カウントアップする ReDim Preserve strFNBOX(n) ' 配列の数を動的に変える strFNBOX(n) = Dir ' 次のファイル名を返します。 Loop と、配列を拡張しながらファイル名をセットします。 分割した表示部は、 'フォルダー名とファイル名配列を受け取り、シートを新規作成
Sub make_data(strFolder As String, strFN() As String)

    Dim nYLine      As Integer '行カウンタ
    
    Workbooks.Add   '新しいブックを追加

    For nYLine = 1 To UBound(strFN)  'ファイル名をセットする
        Cells(nYLine, 1) = strFolder & "\" & strFN(nYLine)
    Next nYLine

End Sub
と、フォルダー名、ファイル名の配列を受けとって、 新規ブックにファイル名を書き込んでます。 ここで、おっ?と思うのは、 For nYLine = 1 To UBound(strFN) 'ファイル名をセットする Cells(nYLine, 1) = strFolder & "\" & strFN(nYLine) Next nYLine の部分の、UBound(strFN)です。 UBoundに配列を渡すと、インデックス番号の最大値を返してくれるので、 これを利用してループを作ってます。 よく、文字列分割の関数 Split関数と組み合わせてUBound関数を使ったりしてます http://www.ken3.org/cgi-bin/test/test024-2.asp ポイントは、実行時に配列の要素数が変化しているので、 その最大値をもらって、処理してます。 メインルーチンは、
Sub Main()

    Dim strFolder As String '選択されたフォルダーを格納
    Dim strBOX()  As String 'ファイル名格納用変数

    'フォルダーを選択させる
    strFolder = getFOLDER()  'フォルダーの選択関数を呼ぶ

    'キャンセルだったら処理を抜ける
    If strFolder = "キャンセル" Then
       Exit Sub
    End If

    '選択されたフォルダーを表示関数に渡し表示する
    Call setFILELIST(strBOX(), strFolder, "*.*") 'データのセット
    
    '新規のシートにデータをセットする
    Call make_data(strFolder, strBOX())

End Sub
と修正しました。 ポイントは、 Dim strBOX() As String 'ファイル名格納用変数 配列のサイズを指定しない定義方法、 と Call setFILELIST(strBOX(), strFolder, "*.*") 'データのセット Call make_data(strFolder, strBOX()) の関数の呼び方です。 配列変数に一度ファイル名を全て保存します で、その配列からシートにデータをセットしてます。 一回配列に保管するのがムダな場合もあるが、 機能が分かれていると、 Call setFILELIST(strBOX(), strFolder, "*.CSV") 'データのセット でCSVのファイル名を取得、 For n = 1 To UBound(strFN) 'ファイルをインポート strIN = strFolder & "\" & strFN(nYLine) strINを使用してインポート Next nYLine なんて少し変更した処理も比較的簡単に作成することができます。 シンプルな汎用性のある共通関数作りにもチャレンジしてみてください。

/* * 4.終わりの挨拶 */

機能を分割すると、汎用性のあるプログラムが書けることが、 なんとなくわかったと思います。 Dim FN() As String Call setFILELIST(FN(), strFolder, "*.jpg") 'データのセット で、ファイルリストが取りたい時などに使える関数になりました。 (*標準関数に少し肉付しただけなんですが(笑)) 今回作成したテストプログラム http://www.ken3.org/p/lzh/off004.lzh に Book-004.xlsが保存されてます。 ダウンロードして、動きをチェックして見てください。 何かの参考となれば幸いです。 プログラム作りは簡単で面白いなぁと感じるような 解説/メールマガジンを書きたいと思ってます。 よろしくお願いします。 AB型の変わり者、三流プログラマーのKen3でした。

シートに設定値を書き、参照する方法

>要望002 : URLの初期値を自由に設定したい
>
>内容
>現在、Googleが初期値でセットされているが、
>シートに設定値を書き、参照するなどして、
>自由にテスト用の初期ページを設定したい。

セルのB6に書かれた値を初期値として利用します。

フォームの初期処理のイベント
 UserForm_Initialize で
 Range("B6") の値を代入後、
 .Navigate で ページに飛ばしただけですが。。

Private Sub UserForm_Initialize()
    Me.txtURL.Text = Range("B6") 'URL初期値
    Me.WebBrowser1.Navigate Me.txtURL.Text
End Sub
こんな感じで セルの値を初期値として使うと、 プログラムの変更無く、いろいろな動作ができます。 ※設計段階、初めから考えとけって?  う〜ん、ここらへんが、設計者のセンスの有無って感じかなぁ・・・  もちろん、私は、設計力の無い 三流プログラマーです。 他の処理でも、セルに初期値やパラメーターを書き込み、 モジュールから参照すると意外と便利ですよ。
不評の動画解説:http://www.youtube.com/watch?v=WfGRHN6qzAY

三流君のHP主な飛び先

VBA系のメルマガで書いた解説を項目ごとにまとめてます

[VBAでAccessを操作(一般)]
[VBAでAccessのレポートを操作]
[VBAでAccessのUserForm/サブフォームを操作]
[VBA Access から Excel 連携]

[VBA でExcel オブジェクト/プロパティ/メソッド/一般]
[VBA でExcel UserForm(ユーザーフォーム)を操作する]
[VBA ExcelからAccessを操作する]

[VBA Outlookの操作]
[VBA IEの操作]
[VBA テキストファイル(*.txt,*.html,*.csv)の操作]
[VBA標準関数関係とその他解説]

ASP系の解説を項目ごとにまとめてみました

[ASP Form等を使用したデータのやり取り]
[ASP その他処理サンプル]
[ASP テキストファイル処理]
[ASP VBScript関数関係の説明]
[ASP ADOでMdbファイルを使う]
[ASP ADOでExcelと接続してみた]