<

Range("A2").CurrentRegion
「Ctrl + Shift + :」 にショートカット

-------------------------------------
 2020-08-04
セル範囲(Range)を取得する方法10選
Range・Cells 入門・まとめ 読みやすいコードの書き方 VBA
この表のオレンジの部分を取得しましょう。


取得したいRangeの範囲

VBAをやっていて、この処理をしたことが無い人はいないのでは?
ってくらいよくある処理ですよね。


単純に書こうとすれば、初心者でもすぐ書けるような方法がいくらでもあるので、
普段はあまり考えない部分かもしれません。


ですがこの処理の書き方はいろいろなやり方があり、
コードの読みやすさの、1つのポイントになる部分です。


読みやすさ、メンテのしやすさ、バグの書きづらさなど、
追求しようと思えば、とても考えがいのある処理です。

自分の知識の確認の意味でも、ちょっと考察してみましょう。
 

Range("セルアドレス")で指定する
Range("○○")を変数で指定できるようにする
Range(Cells(左上), Cells(右下))で指定する
ちょっと寄り道:Enum定数で列番号を定義
Resize(データ数)で取得する
Offsetで取得する
表全体の範囲から、列部分を切り取って取得する
Columnsで取得する
Intersectメソッドで取得する
表全体を簡単に取得するプロパティ
CurrentRegionプロパティ
ワークシート.AutoFilter.Range
見出しを除外する方法
完成形
おまけ:学んだコードは関数化してとっておく
おまけ:1つ忘れていたメソッドを付け足し
 

Range("セルアドレス")で指定する
Range("E3:E7")
まずどストレートにこれ。基本中の基本ですね。


「初心者向け」と見せかけて、単純な読みやすさでは一番なので、
「完全に固定の範囲」であれば、上級者になっても普通に使うと思います。


Range(○○)はいろんな書き方ができますね。


やる人はいないと思いますが、

Range("E3,E4,E5,E6,E7")
でもいけます。


意外と知らない方もいるかもしれませんが、

Range("E3","E7")
でも同じエリアを取得できますし、

Range("E3:E4","E6:E7")
と、範囲から範囲まででも行けたりします。


まあこの辺は遊びというか、実際にこれらの指定方法で何かマクロを組んだことはほとんどないですね(笑)


一応たまに使うものとしては、「A1セルからこの表までの全体」を取得したいときに、
Range(セル範囲, セル範囲)パターンが使えます。
 

Range("A1", "A2:E7")
これでA1:E7を取得することができ、
ここを印刷範囲にしたり、.Rows.Countで最終行を取得したりできますね。

Range("○○")を変数で指定できるようにする
取得したいRangeの範囲

先ほど「完全に固定の範囲」であればRange("E3:E7")を使うと書きました。


ですが、今回の範囲はどう見ても「完全に固定」ではないですね。
次のくだものが売れていかないと、お店はやっていけません。


プログラミングの極意は「動的なデータにどう対応するか」ですので、
まずは一番基本となる「データがどこまで入っているか」に対応しましょう。


ここから先は、「E7」ではなく、

Dim 最終行 As Long
という変数に最終行を取得して、それを使うことにします。


最終行番号の取得コードは、長くなるので別の機会に。

With ActiveSheet
    最終行 = .Cells(.Rows.Count, 5).End(XlUp).Row
    最終行 = .UsedRange.Rows.Count + .UsedRange.Row - 1
    最終行 = .Range("A1", .Autofilter.Range).Rows.Count
End With
↑どれでも好きなものをイメージして先に進んでください。


Range("セルアドレス")で動的データに対応する場合は、

Range("E3:E" & 最終行)
こんな感じで、文字列結合を利用することができます。


ひとまずこれで、データがどんどん追加されていくことには自動対応できますね。

Range(Cells(左上), Cells(右下))で指定する
さてここからはプログラムらしくなっていきます。

Range(Cells(3, 5), Cells(7, 5))
これでE3:E7を取得することができます。

セル範囲を数値で表そうと思ったら、これが一番基本だと思います。


もちろんこんな数字ベタ打ちでは何の意味もなく、
「目的は変数・定数を使えるように」です。


変数と定数を使った例がこんな感じです↓

取得したいRangeの範囲
' モジュール上部にて
Const R1stくだもの表 = 3
Const CNoくだもの表_No = 1
Const CNoくだもの表_品物 = 2
Const CNoくだもの表_単価 = 3
Const CNoくだもの表_数量 = 4
Const CNoくだもの表_売上 = 5

' コード内にて
Dim RLastくだもの表 As Long
RLastくだもの表 = さっきイメージした最終行取得コード

' E3:E7を取得するコード
Range(Cells(R1stくだもの表, CNoくだもの表_売上) _
        , Cells(RLastくだもの表, CNoくだもの表_売上))
これで、4つの数字を全部定数・変数にできました。


最後の式に値を代入してみれば、

Range(Cells(3, 5), Cells(7, 5))
になります。


ここまでくれば、「データがどこまで入っているか」という実行時の対応だけでなく、

表の上部に余白の行を挿入したい
品物と単価の間に購入日の列を挿入したい
といった、表自体の改修時にも、定数をいじるだけで対応できるようになります。


ひとまず、「Rangeプロパティで表のデータ部分をもって来よう」というマクロを、
メンテナンス性を意識して書く場合は、これが基本の形だと思います。



