2024/12/06
【ExcelVBA】複数シートの表に一括反映

【ExcelVBA】複数シートの表に一括反映

以下のように、同じ形式の予定表が複数シートに用意されている場合で、それぞれの予定表の特定の時間に同じ予定を一括で登録する機能の開発方法について解説していきます。

※こちらで開発したファイルは、記事の最後にて配布しています。


開発準備

まず初めに、[開発]タブを選択し、[マクロ]を選択します。

表示された以下の画面にて、開発する機能の名前を入力し、[作成]を選択します。
こちらでは、「setSchedule」と入力しています。

次に表示される以下の画面の「Sub ○○」から「End Sub」の間にコードを記述します。


コードの記述

以下のコードを記述します。

Sub setSchedule()
    
    Dim mWs As Worksheet
    Set mWs = Worksheets("反映")
    
    Dim ws As Worksheet
    Dim i As Long
    
    For i = 4 To 33
        If mWs.Cells(i, "B").Value <> "" Then
            For Each ws In Worksheets
                If ws.Name <> mWs.Name Then
                    If InStr(ws.Cells(i, "B").Value, _
                        mWs.Cells(i, "B").Value) = 0 Then
                        
                        ws.Cells(i, "B").Value = _
                            mWs.Cells(i, "B").Value & vbLf & _
                            ws.Cells(i, "B").Value
                        
                    End If
                End If
            Next ws
        End If
    Next i
    
End Sub

では、コードについて解説していきます。

    Dim mWs As Worksheet
    Set mWs = Worksheets("反映")

反映元となるシート情報を変数「mWs」に割り当てています。

    Dim ws As Worksheet
    Dim i As Long

繰り返し処理で扱う変数を定義しています。
変数「ws」は各シートを繰り返す際に活用し、変数「i」は各行を繰り返す際に活用します。

    For i = 4 To 33
        If mWs.Cells(i, "B").Value <> "" Then
            For Each ws In Worksheets
                If ws.Name <> mWs.Name Then
                    '処理
                End If
            Next ws
        End If
    Next i

Forで反映シートの予定表の先頭行から最終行までを繰り返し、内側のIfで予定が空でない場合に関してのみ、更に内側のFor Eachを実行するように記述しています。

For Eachでは、存在するシート1つ1つのシート情報を順番に変数「ws」に割り当て、更に内側のIfでシート名が「反映」でない場合に関してのみ、最深部の処理を実行するように記述しています。

                    If InStr(ws.Cells(i, "B").Value, _
                        mWs.Cells(i, "B").Value) = 0 Then
                        
                        ws.Cells(i, "B").Value = _
                            mWs.Cells(i, "B").Value & vbLf & _
                            ws.Cells(i, "B").Value
                        
                    End If

最深部では、Ifで反映元のシートの対象行「i」の予定と同じ予定が登録されていないことを確認しています。
InStrを活用して、反映先のシート「ws」の対象行「i」のセルに、反映元のシート「mWs」の対象行「i」のセルの値が含まれているかどうかを判定しています。
InStrで含まれていないと判断された場合は、「0」を返します。
そのため、その結果が「0」の場合という条件式になっています。

この条件を満たしたときに、反映先のシート「ws」の対象行「i」のセルに元々入力されている値に対し、改行「vbLf」と反映元のシートの対象行「i」のセルの値を加えています。


ボタンの作成

コードが完成しましたら、反映シートに実行ボタンを用意します。
実行ボタンは、[開発]タブの中の[挿入]から作成することができます。

ExcelVBAレベル確認

完成

以上の手順で、機能が完成します。
反映シートの10:00の予定(セルB8)に「共通の予定」と入力して、「一括反映」ボタンを押した実行結果は、以下になります。

既存の予定が存在する場合は、その予定を残したまま、先頭に「共通の予定」が追加されます。

▼サンプルファイル▼

2024/11/22
【ExcelVBA】カテゴリー単位でセルを自動結合

【ExcelVBA】カテゴリー単位でセルを自動結合

以下の表のカテゴリーの項目のように同じ値が複数行に続く場合、それらの同じ値のセルを瞬時に結合する機能の開発方法について解説していきます。

こちらで開発する機能は、どんな表にも適用できるようしています。
そのため、既存の表をプレゼン用や配布用として用意する際に活用すると便利です。
※こちらで開発したファイルは、記事の最後にて配布しています。


開発準備

まず初めに、[開発]タブを選択し、[マクロ]を作成します。

表示された以下の画面にて、開発する機能の名前を入力し、[作成]を選択します。
こちらでは、「自動結合」と入力しています。

次に表示される以下の画面の「Sub ○○」から「End Sub」の間にコードを記述します。


コードの記述

以下のコードを記述します。

Sub 自動結合()

    Dim colNo As Long
    colNo = ActiveCell.Column
    Dim lastRow As Long
    lastRow = Cells(Rows.Count, colNo).End(xlUp).Row
    
    Dim sRow As Long
    sRow = 1
    Dim i As Long
    Application.DisplayAlerts = False
    For i = 1 To lastRow
        If Cells(i, colNo).Value <> Cells(i + 1, colNo).Value Then
            Range(Cells(sRow, colNo), Cells(i, colNo)).Merge
            sRow = i + 1
        End If
    Next i
    Application.DisplayAlerts = True
    
End Sub

では、コードについて解説していきます。

    Dim colNo As Long
    colNo = ActiveCell.Column

