Excel VBA 別解集 分岐処理 繰り返し処理 part1

はじめに

セルにコマンドボタンを入れるやり方は、

を参照して欲しい。

問題1

問題:B2セルの点数でコマンドボタンをキックすると、D2セルに判定がでるプログラムを作成せよ

上記の問題で

1)If文でコーディングせよ

2)Select文でコーディングせよ。

解答

1)

Sub Macro1()
    If Range("B2") >= 90 Then
        Range("D2") = "優です"
    ElseIf Range("B2") >= 80 Then
        Range("D2") = "良です"
    ElseIf Range("B2") >= 70 Then
        Range("D2") = "可です"
    Else
        Range("D2") = "不可です"
    End If
End Sub

if文で記述する場合、分岐が長くなるので、if~else~end if だけではだめで、途中にelseif文をかませて記述する必要がある。

このようにif文が長くなる場合には、2)で扱うSelect文が有効である。

2)

Sub main()
    Select Case Range("B2").Value
        Case Is >= 90
            Range("D2") = "優です"
        Case Is >= 80
            Range("D2") = "良です"
        Case Is >= 70
            Range("D2") = "可です"
        Case Else
            Range("D2") = "不可です"
    End Select
End Sub

こちらの方がコードが簡潔に書ける。優劣はないにせよ、両方使えるようになって欲しい。

問題2

問題:B2セル~B8セルに入っている都県の名前をD2セル~D8セルへコピーせよ

上記の問題で

1)For文のみでコピーせよ

2)Functionプロシージャを作成してセルの最終行を取り、For文のみでコピーせよ

3)配列を用いてFor文とUBoundを用いてコピーせよ

4)配列とFor文、UBoundとDo Until~loopを用いてコピーせよ

5)配列を使い、Functionプロシージャで最終行を取り、サブルーチンで都県の名前を取り、Do while~loopでコピーせよ。

6)Functionプロシージャを作成してセルの最終行を取り、For Each文のみでコピーせよ。

7).copyを使い、Rangeのみでコピーせよ。

8)Functionプロシージャで最終行を取り、.copyを使い、cellsとRangeを使ってコピーせよ。

9)Functionプロシージャで最終行を取り、.copyを使い、一度クリップボードへコピーしてからペーストでコピーせよ。

解答

1)

Sub main7()
    Dim i As Integer
    
    For i = 2 To 8
        Cells(i, 4) = Cells(i, 2)
    Next i
End Sub

一番素直で簡潔なやり方である。本来ならこれで十分。

2)

Sub main()
    Dim i As Integer, lcr As Integer
    
    lcr = getLastCellRow
    
    For i = 2 To lcr
        Cells(i, 4) = Cells(i, 2).Value
    Next i
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Function getLastCellRow() As Integer
    getLastCellRow = Cells(Rows.Count, 2).End(xlUp).Row
End Function

Functionプロシージャというのは、Subプロシージャと同じだが、相違点は戻り値があるかどうか、である。Functionプロシージャの方はプロシージャ名に値を代入して、一種の関数のようにして扱う。

3)

Sub Macro1()
    Dim myarry(7) As String
    Dim i As Integer
    
    For i = 2 To UBound(myarry) + 1
        myarry(i - 1) = Cells(i, 2).Value
        Cells(i, 4) = myarry(i - 1)
    Next i
End Sub

UBoundは配列などの最大値をとるものである。ここでは、わざと一度配列にデータを入れて、それから記入するセルにその値を入れている。

4)

Sub main1()
    Dim lcr As Integer, i As Integer
    Dim myarry(7) As String
    
    For i = 1 To UBound(myarry)
        myarry(i) = Cells(i + 1, 2).Value
    Next i
    
    i = 1
    Do Until Cells(i + 1, 2) = ""
        Cells(i + 1, 4) = myarry(i)
        i = i + 1
    Loop
End Sub

配列をFor文で回してあらかじめすべての値を代入し、Doループを使って表現している。ここではセルが空白になるまで(〇〇になるまで、はUntilを使う)回し、iというカウンター変数でセルを制御している。

5)

Sub main2()
    Dim lcr As Integer, i As Integer
    Dim myarry(7) As String
    
    lcr = getLastCellRow
    
    Call getCityName(myarry(), lcr)
    
    i = 1
    Do While Cells(i + 1, 2) <> ""
        Cells(i + 1, 4) = myarry(i)
        i = i + 1
    Loop
 End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Sub getCityName(myarry() As String, lcr As Integer)
    Dim i As Integer
    
    For i = 1 To lcr - 1
        myarry(i) = Cells(i + 1, 2).Value
    Next i
End Sub

getLastRowは、2)でつくったものを再度使っている。セルの最終行をとり、サブルーチンgetCityNameで配列にデータを入れているが戻り値はない。発展でByVal,ByRefで引数を渡すが、この場合は指定がないので、参照渡し(ByRef)で、内部で処理したものが、そのままの状態を保ってmainのルーチンに使える。

6)

Sub main5()
    Dim myrng As Range
    Dim lcr As Integer, i As Integer
    
    lcr = getLastCellRow
    
    i = 2
    For Each myrng In Range(Cells(2, 2), Cells(lcr, 2))
        Range("D" & i) = myrng
        i = i + 1
    Next myrng
End Sub

For Each文はオブジェクト変数(workbook,worksheet,rangeなど)を繰り返し処理する場合に使う方法である。2)でつくったFunctionプロシージャで最終行をとり、Rangeで回してセルに代入している。iはカウンター変数として用い、入力セルを制御している。

7)

Sub main6()
    Range("B2:B8").Copy Range("D2")
End Sub

これはコピー関数を使った例である。Rangeオブジェクトに対して.Copyを入れ、入れる先を書けばそれで済む。お気楽、お手軽な方法であるが、なぜか取り上げているものは見かけない。

8)

Sub main3()
    Dim lcr As Integer
    
    lcr = getLastCellRow
    
    Range(Cells(2, 2), Cells(lcr, 2)).Copy Range(Cells(2, 4), Cells(lcr, 4))
End Sub

.Copy関数と2)でつくったFunctionプロシージャとの組み合わせで、Rangeオブジェクトのなかに、cellsで範囲を取るという手法である。7)よりはデータ数が増えたときにも使える方法である。

9)

Sub main4()
    Dim lcr As Integer
    
    lcr = getLastCellRow
    
    Range(Cells(2, 2), Cells(lcr, 2)).Copy
    Range(Cells(2, 4), Cells(lcr, 4)).PasteSpecial
    Application.CutCopyMode = False
End Sub

一度クリップボードへコピーしてから、ペーストする、いわゆるコピペという方法を使っている。Application.CutCopyMode = Falseは、コピーしたとき点線が残るのを防ぐための処理である。