まあここまでやるかどうかは、マクロの規模やデータの重要度と相談してください。


単発の業務で使う表なら、

Range("E3:E" & 最終行)
でも十分動的です。


逆にいろいろな業務で共有する重要なデータなどでは、
この「売上を意味するE」が、たくさんのマクロに登場するでしょう。

全部"E"とベタ打ちしていると、列を挿入して売り上げがF列になったときに地獄を見ますが、定数化している場合は

Const CNoくだもの表_売上 = 5
この5を6に変えるだけでマクロの改修が完了します。

この辺を吟味して、どこまで丁寧にデータを定数化するかを決めてください。

ちょっと寄り道:Enum定数で列番号を定義
先ほどの定数で、列番号を定義していた

Const CNoくだもの表_No = 1
Const CNoくだもの表_品物 = 2
Const CNoくだもの表_単価 = 3
Const CNoくだもの表_数量 = 4
Const CNoくだもの表_売上 = 5
この部分は、列挙型定数Enumを用いて、

Enum CNoくだもの表
    No = 1
    品物   ' ここから↓が2,3,4…と連番で定義されるしくみ
    単価
    数量
    売上
End Enum
こう書き換えることができます。


その場合のRangeの指定はこんな感じ。

Range(Cells(R1stくだもの表, CNoくだもの表.売上) _
        , Cells(RLastくだもの表, CNoくだもの表.売上))
_ が . に変わっただけですね。


入力は、

Enumの選択肢

と、本体の名前「CNoくだもの表」の後は選択肢から選べるので、サクサク入力できます。

 
列挙型Enumは、単にLong型の定数をまとめて持っておく機能ですが、
「番号を省略した場合は連番」という仕様が、列番号の定数化に超便利です。


先ほど例に挙げた「品物と単価の間に購入日の列を挿入」する場合、

Enum CNoくだもの表
    No = 1
    品物
    購入日   ' これを書き加えると、
    単価      ' ここから↓が1ずつ足される神仕様
    数量
    売上      ' さっきの例の通り、5が6になっている
End Enum
これで済むという、ある意味列番号を定義するために生まれてきたやつです。

Enumを初めて知った方は、この機会に覚えてしまいましょう。

Resize(データ数)で取得する
取得したいRangeの範囲

さて、定数化がようやく終わりましたので、
やっとこさ本題のRange取得プロパティを紹介できますね。


ここからはサクサク行きましょう。
まずはResizeプロパティから。

Resize(行数,列数)でセル範囲を拡張できます。
それを活用して、E3:E7を取得するにはこう書きます↓

' データの数を計算しておく
Dim データ数 As Long
データ数 = RLastくだもの表 - R1stくだもの表 + 1

' E3:E7はこれ
Range("E3").Resize(データ数, 1)

' 列数は変えないので省略も可能
Range("E3").Resize(データ数)

' 定数を使うならこう
Cells(R1stくだもの表, CNoくだもの表.売上).Resize(データ数) 
「一番目のセルからデータの数だけ下へ伸ばした範囲」という書き方が、
直感的にとてもわかりやすいため、素晴らしく読みやすいコードになります。


しかも一度取得した「データ数」は使いまわせるため、

みかんの売上合計 = WorksheetFunction.Sumif _ 
    (Range("B3").Resize(データ数), "みかん", Range("E3").Resize(データ数))
のように、SUMIF(B列,みかん,E列)がこんなに読みやすく書けます。


Resizeを使いこなせると、Rangeの扱いにかなり幅が出ますので、
是非習得していってください。


例えば今回の表全体であるA3:E8なんかも、

Range("A3").Resize(データ数, 表の列数)
で取得することができます。

Offsetで取得する
Resizeの次は、親戚のOffsetを紹介します。


Rangeオブジェクト.Offset(行数, 列数)で、
Rangeオブジェクトを「同じ大きさのまま指定の数分ズラす」ことができます。

' D列の表エリアを右にひとつズラしてE3:E8を取得する
Range("D3:D7").Offset(0, 1)
 
この例のように、大きさが変わらないというのがOffsetのいいところで、
例えばさっきのSUMIFを例にとると、

Set 売上列 = Range("E3").Resize(データ数)

みかんの合計 = WorksheetFunction.Sumif(売上列.Offset(0, -3), "みかん", 売上列)
こんな書き方をすることができます。

読みやすくはないですが、書くのはかなり速そうですね。


定数が使えていないことからもわかる通り、
Offsetは書きやすいけど読みにくいプロパティです。


Resizeと組み合わせると、変幻自在にRangeを扱えるようになりますが、
その自在っぷりに未来の自分が惑わされる可能性があります。

ご利用は計画的に。

表全体の範囲から、列部分を切り取って取得する
取得したいRangeの範囲

今まで挙げた例は、E3からE7までをくっつけたり、動かしたりといった、
いわば「積み木」のような取得方法でした。


これとは異なるアプローチのセル範囲の取得方法として、
「表全体という長方形の板から、E列部分を切り取る」
という、のこぎり的な方法もありますのでご紹介します。

Columnsで取得する
表全体を表すRange("A3:E7")を使うと、こんな感じに書くことができます。

Range("A3:E7").Columns("E")
Range("A3:E7").Columns(CNoくだもの表.品物)
 