今回の機能は、選択しているセルの列に対して、同じ値が連続するセルを結合していきます。
そのため、基準となる列番号を格納する用の「colNo」という変数を用意し、アクティブセル(ActiveCell)の情報から列番号(Column)を取得しています。

    Dim lastRow As Long
    lastRow = Cells(Rows.Count, colNo).End(xlUp).Row

先頭行から1行ずつ、同じ値が連続していないかどうかを確認していきます。
そのため、繰り返し終える位置である最終行の行番号を格納する用の「lastRow」という変数を用意し、「colNo」の列を基準に最終行の行番号を取得しています。
取得される行番号は、「colNo」の列の、シート上の一番下のセル(Cells(Rows.Count, colNo))を選択している状態で、「Ctrl+↑」(End(xlUp))で移動した先のセルの行番号(Row)になります。

    Dim sRow As Long
    sRow = 1

こちらに関しては、結合する際の開始の行番号を格納する用の「sRow」という変数を用意しています。
また、初期値として「1」を設定しています。

    Dim i As Long
    Application.DisplayAlerts = False
    For i = 1 To lastRow
        …
    Next i
    Application.DisplayAlerts = True

次に、先頭行から最終行までを繰り返す時に使用する「i」という変数を用意し、繰り返し処理(For)の前に、結合時の以下の警告を無視する設定(Application.DisplayAlerts = False)を行っています。

繰り返し処理(For)を終えた後には、警告を無視する設定を解除するコード(Application.DisplayAlerts = True)を記述しています。

    For i = 1 To lastRow
        If Cells(i, colNo).Value <> Cells(i + 1, colNo).Value Then
            Range(Cells(sRow, colNo), Cells(i, colNo)).Merge
            sRow = i + 1
        End If
    Next i

では最後、繰り返し処理(For)の内容です。
繰り返し処理(For)では、先頭行から最終行(lastRow)まで1行ずつ繰り返し、内側の条件分岐(If)で、「繰り返し処理の該当行(i)の該当列(colNo)の値と、その次の行(i + 1)の値が一致しない場合」という条件の確認を行っています。
一致しない場合に関しては、該当列(colNo)の開始の行(sRow)から繰り返し処理の該当行(i)までの範囲のセルを結合(Merge)しています。
結合後は、次の結合時の開始の行番号(sRow)を繰り返し処理の該当行(i)の次の行番号(i + 1)に変更しています。

上記のコードを実行することによって、選択しているセルの列に対して、同じ値が連続するセルを結合することができます。

以下のコードに関しては、単体のセル範囲では結合されません。

Range(Cells(sRow, colNo), Cells(i, colNo)).Merge

そのため、今回のようなコードの内容で実現することができます。

▼サンプルファイル▼

2024/11/08
【ExcelVBA】項目名をクリックするだけで並べ替え

【ExcelVBA】項目名をクリックするだけで並べ替え

以下の表に対し、「項目名(見出し)をクリックするだけで、その項目を基準に並べ替えを行う」という機能の開発方法について解説していきます。

※こちらで開発したファイルは記事の最後にて配布しています。


開発準備

「特定のセルを選択すると同時に、何かしら処理を実行する」という仕組みは、該当するシートモジュールイベントプロシージャを活用することで実現できます。

シートモジュールは、該当するシートのタブ上で右クリックし、[コードの表示]を選択することで表示することができます。

選択すると、以下のエディタ画面(VBE)が表示されます。
また、該当するシートのシートモジュールが表示された状態になります。
「Option Explicit」は、VBEの設定内容次第では表示されません。「Option Explicit」についての解説はこちらでは省略します。

次に、セルを選択すると同時に処理が実行される特殊なプロシージャ(イベントプロシージャ)を用意する必要があります。
そのためには、シートモジュールの左上のリストから「Worksheet」を選択する必要があります。

「Worksheet」を選択すると、自動で「Worksheet_SelectionChange」というプロシージャが表示されます。
このプロシージャが、該当するシート上のいずれかのセルが選択されると同時に処理が実行されるイベントプロシージャと呼ばれるものになります。

まずは、表示された「Worksheet_SelectionChange」というプロシージャ内にコードを記述していきますが、他のイベントプロシージャを表示したい場合は、右上のリストから表示することができます。

左上のリストで「Worksheet」を選択すると、右上のリストに関しては、自動で「SelectionChange」が選択され、「Worksheet_SelectionChange」というプロシージャが表示されます。


項目名をクリックするだけで昇順にする

では、項目名をクリックするだけで、その項目を基準に表を昇順にする機能を開発していきます。

まずは、以下のコードを「Worksheet_SelectionChange」というプロシージャ内に記述します。

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

    If Target.Row = 2 And _
        Target.Column >= 2 And Target.Column <= 5 Then
        
        Dim rng As Range
        Set rng = Range("B2").CurrentRegion
        rng.Sort _
            Key1:=Target, _
            Order1:=xlAscending, _
            Header:=xlYes
        
    End If
    
End Sub

では、コードについて解説していきます。

    If Target.Row = 2 And _
        Target.Column >= 2 And Target.Column <= 5 Then  End If

「Worksheet_SelectionChange」プロシージャの引数「Target」に、トリガーとなったセルの情報が渡されます。
そのTargetを活用し、そのTargetの情報が「行番号が2、尚且つ、列番号が2以上、5以下」であるかどうかを確認しています。
その条件を満たしている時、要するに、以下の項目名の範囲内が選択された時に、Ifの中の処理が実行されます。

        Dim rng As Range
        Set rng = Range("B2").CurrentRegion
        rng.Sort _
            Key1:=Target, _
            Order1:=xlAscending, _
            Header:=xlYes