Columnsプロパティは、よくある「Worksheet」を親にすると列全体を指します。
省略時はActiveSheetの列全体を取ってきますよね。

このColumnsプロパティですが、実はRangeオブジェクトを親にすることもでき、
「セル範囲が入っているRangeオブジェクト.Columns(列番号)」とすると、
「そのセル範囲の第○列目」を取ってくることができます。


書いたコードの見た目も、「くだもの表の品物列」って感じで、とてもいいですね。


ただしこの方法、データがA列から始まっていると、
かなり読みやすくていい方法なんですが、

Columnsの罠

この表のように、B列以降から表が始まる場合は注意が必要です。


この場合、

Range("B3:E7").Columns("E")
これはシート上で言うところのF列を指してしまいます。

B列からみたE列のようなイメージになっちゃうため、
A列始まりでない表では、その分ズレちゃうんですね。


ということで、Columnsの性質を覚えつつ、本命は↓へ。

Intersectメソッドで取得する
Intersectメソッドは、引数に渡すセル範囲が「重なっている部分」を返します。

今回の場合は、「表全体の長方形」と「E列全体」の重なる部分を取ると、
画像のように売上列のブロックを取得することができます。


Intersectの例

こんな感じで範囲を取得します。「交差部分」と呼んだりしますね。


これなら表エリアの開始列がA列かどうかに関わらず、
「第5列」なら5で行けますので、定数との相性も良いです↓

Intersect(Range("B3:E7"), Columns(CNoくだもの表.売上))
 

私はEnumを愛しているので、Enumと相性のよいこれが一番好きです。

表全体を簡単に取得するプロパティ
さて、わざわざこれらの「のこぎり」を便利と紹介したのは、
元の板となるRange("A2:E7")を、簡単に取得するいいプロパティがあるからです。


まずは以下の2つを覚えておきましょう。

CurrentRegionプロパティ
あるセルを含む、表っぽい部分を自動取得してくれます。

CurrentRegionのサンプル

この機能は「アクティブセル領域」と呼び、
「Ctrl + Shift + :」 にショートカットがセットされていますので、
試しにやってみてください。


空の行だったり、表が複数隣接していない限りは、
手っ取り早く表のセル範囲を取得できる優秀なプロパティです。


今回の例では、

Range("A2").CurrentRegion
でRange("A2:E7")を取得できます。


というのは嘘で、Range("A1:E7")を取得しやがります。

アホの子Region

大変便利なCurrentRegionさんですが、
今回のように、「表のタイトル」などをよくアホの子しますので、
ご利用は計画的に。

ワークシート.AutoFilter.Range
ワークシート.AutoFilter.Rangeで、オートフィルターのかかっているエリア全体を取得できます。


親のオブジェクトが「ワークシート」なので、
どこか起点となるセルを探さなくてもいいのがメリット。
 

Worksheets("くだもの売上表").AutoFilter.Range
これで"A2:E7"を取得できます。

セル番地が一つも出て来ないコードにできますね。


ユーザー側で設置しちゃえるので、Excelがアホの子しないのもメリットです。
(ユーザーがアホの子する危険がありますが)




-------------------------------------
For i = 0 To max学部番号
    For j = 0 To max学科番号
        For k = 0 To max専攻番号

        Debug.Print CStr(i) & "-" & CStr(j) & "-" & CStr(k), PUB_ary学部等一覧(i, j, k).学部番号, _
        PUB_ary学部等一覧(i, j, k).学部CODE, _
        PUB_ary学部等一覧(i, j, k).学部名, _
        PUB_ary学部等一覧(i, j, k).学科番号, _
        PUB_ary学部等一覧(i, j, k).学科CODE, _
        PUB_ary学部等一覧(i, j, k).学科名, _
        PUB_ary学部等一覧(i, j, k).専攻番号, _
        PUB_ary学部等一覧(i, j, k).専攻CODE, _
        PUB_ary学部等一覧(i, j, k).専攻名, _
        PUB_ary学部等一覧(i, j, k).質問CODE
        Next k
    Next j

Next i

--------------------------学部学科専攻new

Function func学部一覧を作る()
    '戻り値は



End Function
'学部コンボボックス設定
Private Sub cmd学部セット_Click()

    'PUB_ary学部等一覧()を作る
    '戻り値はエラーメッセージか空
    ret = func学部一覧配列作成()


    'PUB_ary学部等一覧()から学部配列作成(PUB_aryコンボ())
    '戻り値はPUB_aryコンボ()
    ret = funcコンボボックス(1, "", "", "")


    ComboBox1.Clear
    'コンボボックスを3列にする
    ComboBox1.ColumnCount = 3
    '3列目を選択された値にする(C学部)
    ComboBox1.TextColumn = 3
    'それぞれの列幅を指定
    ComboBox1.ColumnWidths = "0;0;60"
    
    '項目の追加
    ComboBox1.AddItem
    ComboBox1.List(0, 0) = 0
    ComboBox1.List(0, 1) = "ALL"
    ComboBox1.List(0, 2) = "全て"


    MODE = 1
    学部CODE = 0
    学科ODE = 0

    '学部一覧を作る
    ret = func学部学科専門一覧(MODE, 学部CODE, 学科CODE)
    If ret = True Then
    
        For i = 0 To UBound(PUB_aryコンボ)
           ComboBox1.AddItem
            ComboBox1.List(i + 1, 0) = PUB_aryコンボ(i).番号
            ComboBox1.List(i + 1, 1) = PUB_aryコンボ(i).CODE
            ComboBox1.List(i + 1, 2) = PUB_aryコンボ(i).名称
        Next i
    
    End If
    ComboBox1.ListIndex = 0

End Sub
Function funcコンボボックス(MODE, 学部番号, 学科番号, 専攻番号)
Select Case MODE

Case 1
    cnt = 0: back = -1
    For i = 0 To UBound(PUB_ary学部等一覧, 1)
    For j = 0 To UBound(PUB_ary学部等一覧, 2)
    For k = 0 To UBound(PUB_ary学部等一覧, 3)
        If PUB_ary学部等一覧(i, j, k).学部番号 <> back And Not IsEmpty(PUB_ary学部等一覧(i, j, k).学部番号) Then
            ReDim PUB_aryコンボ(cnt)
            PUB_aryコンボ(cnt).番号 = PUB_ary学部等一覧(i, j, k).学部番号
            PUB_aryコンボ(cnt).CODE = PUB_ary学部等一覧(i, j, k).学部CODE
            PUB_aryコンボ(cnt).名称 = PUB_ary学部等一覧(i, j, k).学部名
        End If
    Next k
    Next j
    Next i
    

Case 2
Case 3
Case Else

End Select



End Function
Function func学部一覧配列作成()

'Public PUB_ary学部等一覧() As type専攻
Set sheet学部 = ThisWorkbook.Sheets("学部学科専攻new")
Dim hajR, owaR

Dim ary学部番号()
Dim ary学部CODE()
Dim ary学部名()
Dim ary学科番号()
Dim ary学科CODE()
Dim ary学科名()
Dim ary専攻番号()
Dim ary専攻CODE()
Dim ary専攻名()
Dim ary質問CODE()

c学部番号 = 2
c学部CODE = 3
c学部名 = 4
c学科番号 = 5
c学科CODE = 6
c学科名 = 7
c専攻番号 = 8
c専攻CODE = 9
c専攻名 = 10
c質問CODE = 11

'表の最後の行を取得
hajR = 6

r = hajR
With sheet学部
    While CStr(.Cells(r + 1, c学部番号)) & _
CStr(.Cells(r + 1, c学部CODE)) & _
CStr(.Cells(r + 1, c学部名)) & _
CStr(.Cells(r + 1, c学科番号)) & _
CStr(.Cells(r + 1, c学科CODE)) & _
CStr(.Cells(r + 1, c学科名)) & _
CStr(.Cells(r + 1, c専攻番号)) & _
CStr(.Cells(r + 1, c専攻CODE)) & _
CStr(.Cells(r + 1, c専攻名)) & _
CStr(.Cells(r + 1, c質問CODE)) > ""

    r = r + 1
Wend
owaR = r


'番号の最大値を取得
max学部番号 = -1
max学科番号 = -1
max専攻番号 = -1

For r = hajR To owaR
    i = r - hajR
    '--------------------
    dmy = .Cells(r, c学部番号)
    If dmy = "" Then
        dmy = -1
    End If
    If max学部番号 < dmy Then
        max学部番号 = dmy
    End If
    '--------------------
     dmy = .Cells(r, c学科番号)
    If dmy = "" Then
        dmy = -1
    End If
    If max学科番号 < dmy Then
        max学科番号 = dmy
    End If
    '--------------------
     dmy = .Cells(r, c専攻番号)
    If dmy = "" Then
        dmy = -1
    End If
    If max専攻番号 < dmy Then
        max専攻番号 = dmy
    End If
    '--------------------

    '一行ずつ、一項目ずつ配列に入れる
    ReDim Preserve ary学部番号(i)
    ReDim Preserve ary学部CODE(i)
    ReDim Preserve ary学部名(i)
    ReDim Preserve ary学科番号(i)
    ReDim Preserve ary学科CODE(i)
    ReDim Preserve ary学科名(i)
    ReDim Preserve ary専攻番号(i)
    ReDim Preserve ary専攻CODE(i)
    ReDim Preserve ary専攻名(i)
    ReDim Preserve ary質問CODE(i)

    ary学部番号(i) = .Cells(r, c学部番号)
    ary学部CODE(i) = .Cells(r, c学部CODE)
    ary学部名(i) = .Cells(r, c学部名)
    ary学科番号(i) = .Cells(r, c学科番号)
    ary学科CODE(i) = .Cells(r, c学科CODE)
    ary学科名(i) = .Cells(r, c学科名)
    ary専攻番号(i) = .Cells(r, c専攻番号)
    ary専攻CODE(i) = .Cells(r, c専攻CODE)
    ary専攻名(i) = .Cells(r, c専攻名)
    ary質問CODE(i) = .Cells(r, c質問CODE)
Next r

MsgBox CStr(max学部番号) & "/" & CStr(max学科番号) & "/" & CStr(max専攻番号)

'取得最大値で動的配列を設定
ReDim Preserve PUB_ary学部等一覧(max学部番号, max学科番号, max専攻番号)
For i = 0 To max学科番号



'項目ごと配列を整理する。空欄に必要な数字を入れたりする。
'一行目のみ別に処理する
'

'1行目(I=0)だけ特別
i = 0
If ary学部番号(i) = "" Or ary学部番号(i) = 0 Then
    msg = "1行目の学部番号が空白かゼロです。不正なデータですので作業を終了します。"
    GoTo func学部一覧配列作成_ERR