こちらで「rng」というRange型の変数を用意し、その変数に対象の表の範囲を割り当てています。
「Range(“B2”).CurrentRegion」で、セルB2周囲に連続しているデータ範囲全体を指定しています。

その「rng」に対し「Sort」で並べ替えを行っています。
「Key1:=Target」でTargetの属する列を並べ替えの基準の列として指定し、「Order1:=xlAscending」で昇順を指定、「Header:=xlYes」でrngが項目名を含む範囲ということを指定しています。

以上の内容で実現できます。
該当する項目名を選択することで、以下のように並べ替えを行うことができます。


項目名を右クリックするだけで降順にする

では次に、項目名を右クリックすることで、その項目を基準に表を降順にする機能を開発していきます。

先ほどと同様に、シートモジュール上にコードを記述していきます。
ただ、先ほどとは別のイベントプロシージャを使用する必要があります。

そのプロシージャとは、該当するシート上のいずれかのセルの上で右クリックした時に処理が実行されるというイベントプロシージャです。
シートモジュールの右上のリストから「BeforeRightClick」を選択することで表示することができます。

表示された「Worksheet_BeforeRightClick」というプロシージャ内にコードを記述していきます。

まずは、以下のコードを記述します。

Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
    
    If Target.Row = 2 And _
        Target.Column >= 2 And Target.Column <= 5 Then
        
        Cancel = True
        Dim rng As Range
        Set rng = Range("B2").CurrentRegion
        rng.Sort _
            Key1:=Target, _
            Order1:=xlDescending, _
            Header:=xlYes
        
    End If
    
End Sub

コードの内容は、先ほどの内容とほぼ同じになります。
そのため、異なる点のみを解説します。

        Cancel = True

「Cancel」に対し、Trueを指定することで、右クリック時にメニューが表示されないようにすることができます。

        rng.Sort _
            Key1:=Target, _
            Order1:=xlDescending, _
            Header:=xlYes

先ほどの内容とは異なり、こちらでは「Order1:=xlDescending」として降順にしています。

以上の内容で実現できます。
該当する項目名の上で右クリックすることで、以下のように並べ替えを行うことができます。

▼サンプルファイル▼

2024/11/01
【ExcelVBA】空白を上に詰める

【ExcelVBA】空白を上に詰める

以下のような表で、空白行を除外して上に詰める場合、並べ替え機能を活用すると、書式の設定位置や要素の順番に関しても変わってしまいます。

今回は、書式の設定位置や要素の順番を変えずに、そのままの状態で上詰めする機能をVBAで開発する方法について解説していきます。
※こちらで開発したファイルは、記事に最後にて配布しています。


開発

初めに、[開発]タブの中の[マクロ]を選択します。

[マクロ]を選択すると表示される以下の画面に、開発する機能の名前を入力し、[作成]を選択します。
こちらで「上詰め」と入力しています。

[作成]を選択すると表示される以下のエディタ画面の「Sub 上詰め()」から「End Sub」の間にコードを記述していきます。
「Option Explicit」は、エディタの設定次第では表示されません。

では、以下のコードを記述します。

Sub 上詰め()

    Dim inData As Variant, outData As Variant
    inData = Range("B3:B11").Value
    ReDim outData(1 To UBound(inData), 1 To 1) 
    
    Dim d As Variant, i As Long: i = 1
    For Each d In inData
        If d <> "" Then 
            outData(i, 1) = d
            i = i + 1
        End If
    Next d
    
    Range("B3:B11").Value = outData
    
End Sub

解説

このコードについて、簡単に解説していきます。

    Dim inData As Variant, outData As Variant
    inData = Range("B3:B11").Value

ここで、inDataとoutDataという変数を用意し、inDataには上詰めする対象のセル範囲B3~B11の値のみを格納しています。
具体的には、inDataにセルB3~B11の値を1列の2次元配列として取得しています。

    ReDim outData(1 To UBound(inData), 1 To 1) 

outDataに関しては、inDataと同じ行数、列数の2次元配列になるように変換しています。
inDataのようにセルの範囲を格納すると、添字が1からの2次元配列になるため、outDataに関しても同様に、添字を1からとした2次元配列を用意しています。
行に関しては、UBoundを用いてinDataの行数を取得し、列に関しては、1列のみの範囲になるため、「1 To 1」と1列のみを用意しています。

    Dim d As Variant, i As Long: i = 1
    For Each d In inData
        If d <> "" Then 
            outData(i, 1) = d
            i = i + 1
        End If
    Next d

次に、必要な変数を用意し、For EachでinDataの値を先頭から1つずつ繰り返してdに渡しています。
この繰り返し処理の中で、dの値が空でない場合に、outDataのi行目に加えていくようにしています。
この「i」に関しては、初期値は1で、outDataに加えられた後に、「i」自身に1を加えています。
これにより、outDataには、inDataの空の値を除外した値のみが上詰めで格納されます。

    Range("B3:B11").Value = outData

最後に、outDataの値を対象の表に貼り付けています。
outDataの配列の要素で、値が格納されなかった要素に関しては、初期値として空が渡されます。


ボタン作成

後は、開発した機能をボタンに割り当てることで完成です。
ボタンに関しては、[開発]タブの中の[挿入]から作成することができます。

[挿入]から[フォームコントロール]の中の[ボタン]を選択し、図形を作成する時と同様に、好みの位置にボタンを作成します。
ボタンを作成すると、[マクロの登録]という画面が表示されるため、開発した機能の名前(上詰め)を選択して確定します。

これだけで、開発した機能を割り当てたボタンを作成することができます。
必要に応じて、ボタンの名前を変更すると良いです。
※一度作成したボタンを選択すると、機能が実行されてしまいます。作成後に編集する際は、右クリック、もしくはCtrlキーを押しながらクリックすることで編集することができます。

▼サンプルファイル▼

2024/09/27
【ExcelVBA】セルの値とシート見出しの色を連動

【ExcelVBA】セルの値とシート見出しの色を連動

以下のシートのセルA2に入力されているステータスに応じて、シート見出しの色を自動で変更する仕組みについて解説していきます。

こちらの内容は、VBAで開発しています。
※実際に開発したファイルに関しては、記事の最後にて配布しています。

ExcelVBAレベル確認

1. 開発準備

今回の機能は、各シートのセルA2のステータスの値に応じて、シート見出しの色が変換するという内容です。
セルA2にステータスが入力されているシートに関して、全てに適用する場合は、ブックモジュールを活用します。

ブックモジュールは、[開発]タブの中の[Visual Basic]を選択して、プロジェクトウィンドウから[ThisWorkbook]を選択することで、表示することができます。

表示されたブックモジュールにて、上のリストから[Workbook]を選択し、隣のリストから[SheetChange]を選択します。

表示された[Workbook_SheetChange]というプロシージャのみを活用します。
他のプロシージャに関しては、削除しても問題ございません。

[Workbook_SheetChange]というプロシージャが、各シートのセルが編集された時に実行されるイベントプロシージャになります。
このプロシージャの引数「Sh」に実行のきっかけとなったシートの情報、引数「Target」に実行のきっかけとなったセルの情報が渡されます。


2. コードの記述

これらの情報を活用して、以下のように処理を記述します。

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    
    If Sh.Range("A1").Value = "ステータス" Then
        If Sh.Range("A2").Value = "確認待ち" Then
            Sh.Tab.Color = RGB(255, 255, 0)
        ElseIf Sh.Range("A2").Value = "修正待ち" Then
            Sh.Tab.Color = RGB(255, 165, 0)
        ElseIf Sh.Range("A2").Value = "完了" Then
            Sh.Tab.Color = RGB(180, 180, 180)
        Else
            Sh.Tab.ColorIndex = xlColorIndexNone
        End If
    End If
    
End Sub

では、このコードの処理の内容を解説します。

If Sh.Range("A1").Value = "ステータス" Then

初めに、対象のシートのセルA1に”ステータス”という文字が入力されているかどうかを確認します。
”ステータス”という文字が入力されている場合に関してのみ、内側の以下の処理を実行します。

If Sh.Range("A2").Value = "確認待ち" Then
    Sh.Tab.Color = RGB(255, 255, 0)
ElseIf Sh.Range("A2").Value = "修正待ち" Then
    Sh.Tab.Color = RGB(255, 165, 0)
ElseIf Sh.Range("A2").Value = "完了" Then
    Sh.Tab.Color = RGB(180, 180, 180)
Else
    Sh.Tab.ColorIndex = xlColorIndexNone
End If

ここで、セルA2の値が”確認待ち”なのか、”修正待ち”なのか、”完了”なのか、それ以外なのかを判断し、それぞれの条件に合ったシート見出しの色を設定しています。

Sh.Tab.Color = RGB(255, 255, 0)

”確認待ち”の場合は、上記の内容でシート見出しの色を黄色にしています。
色はRGBで指定しています。
他、”修正待ち”の場合はオレンジ色、”完了”の場合は灰色にしています。

Sh.Tab.ColorIndex = xlColorIndexNone

どれにも該当するステータスがない場合は、上記の内容でシート見出しの色をリセット(色なし)しています。
リセットする場合は、ColorIndexを使用し、xlColorIndexNoneと指定します。


3. 完成

このコードを記述することで、以下のように、セルA2のステータスに応じて、該当するシート見出しの色が自動で変更されます。

▼サンプルファイル▼

2024/09/20
【ExcelVBA】選択した値の関連データを自動で抽出

【ExcelVBA】選択した値の関連データを自動で抽出

この記事では、特定のデータを選択して「抽出」ボタンを押すだけで、関連データを別シートに自動で抽出する機能の開発方法について解説しています。
解説には、以下の表を活用します。

(例)「男」を選択して「抽出」ボタンを押す → 「男」シートが作成され「男」のデータのみが抽出される

※開発したファイルは、記事の最後で配布しています。


1. 開発準備

まずは、[開発]タブの中の[マクロ]を選択します。

表示された以下の画面にて、開発する機能の名前を入力します。
こちらでは「抽出」と入力しています。

入力後、[作成]ボタンを押します。

以下の画面が表示されましたら、エディタ内のSub~End Subの中にプログラムを記述していきます。
※Option Explicitはエディタの設定内容によっては表示されません。


2. コードの記述

Sub~End Subの中に記述する内容は、以下になります。

Sub 抽出()
    
    Dim t As Range
    Set t = ActiveCell
    
    t.AutoFilter Field:=t.Column - 1, Criteria1:=t.Value
    Columns("A:E").Copy
    
    With Worksheets.Add
        .Range("A1").PasteSpecial Paste:=xlPasteFormats
        .Range("A1").PasteSpecial Paste:=xlPasteColumnWidths
        .Range("A1").PasteSpecial Paste:=xlPasteValues
        .Name = t.Value
        .Range("A1").Select
    End With
    
    t.AutoFilter
    
End Sub

先頭から順番に解説していきます。