ElseIf ary学部CODE(i) = "" Or ary学部CODE(i) = 0 Then
    msg = "1行目の学部CODEが空白かゼロです。不正なデータですので作業を終了します。"
    GoTo func学部一覧配列作成_ERR
ElseIf ary学部名(i) = "" Or ary学部名(i) = 0 Then
    msg = "1行目の学部名が空白かゼロです。不正なデータですので作業を終了します。"
    GoTo func学部一覧配列作成_ERR
End If

If ary学科番号(i) = "" Then
    ary学科番号(i) = 0
End If

If ary専攻番号(i) = "" Then
    ary専攻番号(i) = 0
End If

For i = 1 To UBound(ary学部番号)
    
    If ary学部番号(i) = "" Then
        ary学部番号(i) = ary学部番号(i - 1)
    End If
    If ary学部CODE(i) = "" Then
        ary学部CODE(i) = ary学部CODE(i - 1)
    End If
    
    If ary学部名(i) = "" Then
        ary学部名(i) = ary学部名(i - 1)
    End If
    If ary学科番号(i) = "" Then
        If (ary学部番号(i) = ary学部番号(i - 1)) Then
            ary学科番号(i) = ary学科番号(i - 1)
        Else
            ary学科番号(i) = 0
        End If
    End If
    If ary学科CODE(i) = "" And (ary学部番号(i) = ary学部番号(i - 1)) Then
        ary学科CODE(i) = ary学科CODE(i - 1)
    End If
    If ary学科名(i) = "" And (ary学部番号(i) = ary学部番号(i - 1)) Then
        ary学科名(i) = ary学科名(i - 1)
    End If
    
    If ary専攻番号(i) = "" Then
        If (ary学科番号(i) = ary学科番号(i - 1)) Then
            ary専攻番号(i) = ary専攻番号(i - 1)
        Else
            ary専攻番号(i) = 0
        End If
    End If
    
    
Next i


For i = 0 To UBound(ary学部番号)
r = i + 6
    .Cells(r, 15) = ary学部番号(i)
    .Cells(r, 16) = ary学部CODE(i)
    .Cells(r, 17) = ary学部名(i)
    .Cells(r, 18) = ary学科番号(i)
    .Cells(r, 19) = ary学科CODE(i)
    .Cells(r, 20) = ary学科名(i)
    .Cells(r, 21) = ary専攻番号(i)
    .Cells(r, 22) = ary専攻CODE(i)
    .Cells(r, 23) = ary専攻名(i)
    .Cells(r, 24) = ary質問CODE(i)

Next i

End With
    
For i = 0 To UBound(ary学部番号)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).学部番号 = ary学部番号(i)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).学部CODE = ary学部CODE(i)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).学部名 = ary学部名(i)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).学科番号 = ary学科番号(i)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).学科CODE = ary学科CODE(i)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).学科名 = ary学科名(i)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).専攻番号 = ary専攻番号(i)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).専攻CODE = ary専攻CODE(i)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).専攻名 = ary専攻名(i)
    PUB_ary学部等一覧(ary学部番号(i), ary学科番号(i), ary専攻番号(i)).質問CODE = ary質問CODE(i)
Next i
    
func学部一覧配列作成 = ""
Exit Function

'------------------------------------------------------------------------------------------------
    
    
    
    r開始 = sheet学部.Range("学部番号").Row + 1
    r = r開始: chk = "A"
    While chk <> ""
        chk = sheet学部.Cells(r, c学部CODE) & sheet学部.Cells(r, c学科CODE) & sheet学部.Cells(r, c専攻CODE)
        r = r + 1
    Wend
    r終了 = r - 2
    
    If MODE = 1 Then
        GoSub 学部表
'        aaa = ""
'        For i = 0 To UBound(PUB_aryコンボ)
'            aaa = aaa & Str(i) & " " & PUB_aryコンボ(i).番号 & " " & PUB_aryコンボ(i).CODE & " " & PUB_aryコンボ(i).名称 & vbCrLf
'        Next i
'        MsgBox aaa
     End If
    
    If MODE = 2 Then
        GoSub 学科表
'        aaa = ""
'        For i = 0 To UBound(PUB_aryコンボ)
'            aaa = aaa & Str(i) & " " & PUB_aryコンボ(i).番号 & " " & PUB_aryコンボ(i).CODE & " " & PUB_aryコンボ(i).名称 & vbCrLf
'        Next i
'        MsgBox aaa
    End If
    
    If MODE = 3 Then
        GoSub 専攻表
'        aaa = ""
'        For i = 0 To UBound(PUB_aryコンボ)
'            aaa = aaa & Str(i) & " " & PUB_aryコンボ(i).番号 & " " & PUB_aryコンボ(i).CODE & " " & PUB_aryコンボ(i).名称 & vbCrLf
'        Next i
'        MsgBox aaa
    
    
    End If