Dim t As Range
Set t = ActiveCell

こちらでは、tというセルの情報を格納する用の変数(入れ物)を用意し、アクティブセル(選択基準のセル)の情報を格納しています。

t.AutoFilter Field:=t.Column - 1, Criteria1:=t.Value

こちらで、先ほど定義したtのセルを基準にフィルター機能で絞り込みを行っています。
絞り込みの内容は、tの列番号から1を引いた位置の列(表がB列から始まっているため、実際の項目の位置情報と列番号は異なる)に対し、tのセルの値と一致するデータになります。

以下の場合、セルD5が選択されているため、D列の列番号の4から1を引いた3番目の項目(性別)に、セルD5の値(男)が入力されているデータのみで絞り込みを行います。

Columns("A:E").Copy

そして、絞り込みをした表を含むA~E列の範囲をコピーしています。

With Worksheets.Add
    .Range("A1").PasteSpecial Paste:=xlPasteFormats
    .Range("A1").PasteSpecial Paste:=xlPasteColumnWidths
    .Range("A1").PasteSpecial Paste:=xlPasteValues
    .Name = t.Value
    .Range("A1").Select
End With

こちらで、新しいシートを追加し、コピーしたデータ(書式、列幅、値)を貼り付けています。
貼り付けた後に、シート名をtのセルの値にし、そのシートのセルA1を選択するという処理です。

t.AutoFilter

最後に、絞り込みをした表の絞り込みを解除して、処理が終了します。


3. ボタンの作成

後は、開発した機能をボタンに割り当てます。
ボタンは、[開発]タブの中の[挿入]から[ボタン]を選択することで作成することができます。

図形の作成時と同様に、好みの位置にボタンを作成することができます。
ボタンを作成すると[マクロの登録]という画面が表示されるため、開発したマクロ(こちらの場合は「抽出」)を選択して確定します。

必要に応じて、ボタンの表示名を変更することで、ボタンの完成です。
※一度作成したボタンを選択すると、割り当てた処理が実行されてしまいます。
作成したボタンを編集する際は、右クリック、もしくは、Ctrlキーを押しながら選択します。

ExcelVBAレベル確認

4. 完成

以上の手順で完成です。

好みのデータを選択してから「抽出」ボタンを押すことで、選択したデータに関連するデータを別シートに抽出することができます。

こちらで開発したExcelファイルは、以下になります。

▼サンプルファイル▼

2024/08/16
【ExcelVBA】選択セルの列幅を自動調整

【ExcelVBA】選択セルの列幅を自動調整

セルの列幅に収まらない値が入力されている場合、その値はセルからはみ出してしまいます。
右隣りのセルにも値が入力されている場合は、はみ出した値が見えなくなってしまいます。
その対策として、セル内の値を[折り返して表示する]や、セルの列幅を広げるといった方法がありますが、以下のような予定表などの場合は、見た目が悪くなってしまいます。

そのため今回は、選択したセルの列幅を自動で調整し、他のセルを選択すると同時に列幅が元に戻る仕組みを、VBAを用いて実現していきます。

※こちらで解説したファイルは記事の最後にて配布しています。

ExcelVBAレベル確認

仕組み

今回の仕組みは以下のようになります。

①セルを選択すると同時に、選択しているセルを基準に列幅を自動調整
②他のセルを選択すると同時に、列幅を元に戻す

「①」に関しては、予定表の中が選択された時のみに適用します。

「②」に関しては、曜日の列を基準に列幅を調整することで、元の状態に戻していきます。

特定のシート上のセルを選択すると同時に何かしらの処理を実行するには、シートモジュールを活用します。


1. 開発準備

シートモジュールを開くには、対象のシートタブの上で右クリックし、[コードの表示]を選択します。

表示された画面がシートモジュールの編集画面になります。

次に、編集画面の上部にあるリストから[Worksheet]を選択します。

選択すると「Worksheet_SelectionChange」というイベントプロシージャが表示されます。
万が一、異なるイベントプロシージャが表示された場合は、先ほどのリストの右隣りのリストから「SelectionChange」を選択してください。
※「Option Explicit」は環境設定によっては表示されません。

このイベントプロシージャは、該当するシートのセルの選択位置が変更されると同時に実行されるものになります。


2. コードの記述

SubからEnd Subの間に、以下のコードを記述します。

では、このコードの意味について解説していきます。

「Worksheet_SelectionChange」の引数である「Target」には、選択されたセルの情報が渡されます。
先頭行の「If Target.CountLarge = 1 Then」から末尾の「End If」の中に関しては、「Target.CountLargr = 1」の条件を満たしている時のみ、要するに選択しているセルが複数ではなく1つの時のみに実行されます。

先ほどの条件を満たしている場合は、「Range(“C4:AF4”).Columns.AutoFit」が実行されます。
この処理は、「Range(“C4:AF4”)」を基準に列幅を自動調整するというものです。
「Range(“C4:AF4”)」は曜日が入力されているセルのため、この処理で、予定表全体が曜日のセルを基準とした列幅で自動調整されます。

次に、以下のIFの処理です。

こちらの内容は、以下の条件が書かれています。

・選択されたセルの行番号が5以上、かつ、19以下、かつ、列番号が3(C列)以上、かつ32(AF列)以下

つまり、予定を入力する範囲の中になります。

この範囲の中のセルが選択された場合に関してのみ、Ifの中の「Target.Columns.AutoFit」が実行されます。
「Target.Columns.AutoFit」は選択したセルを基準に列幅を自動調整するというものです。


3. 完成