Exit Function
'==================================================
学部表:
'==================================================
my学部CODE = ""
i = 0
For r = r開始 To r終了
    If sheet学部.Cells(r, c学部CODE) <> my学部CODE Then
        ReDim Preserve PUB_aryコンボ(i)
        PUB_aryコンボ(i).番号 = sheet学部.Cells(r, c学部番号)
        PUB_aryコンボ(i).CODE = sheet学部.Cells(r, c学部CODE)
        PUB_aryコンボ(i).名称 = sheet学部.Cells(r, c学部名)
        PUB_aryコンボ(i).質問 = sheet学部.Cells(r, c質問CODE)
        my学部CODE = PUB_aryコンボ(i).CODE
        i = i + 1
    End If
Next r
    
Return

'==================================================
学科表:
'==================================================
my学科CODE = ""
i = 0

For r = r開始 To r終了
    If sheet学部.Cells(r, c学部CODE) = from学部CODE Then '指定学部コードなら作業
        If sheet学部.Cells(r, c学科CODE) <> my学科CODE Then
   
            ReDim Preserve PUB_aryコンボ(i)
            PUB_aryコンボ(i).番号 = sheet学部.Cells(r, c学科番号)
            PUB_aryコンボ(i).CODE = sheet学部.Cells(r, c学科CODE)
            PUB_aryコンボ(i).名称 = sheet学部.Cells(r, c学科名)
            PUB_aryコンボ(i).質問 = sheet学部.Cells(r, c質問CODE)
            my学科CODE = PUB_aryコンボ(i).CODE
            i = i + 1
        End If
    End If
Next r
Return

'==================================================
専攻表:
'==================================================
i = 0

For r = r開始 To r終了
    
    If (sheet学部.Cells(r, c学部CODE) = from学部CODE) And _
         (Str(sheet学部.Cells(r, c学科CODE)) = Str(from学科CODE)) Then
   
            ReDim Preserve PUB_aryコンボ(i)
            PUB_aryコンボ(i).番号 = sheet学部.Cells(r, c専攻番号)
            PUB_aryコンボ(i).CODE = sheet学部.Cells(r, c専攻CODE)
            PUB_aryコンボ(i).名称 = sheet学部.Cells(r, c専攻名)
            PUB_aryコンボ(i).質問 = sheet学部.Cells(r, c質問CODE)
            i = i + 1
    End If
Next r
Return

Exit Function

func学部一覧配列作成_ERR:
MsgBox msg
func学部一覧配列作成 = msg
End Function









Private Sub cmd2_Click()
    'つくりゅボタン
    chk学部 = Me.CheckBox1
    chk学科 = Me.CheckBox2
    chk専攻 = Me.CheckBox3
    
    my学部CODE = Range("G21")
    my学科CODE = Range("G24")
    my専攻CODE = Range("G27")
    
    '-------------
    '学部を作る
    '-------------
    MODE = 1
    If my学部CODE = "ALL" Then
        学部CODE = ""
    Else
        学科CODE = my学部CODE   '←これで作れるように !
    End If
    
    ret = func学部学科専門一覧(MODE, 学部CODE, 学科CODE)
    For i = 0 To UBound(PUB_aryコンボ)
        ReDim Preserve Pub_ary学部(i)
        Pub_ary学部(i).学部番号 = PUB_aryコンボ(i).番号
        Pub_ary学部(i).学部CODE = PUB_aryコンボ(i).CODE
        Pub_ary学部(i).学部名 = PUB_aryコンボ(i).名称
        Pub_ary学部(i).質問CODE = PUB_aryコンボ(i).質問 '--------------------複数の時に
    Next i
    
    
    '学科を作る
    i = 0
    If my学科CODE <> "ALL" Then
        ReDim Preserve PUB_ary学科(i)
        ary学科(i) = my学科CODE
    Else    '全部
        MODE = 2
        For i = 0 To UBound(ary_学部)
             学部CODE = my学部CODE
        学科CODE = ""
        ret = func学部学科専門一覧(MODE, 学部CODE, 学科CODE)
        For i = 0 To UBound(PUB_aryコンボ)
            ReDim Preserve Pub_ary学部(i)
            Pub_ary学部(i).学部番号 = Pub_ary学部(i).学部番号
            Pub_ary学部(i).学部CODE = Pub_ary学部(i).学部CODE
            Pub_ary学部(i).学部名 = Pub_ary学部(i).学部名
            
            
            Pub_ary学部(i).学部番号 = PUB_aryコンボ(i).番号
            Pub_ary学部(i).学部CODE = PUB_aryコンボ(i).CODE
            Pub_ary学部(i).学部名 = PUB_aryコンボ(i).名称
            Pub_ary学部(i).質問CODE = PUB_aryコンボ(i).質問 '--------------------複数の時に
        Next i
    End If
    
    End If
        
            
            
                
    

End Sub

'Private Sub cmd学部セット_Click()
'
'End Sub