以上の内容をシートモジュールに記述することで、機能としては完成です。
こちらの内容を実装したサンプルファイルは以下になります。

▼サンプルファイル▼

2024/07/12
【ExcelVBA】Functionで複数の戻り値を設定

【ExcelVBA】Functionで複数の戻り値を設定

通常、Functionの戻り値に設定できる数は、以下のように1つになります。

実は、ある方法を活用することで、複数の戻り値を設定することができるようになります。
その方法について、解説していきます。


複数の戻り値を設定

その方法は、「構造体」を活用するという方法です。
構造体とは、複数の変数をまとめて1つの塊にしたものになります。 詳しくは、下記記事をご確認ください。

>構造体の作成方法

まずは、戻り値として設定したい構造体を、以下のように定義します。
※構造体の名前や要素は、好みの内容で問題ございません。また、構造体は必ずSubよりも前に定義する必要があります。

構造体を定義することができましたら、後は、その構造体を戻り値として設定することで、実現できます。
イメージは、以下のようになります。

こちらの内容では、関数「MULT_NUMBER」でエラーが発生した時に、「MULT_NUMBERでエラーです」と表示し処理を中断するように実装されています。


注意点

注意点として、構造体を戻り値に設定する場合は、必ず戻り値の型を定義する必要があります。
型の定義を忘れてしまうと、以下のようにエラーになります。

2024/06/28
【ExcelVBA】ダブルクリックでデータを移動

【ExcelVBA】ダブルクリックでデータを移動

以下の「未完了の表」の中にあるタスク名をダブルクリックすることで、瞬時に、「完了の表」に該当するタスクを移動させる仕組みの実現方法について、解説していきます。

今回の仕組みを実現したサンプルファイルは、記事の最後にて配布しています。


1. 開発準備

特定のシート内の特定のセルをダブルクリックした時に、何かしらの処理を実行させる場合は、「シートモジュール」を活用します。
シートモジュールは、[開発]タブの中の[Visual Basic]を選択し、表示されたVBEの画面内の[プロジェクト]から、該当するシートをダブルクリックすることで、開くことができます。

他の方法ですと、該当するシートタブ上で右クリックし、表示されたメニューから[コードの表示]を選択することでも、シートモジュールを開くことができます。


次に、「セルをダブルクリックした時に実行されるイベントプロシージャ」を用意する必要があります。
そのため、シートモジュール上の[General]と書かれたリストから[Worksheet]を選択します。

恐らく、「Worksheet_SelectionChange」というイベントプロシージャが表示されるかと思います。

次に、隣のリストから[BeforeDoubleClick]を選択します。

そのようにすると、「Worksheet_BeforeDoubleClick」というイベントプロシージャが表示されるため、このプロシージャのみを残し、他は削除しても問題ございません。

この「Worksheet_BeforeDoubleClick」というイベントプロシージャが、シートモジュールが属するシート上のセルをダブルクリックした時に実行されるイベントプロシージャになります。

ExcelVBAレベル確認

2. コードの記述

次に、SubからEnd Subの間に、以下のコードを記述します。

コードの内容について解説します。

「Worksheet_BeforeDoubleClick」では、引数である「Target」にダブルクリックされた対象のセルの情報が渡されます。
そのため、「If Target.Row >= 4 And Target.Column = 2 And Target.Value <> “” Then」にて、ダブルクリックされた対象が、4行目以上であり、2列目(B列)であり、空白でない場合に「If」から「End If」の間の処理が実行されるようにしています。
※1行のコードを改行する場合は、「(半角スペース)_」を入力します。

「4行目以上、2列目」というのは、該当するシート上の「未完了の表」の中を指します。

次に、「Worksheet_BeforeDoubleClick」の引数の「Cancel」を更新します。
[Cancel]の値を「True」にすることで、ダブルクリック後の動作(セル内にカーソルが表示され、編集モードに切り替わる)を中断することができます。

今回の目的は、タスク名が入力されたセルを移動させることになるため、「Cancel = True」と記述し、ダブルクリック後の動作を中断しています。

最後に以下の内容です。

「Target.Copy」にて、ダブルクリックされたセル自体をコピーし、「Range(“D4”).Insert xlDown」にて、セルD4の位置に、コピーしたセルを挿入しています。
「xlDown」では、セルの挿入後に、セル全体が下方向に移動するように指定しています。

そして、「Target.Delete」にて、元のセルを削除することで、未完了タスクを上に詰めています。

「Target.Delete」に関しては、「Target.Delete xlShiftUp」のように「xlShiftUp」と記述し、「上方向にシフト」と指定することもできますが、省略時は「xlShiftUp」が適用されるため、こちらでは省略しています。

以上で完成になります。
実装したサンプルファイルは、以下になります。

▼サンプルファイル▼

2024/05/31
【ExcelVBA】数式「AND(3,4)」とVBA「3 And 4」は違う!?

【ExcelVBA】数式「AND(3,4)」とVBA「3 And 4」は違う!?

IF関数などに設定する倫理式(TRUEもしくはFALSEを返す式)に関して、Excelの数式やVBAでは、「0」がFALSE、「0」以外の数値がTRUEという意味として扱われます。

しかし、AND条件にすると、VBAでは、以下の黄色のセルのように、理想通りの結果にならないことがあります。

「3」と「4」では、ともに「0」以外の数値であるため、AND条件ではTRUEになるかと思うのですが、VBAではFALSEになってしまいます。
今回は、「なぜVBAのAND条件では理想通りの結果を返さなかったのか」について解説していきます。