'学部コード変更→学科コードを変更する
Private Sub ComboBox1_Change()
    
    '選んだINDEX
    idx = Me.ComboBox1.ListIndex
    
    '選択失敗→終了
    If idx = -1 Then
        Exit Sub
    End If
        
    '選択した学部Combの値を控えておく
    Range("F21") = Me.ComboBox1.List(idx, 0)
    Range("G21") = Me.ComboBox1.List(idx, 1)
    Range("H21") = Me.ComboBox1.List(idx, 2)
    
    '学科Combのクリアと項目の追加
    
    ComboBox2.Clear
    'コンボボックスを3列にする
    ComboBox2.ColumnCount = 3
    '3列目を選択された値にする(AA学科)
    ComboBox2.TextColumn = 3
    'それぞれの列幅を指定
    ComboBox2.ColumnWidths = "0;0;60"

    '初期値
    ComboBox2.AddItem
    ComboBox2.List(0, 0) = 0
    ComboBox2.List(0, 1) = "ALL"
    ComboBox2.List(0, 2) = "全て"
    
    
    '選ばれた学部CODE
    学部CODE = Me.ComboBox1.List(idx, 1)
    
    '学部CODEがALLなら、学科CODEもALLのみで終わり
    If 学部CODE = "ALL" Then '全て
        Exit Sub
    End If
        
    '学科CODEを調べに行く
    学科ODE = 0
    MODE = 2
    If func学部学科専門一覧(MODE, 学部CODE, 学科CODE) Then  '成功
    
        '項目の追加
    
        For i = 0 To UBound(PUB_aryコンボ)
            ComboBox2.AddItem
            ComboBox2.List(i + 1, 0) = PUB_aryコンボ(i).番号
            ComboBox2.List(i + 1, 1) = PUB_aryコンボ(i).CODE
            ComboBox2.List(i + 1, 2) = PUB_aryコンボ(i).名称
        Next i

    End If

    ComboBox2.ListIndex = 0

End Sub

'学科コード変更→専攻コードを変更する
Private Sub ComboBox2_Change()
    
    '選んだINDEX
    idx = Me.ComboBox2.ListIndex
    
    '選択失敗→終了
    If idx = -1 Then
        Exit Sub
    End If

    '選択した学科Combの値を控えておく
    Range("F24") = Me.ComboBox2.List(idx, 0)
    Range("G24") = Me.ComboBox2.List(idx, 1)
    Range("H24") = Me.ComboBox2.List(idx, 2)
 
    '専攻Combのクリアと項目の追加
    ComboBox3.Clear
    'コンボボックスを3列にする
    ComboBox3.ColumnCount = 3
    '3列目を選択された値にする(AAコース)
    ComboBox3.TextColumn = 3
    'それぞれの列幅を指定
    ComboBox3.ColumnWidths = "0;0;60"
    
    '初期値
    ComboBox3.AddItem
    ComboBox3.List(0, 0) = 0
    ComboBox3.List(0, 1) = "ALL"
    ComboBox3.List(0, 2) = "全て"
    
    '選ばれた学科CODE
    学科CODE = Me.ComboBox2.List(idx, 1)
    
    '学科CODEがALLなら、専攻CODEもALLのみで終わり
    If 学科CODE = "ALL" Then '全て
        Exit Sub
    End If
    
    '専攻CODEを調べに行く
    MODE = 3
    学部CODE = Range("G21")
    学科CODE = Me.ComboBox2.List(idx, 1)
        
    If func学部学科専門一覧(MODE, 学部CODE, 学科CODE) Then
         For i = 0 To UBound(PUB_aryコンボ)
            ComboBox3.AddItem
            ComboBox3.List(i + 1, 0) = PUB_aryコンボ(i).番号
            ComboBox3.List(i + 1, 1) = PUB_aryコンボ(i).CODE
            ComboBox3.List(i + 1, 2) = PUB_aryコンボ(i).名称
        Next i
    End If
    ComboBox3.ListIndex = 0
End Sub

Private Sub ComboBox3_Change()


    '選んだINDEX
    idx = Me.ComboBox3.ListIndex
    
    '選択失敗→終了
    If idx = -1 Then
        Exit Sub
    End If
    '選択した学部Combの値を控えておく
        
    
    Range("F27") = Me.ComboBox3.List(idx, 0)
    Range("G27") = Me.ComboBox3.List(idx, 1)
    Range("H27") = Me.ComboBox3.List(idx, 2)
End Sub

Private Sub CommandButton1_Click()
Dim all部 As type専攻
maxb = 0
For r = 6 To 18
If Cells(r, 2) > maxb Then
maxb = Cells(r, 2)
End If
Next r

maxk = 0
For r = 6 To 18
If Cells(r, 5) > maxk Then
maxk = Cells(r, 5)
End If
Next r

maxs = 0
For r = 6 To 18
If Cells(r, 8) > maxs Then
maxs = Cells(r, 8)
End If
Next r

MsgBox CStr(maxb) & "/" & CStr(maxk) & "/" & CStr(maxs)



ReDim Preserve all部(maxb, maxk, maxs)

For r = 6 To 18

    



End Sub

-----------------------------------------------------------------------------------------------
Public Type type学部
    学部番号 As Variant
    学部CODE As Variant
    学部名 As Variant
    質問CODE As Variant
    
End Type




Public Type type学科
    学部番号 As Variant
    学部CODE As Variant
    学部名 As Variant
    学科番号 As Variant
    学科CODE As Variant
    学科名 As Variant
    質問CODE As Variant
End Type

Public Type type専攻
    学部番号 As Variant
    学部CODE As Variant
    学部名 As Variant
    学科番号 As Variant
    学科CODE As Variant
    学科名 As Variant
    専攻番号 As Variant
    専攻CODE As Variant
    専攻名 As Variant
    質問CODE As Variant
End Type


Public Type typeコンボ
    番号 As Variant
    CODE As Variant
    名称 As Variant
    質問 As Variant
End Type

Public Pub_ary学部() As type学部
Public PUB_ary学科() As type学科
Public PUB_ary専攻() As type専攻
Public PUB_aryコンボ() As typeコンボ