ExcelVBAレベル確認

原因と対策

結果に違いが発生する理由は、Excelの数式での判定方法とVBAでの判定方法が異なるためです。
そのため、判定方法の違いについて確認していきます。

Excelの数式での判定方法は、条件1つ1つに対し、TRUEかFALSEかを判定して、AND条件の場合は、複数の条件がTRUEなのかを判定しています。
そのため、「3」と「4」の比較では、「3」がTRUEで「4」もTRUEのため、「AND(3,4)」ではTRUEという結果になります。

それに対しVBAでは、1つ1つの条件に対し、ビット単位で演算しています。
具体的には、二進数のビット単位(各桁同士)での演算になります。

「3」という数値を二進数で表現すると「0011」になり、「4」という数値を二進数で表現すると「0100」になります。

AND演算とは、「0」と「1」では「0」になり、「1」と「0」でも「0」となり、「1」と「1」の場合に関してのみ「1」となるような演算になります。

そのため、「0011」と「0100」をビット単位でAND演算すると、右から1桁目は「1」と「0」で「0」、2桁目も「1」と「0」で「0」、という感じで「0000」という結果になります。
「0000」という二進数は「0」という数値を意味するため、FALSEという結果になったということになります。

もし、数値同士をVBAで比較したい場合は、以下のように「0でない場合」という条件を加えると良いです。

2024/04/26
【ExcelVBA】VBAを使ってシートの初期設定を自動化

【ExcelVBA】VBAを使ってシートの初期設定を自動化

Excel関連の何かしらの作業を自動化する際に、便利な機能としてマクロというものがあります。
このマクロを開発することができるプログラミング言語がVBAになります。
こちらでは、次の作業を自動化するマクロを、VBAを用いて開発する方法について解説していきます。
※開発したファイルは記事に最後にて配布しています。

ExcelVBAレベル確認

作業内容

1.以下のテンプレートシート「YYYYMMDD」のコピーを作成し、シート名を作業日の日付(YYYYMMDD形式)にする

2.コピーしたシートのセルB2に作業日の日付を入力する


1. 開発の準備

では早速、自動化するマクロを開発していきます。
※開発したマクロに関しては、「Ctrl+Shift+A」というショートカットで実行できるようにも設定していきます。

まずは、[開発]タブを選択し、その中の[マクロ]を選択します。

次に、以下の画面にて、好みの名前を入力し、[作成]を選択します。
こちらでは「シート作成」と入力しています。

表示されました以下の画面にて、プログラムを記述していきます。
※「Option Explicit」は設定内容によっては表示されません。


2. コードの記述

記述する内容は、以下になります。

こちらのプログラムに関して、1行ずつ解説していきます。

まずは、以下の内容について解説します。

Worksheets("YYYYMMDD").Copy After:=Worksheets(1)

こちらでは、「YYYYMMDD」のシートをコピーし、2枚目の位置に貼り付けています。
「Worksheets(1)」が先頭から1番目のシートを指しているため、「Copy」というコピーする機能の設定(引数)の「After」に「Worksheets(1)」を指定することで1番目のシートの後ろと指定しています。

次は、以下の内容について解説します。

With ActiveSheet
    .Name = Format(Date, "yyyymmdd")
    .Range("B2").Value = Date
End With

まずは、「With」について解説します。
「With」を用いることにより、「With」から「End With」の間に関して、「With」の後ろに指定した要素「ActiveSheet」を省略して記述することができるようになります。
省略して記述する場合は、「.」から記述します。

つまり、以下のプログラムと同じ意味になります。

ActiveSheet.Name = Format(Date, "yyyymmdd")
ActiveSheet.Range("B2").Value = Date

同じ要素(こちらでは「ActiveSheet」)に対して操作する場合は、「With」で囲むことによって、処理の塊が分かりやすくなります。

では次に、以下のプログラムについて解説します。

ActiveSheet.Name = Format(Date, "yyyymmdd")

「ActiveSheet」とは現在選択されているシートを指します。
シートをコピーして複製すると、その複製されたシートが自動で選択されるため、「ActiveSheet」は新たに追加したシートのことを指しています。
そのシートの名前「.Name」を「Format(Date, “yyyymmdd”)」で、マクロを実行した日付にしています。
「Date」で、マクロを実行した日付の情報を取得することができるのですが、シート名にはYYYYMMDD形式で設定したいため、Format関数を活用して、形式を変換しています。

では最後に、以下のプログラムについて解説します。

ActiveSheet.Range("B2").Value = Date

こちらでも先ほど同様に「ActiveSheet」を指定しています。
そのシートのセルB2「Range(“B2”)」の値「.Value」に、マクロを実行した日付「Date」を入力しています。

ExcelVBAレベル確認

3. 完成

このようにして開発することができました。
開発したプログラムは、対象のプログラム名を指定し、実行ボタンを押すことで実行することができます。

実行することにより、以下のようにシートが作成され、セルB2に日付が入力されます。

注意点として、Excel上には同じシート名のシートを作成することができないため、同日に複数回実行すると、以下のようなエラーが表示され、処理が中断されます。

再度実行する際は、作成したシートを削除してから行う必要があります。 必要に応じて、シート名が重複した場合には「YYYYMMDD_2」のような番号を加えるようにプログラミングするのも良いかと思います。
その方法については、こちらでは省略します。


4. ショートカットの設定

最後に、ショートカットの設定方法です。
毎回、VBAの編集画面(VBE)を開いて実行するのは手間になるため、ショートカット活用するのがオススメになります。
まずは、[開発]タブの中の[マクロ]を選択し、以下の画面を表示します。