Public PUB_ary学部等一覧() As type専攻






'-----------------------------------------------------------------

Function func学部学科専門一覧(MODE, from学部CODE, from学科CODE) As Boolean

from学部CODE = Trim(from学部CODE)
from学科CODE = Trim(from学科CODE)
Set sheet学部 = ThisWorkbook.Sheets("学部学科専攻new")

'MODE 1=学部一覧, 2=学科 ,3=専攻
学部学科専門一覧 = False

    If MODE < 1 Or MODE > 3 Then
        func学部学科専門一覧 = False
        MsgBox "!"
        Exit Function
    End If

    c学部番号 = sheet学部.Range("学部番号").Column
    c学部CODE = sheet学部.Range("学部CODE").Column
    c学部名 = sheet学部.Range("学部名").Column
    
    c学科番号 = sheet学部.Range("学科番号").Column
    c学科CODE = sheet学部.Range("学科CODE").Column
    c学科名 = sheet学部.Range("学科名").Column
    
    c専攻番号 = sheet学部.Range("専攻番号").Column
    c専攻CODE = sheet学部.Range("専攻CODE").Column
    c専攻名 = sheet学部.Range("専攻名").Column
    
    c質問CODE = sheet学部.Range("質問CODE").Column
    
    sheet学部.Activate
    
    r開始 = sheet学部.Range("学部番号").Row + 1
    r = r開始: chk = "A"
    While chk <> ""
        chk = sheet学部.Cells(r, c学部CODE) & sheet学部.Cells(r, c学科CODE) & sheet学部.Cells(r, c専攻CODE)
        r = r + 1
    Wend
    r終了 = r - 2
    
    If MODE = 1 Then
        GoSub 学部表
'        aaa = ""
'        For i = 0 To UBound(PUB_aryコンボ)
'            aaa = aaa & Str(i) & " " & PUB_aryコンボ(i).番号 & " " & PUB_aryコンボ(i).CODE & " " & PUB_aryコンボ(i).名称 & vbCrLf
'        Next i
'        MsgBox aaa
     End If
    
    If MODE = 2 Then
        GoSub 学科表
'        aaa = ""
'        For i = 0 To UBound(PUB_aryコンボ)
'            aaa = aaa & Str(i) & " " & PUB_aryコンボ(i).番号 & " " & PUB_aryコンボ(i).CODE & " " & PUB_aryコンボ(i).名称 & vbCrLf
'        Next i
'        MsgBox aaa
    End If
    
    If MODE = 3 Then
        GoSub 専攻表
'        aaa = ""
'        For i = 0 To UBound(PUB_aryコンボ)
'            aaa = aaa & Str(i) & " " & PUB_aryコンボ(i).番号 & " " & PUB_aryコンボ(i).CODE & " " & PUB_aryコンボ(i).名称 & vbCrLf
'        Next i
'        MsgBox aaa
    
    
    End If


func学部学科専門一覧 = True
Exit Function
'==================================================
学部表:
'==================================================
my学部CODE = ""
i = 0
For r = r開始 To r終了
    If sheet学部.Cells(r, c学部CODE) <> my学部CODE Then
        ReDim Preserve PUB_aryコンボ(i)
        PUB_aryコンボ(i).番号 = sheet学部.Cells(r, c学部番号)
        PUB_aryコンボ(i).CODE = sheet学部.Cells(r, c学部CODE)
        PUB_aryコンボ(i).名称 = sheet学部.Cells(r, c学部名)
        PUB_aryコンボ(i).質問 = sheet学部.Cells(r, c質問CODE)
        my学部CODE = PUB_aryコンボ(i).CODE
        i = i + 1
    End If
Next r
    
Return

'==================================================
学科表:
'==================================================
my学科CODE = ""
i = 0

For r = r開始 To r終了
    If sheet学部.Cells(r, c学部CODE) = from学部CODE Then '指定学部コードなら作業
        If sheet学部.Cells(r, c学科CODE) <> my学科CODE Then
   
            ReDim Preserve PUB_aryコンボ(i)
            PUB_aryコンボ(i).番号 = sheet学部.Cells(r, c学科番号)
            PUB_aryコンボ(i).CODE = sheet学部.Cells(r, c学科CODE)
            PUB_aryコンボ(i).名称 = sheet学部.Cells(r, c学科名)
            PUB_aryコンボ(i).質問 = sheet学部.Cells(r, c質問CODE)
            my学科CODE = PUB_aryコンボ(i).CODE
            i = i + 1
        End If
    End If
Next r
Return

'==================================================
専攻表:
'==================================================
i = 0

For r = r開始 To r終了
    
    If (sheet学部.Cells(r, c学部CODE) = from学部CODE) And _
         (Str(sheet学部.Cells(r, c学科CODE)) = Str(from学科CODE)) Then
   
            ReDim Preserve PUB_aryコンボ(i)
            PUB_aryコンボ(i).番号 = sheet学部.Cells(r, c専攻番号)
            PUB_aryコンボ(i).CODE = sheet学部.Cells(r, c専攻CODE)
            PUB_aryコンボ(i).名称 = sheet学部.Cells(r, c専攻名)
            PUB_aryコンボ(i).質問 = sheet学部.Cells(r, c質問CODE)
            i = i + 1
    End If
Next r
Return


End Function