こちらの画面より、開発したプログラム名を選択し、[オプション]を選択します。

以下の画面の[ショートカットキー]のテキストボックスを選択し、Shiftキーを押しながらAキーを押すことで、「Ctrl+Shift+A」というショートカットを設定することができます。

設定後は、[OK]を選択して確定し、設定画面を全て閉じることで、CtrlキーとShiftキーを押しながらAキーを押すして、開発したマクロを実行することができるようになります。

こちらで開発したファイルは、以下から取得できます。


まとめ

今回の内容は、VBAを用いて繰り返し作業を自動化する一例になります。
ぜひ、日々の繰り返し作業の自動化に、VBAを活用してみてください。
※理解していないプログラムの実行は、情報漏洩データの紛失などの大きな問題につながる可能性があるため、理解した上で実行してください。

2024/03/29
【ExcelVBA】更新履歴を自動で入力

【ExcelVBA】更新履歴を自動で入力

以下のような更新履歴表に関して、「更新」ボタンを押して更新内容を入力するだけで、表の最終行に「更新日、更新者(パソコンにログオン(ログイン)したユーザー名)、更新内容(インプットボックスに入力した値)」が自動で入力される仕組みを開発していきます。

VBAを活用することで、簡単にパソコンに記録されている情報(パソコンにログオンしたユーザー名など)を取得することができます。
今回は、更新者としてパソコンにログオンしたユーザー名を取得していますが、他の値を取得する方法についても、確認用のマクロを配布して解説しています。


準備

機能を開発するために、まずは更新履歴表を用意します。
今回こちらでは、以下のような表を用意しています。

5行目以降に関しては、罫線のみで値を入力していない状態にしておきます。
※用意した表のレイアウト(項目の位置など)によっては、開発するプログラムの内容が異なります。


開発

次に、[開発]タブの中の[マクロ]を選択します。

※[開発]タブが表示されていない場合は、以下の手順をご確認ください。

>マクロを開発する準備

以下の画面が表示されましたら、開発する機能の名前(こちらでは「更新」)を入力し、[作成]を選択します。

以下の画面が表示されましたら、「Sub 更新()~End Sub」の間にプログラムを入力していきます。
※環境によっては、「Option Explicit」が表示されていないことがありますが、今回はなくても問題ございません。

では次に、以下のようにプログラムを入力します。
※こちらを実装したExcelファイルは、記事の最後にて配布しています。

Sub内はTabキーにてインデント(字下げ)しています。
インデントの有無では処理に影響はないのですが、処理の見やすさの観点からインデントする癖をつけておいた方が良いです。


プログラムの解説

プログラムの内容について簡単に確認していきます。

まずは、以下の内容です。

「Dim」と書かれているのは、一時的に値を格納する部屋(変数)を用意する宣言(変数宣言)になります。
「As」の後に部屋の種類を記述しています。(「String」は文字専用の型)

次に、用意した「detail」という変数にインプットボックス「InputBox」に入力した値を格納します。

「InputBox」の括弧の中の文字は、インプットボックスに表示される文字になります。
イメージは以下になります。

次に以下の内容です。

「Dim」は先ほど同様に変数宣言になります。(「Long」は数値専用の型)

「Rows.Count」はシートに存在している最大の行番号になるため、「Cells(Rows.Count,”B”)」でシート上のB列の一番下のセルを指定しています。

このセルから、Ctrlキーを押しながら上に移動「.End(xlUp)」し、止まった位置の行番号「.Row」に1を加えた数を取得しています。
→ B列の下から上に向かっていく中で、次に文字が入力されているセルの一つ下の行番号(5)を取得

次に以下の内容です。

先ほど取得した行番号のB列のセルに実行した時の日付「Date」を入力し、C列のセルにパソコンにログオンしたユーザー名を入力、D列のセルにインプットボックスに入力した値を入力しています。 ユーザー名はEnviron関数を用いて取得しています。
※Environ関数で取得できる値については、最後に確認用マクロを配布して解説しています。

最後に以下の内容にて、Excelファイルを保存しています。


ボタンの配置

これで機能としては完成しているため、後はボタンを作成し、そのボタンに開発した機能を割り当てれば完成です。

ボタンは、[開発]タブの中の[挿入]から作成すると良いです。

上記のボタンを選択後、図形の作成時と同様にボタンを作成すると、[マクロの登録]画面が表示されます。
そこでは、開発したマクロの名前を選択することで、マクロを割り当てたボタンを用意することができます。
ボタンの表示名などは必要に応じて変更してください。
※作成したボタンを編集する場合は、Ctrlキーを押しながら選択します。

このようにして、ボタンを押してインプットボックスに更新内容を入力するだけで、表の最終行に値が入力されます。


Environ関数について

最後に、Environ関数で取得できる値について、確認用のファイルを配布して解説していきます。

Environ関数で取得できる値は以下になります。

Environ関数の引数に上記の左側にある環境変数名を設定することで、その値を取得することができます。
先ほどのプログラムで使用した値は「USERNAME」になります。

どのような値が取得できるのかは、実際に試された方がイメージしやすいかと思いますので、各々で確認できるファイルを配布します。
配布ファイルのマクロの実行を許可し、「出力」ボタンを押すだけで、値を確認することができます。

ExcelVBAレベル確認

配布

今回開発した「更新履歴を自動で入力する機能のExcelファイル」と「Environ関数の出力確認用のExcelファイル」は以下になります。

ぜひ試してみてください。