excelVBA本格入門を読みながら当時考えたこと
Option Explicit
'図形をShift+ドラッグは比率維持,Alt+ドラッグはぴったり移動、Ctr+ドラッグはコピー
'Ctr+クリックで、マクロを実行することなくボタンを選択できる。
'マクロをショートカットキーに登録することもできる。クイックアクセスツールバーにも。
'キーワードを選択しておいて、F1でヘルプを開く。
'モジュールとは。マクロを記述するための専用シート
'プロジェクトとは。モジュールの集まり。
'プロジェクト=標準モジュール+ユーザーフォーム+クラスモジュール+Excelオブジェクト(ブック、ワークシート、グラフシート)
'Excelブック=ワークシート+グラフシート
'自動メンバー表示の後、Tabで確定。Enterは確定改行。
'バグを発見する方法は、疑わしい位置で実行を中断し、そこから動作確認しながら1ステップずつ実行していく。
'ステップインしたら、Excel上でその1つ前のステートメントが期待通り動作したか確認する。これを繰り返す。
'(田中亨メモ)
'1マクロ記録する
'2マクロ記録を読む
'3無駄を省く(シェイプ等はSlectとSelectionが違うので、削りすぎてエラーになったらSelectionは残せばよい
'4メソッドプロパティに検討がついたらヘルプを見る(F1)
'
'マクロ記録は必要なコードを作ってくれる機能ではない。
'マクロ記録は行った操作をVBAのコードとして記述するだけ。
'解説機能はヘルプF1
'マクロ記録だけでは対話型マクロと条件分岐や繰り返しが作れない。
'オブジェクトとは。excelの部品。例。ブック、シート、セル
'自動車(アプリケーション=Excel)、ボディー、タイヤ、エンジン(オブジェクト=Excelの部品)
'プロパティとは。オブジェクトの「特徴」のこと。
'オブジェクト式
'①対象.命令 ②対象.様子=値 ③対象.様子
'変数とは。箱。
'階層構造を省略しなければ、アクティブではないシートに代入(計算)できる。
'選択(指定)さでできれば、代入(計算)できる。
'(ちゅんちゅんメモ)
'BookとSheet を省略しないで書く。省略を発見したらすぐ補完しておく。
'コレクションとは。オブジェクトの集合体。オブジェクトとは。部品。
'すべてのブックを閉じる
sub すべてのブックを閉じる()
Workbooks.Close
End sub
'VBAでは「Workbooks」のようなコレクションを特定するためのキーワードはプロパティに分類される。
'Workbooks(1).close
' (ワークブックスプロパティ)に(引数)を指定するとWorkbookオブジェクトが特定できる。
'セルというオブジェクトを特定するキーワードをCellsプロパティ、ActiveCellプロパティ、Offsetプロパティ、と表現する。
'事例1 保存場所を特定してブックを開く
sub ブックを開く()
Dim wb As Workbook
Set wb = Workbooks.Open(Filename:="C:\honkaku\Hoge.xlsx")
End sub
'カレントフォルダとは。現在選択されているフォルダ。[ファイルを開く]ダイアログボックスに表示されているフォルダ。
'事例2 カレントフォルダのブックを開く
sub ブックを開く2()
Dim wb As Workbook
Set wb = Workbooks.Open(Filename:="Hoge.xlsx")
End sub
'カレントフォルダはどうやって変更するのか
'ユーザーの[ドキュメント]フォルダが既定のカレントフォルダ
'[名前をつけて保存]で保存先を変えるとCurDirも変わる。
'chDirステートメントで変更。curDir関数で確認。
'
'パスを指定してブックを開く(田中亨)
' Workbooks.Open ファイル名
' (ファイルのパス。=パス¥ファイル名)
sub ブックのコピー()
''新規ブックできる
ThisWorkbook.Sheets.Copy
'保存する
ActiveWorkbook.SaveAs ThisWorkbook.Path & "\HogeHoge.xlsx"
End sub
'事例3 ブックを保存して閉じる
sub ブックを保存して閉じる()
Workbooks("Hoge.xlsx").Close savechanges:=True
End sub
'事例4
sub 印刷プレビューを実行する()
ThisWorkbook.Worksheets("売上台帳").PrintPreview
End sub
sub 印刷実行()
ThisWorkbook.Worksheets("Hoge.xlsx").PrintOut
End sub
'事例5
sub シートの削除()
Application.DisplayAlerts = False
ThisWorkbook.Worksheets("Hoge").Delete
Application.DisplayAlerts = True
End sub
'
'
sub シートのコピー()
' Thisworkbook.Worksheets("Hoge").Copy Before:=
' After:=
'End sub
'
'
sub シートの追加()
' Worksheets("Hoge").Add
' Before:=
' After:=
' count:=
'End sub
sub シートを追加してすぐ名前を付ける()
ThisWorkbook.Worksheets.Add.Name = "Huga"
'worksheets.addで追加したワークシートオブジェクトが返る
End sub
sub シートの非表示_ユーザー再表示可()
ThisWorkbook.Worksheets("Hoge").Visible = xlSheetHidden
End sub
sub シートの非表示_ユーザー再表示不可能()
ThisWorkbook.Worksheets("Hoge").Visible = xlSheetVeryHidden
End sub
sub シートの再表示()
ThisWorkbook.Worksheets("Hoge").Visible = xlSheetVisible
End sub
'コレクションとは。オブジェクトの集合体。
'rangeコレクションは存在しない。1つのセルでもセル範囲でもRangeオブジェクト。注意。
'セルをコピーするには。
' コピー元のセル.Copy コピー先のセル
sub 非連続セル範囲の選択()
Range("A1,B2,C3,D4").Select
Range("A1:C3,E5:F8").Select
' セル範囲の選択は range("左上セル","右下セル")
Range(Cells(2, 2), Cells(5, 2)).Select
' →For Next構文の中で、
' Range(Cells(i,2), cells(i,5))とすれば条件に合致するデータを行単位で操作できる。
' →Range(cells(i,2), Cells(i,2).end(xltoRight)
End sub
sub 名前が定義されたセルを選択する11()
'セル範囲に売上合計という名前の定義がされていることを前提として
'名前の定義は 右クリックや名前ボックスで行う
Range("売上合計").Select
End sub
sub 行全体や列全体を取得する方法12()
'A列からD列及びF列を取得する
Range("A:D,F:F").Select
'1行目から4行目まで及び6行目を取得する
Range("1:4,6:6").Select
End sub
sub すべてのセルを選択する13()
Cells.Select
End sub
'SelectするにはRangeオブジェクトの親オブジェクト(シートオブジェクト)がアクティブになっている必要がある
sub アクティブシートになっていないRangeはセレクトできない13_2()
Workbooks("hoge.xlsx").Worksheets("Fuga").Range("A1:D30").Select
End sub
sub Rangeをselectするには2段階に分けて親シートをアクティブにしてから13_2()
Workbooks("hoge.xlsx").Worksheets("Fuga").Activate
Range("A1:D25").Select
End sub
sub アクティブシートになくてもセルを1発で選択する13_3()
Application.Goto Workbooks("hoge.xlsx").Worksheets("Fuga").Range("A1:D30")
End sub
'withブロックで、
'With Workbook("").Worksheets("")
'と1行にするか、
'With Workbook("")
' With Worksheets("")
'と入れ子にするかは、Withの中で複数シート触るなら分けた方が良い。
sub Not演算子でプロパティのオンオフ切替14()
'Dr列を
With Columns("D")
'表示のオンオフ切替
.Hidden = Not .Hidden
End With
End sub
'田中亨メモ
'値の設定文やどこかに何かを代入する、というとき
'まず「何を」ではなく、「どこへ」という受け取り側をイメージする。
'VBAの構文①オブジェクト式②ステートメント③関数
'オブジェクト式の基本2文型①対象.命令、②対象.様子 = 値
'操作対象がセルのとき、.Valueは省略できる。読みやすい方を使う。読みやすいかどうかは自分が決めること。
sub セルの数式と値をクリアする19_1()
Range("A1").Select
'activecellプロパティは1つのセル(アクティブセル)を特定し
ActiveCell.Value = ""
End sub
sub セルの内容をクリアする19_2()
Range("A1.D14").Select
'clearcontentsならセル範囲もクリアできる。
'Selectionはアクティブセルも選択セル範囲も特定できる。
'選択セルの数式と値をクリアする
Selection.Value.ClearContents
'選択セルの書式クリア
Selection.Value.ClearFormats
'選択セルのコメント削除
Selection.Value.CcearComments
'選択セルの数式、値、コメント、書式すべて削除
Selection.Value.ClearContents
End sub
sub 選択セル範囲の位置を変更する20()
Range("C2:D6").Select
Selection.Offset(-1, 2).Select
End sub
sub 選択セル範囲の行位置を変更する21()
Range("C2:D6").Select
'0を省略できるからといって省略したら読みにくい
Selection.Offset(-1, 0).Select
End sub
sub 選択セル範囲の列位置を変更する22()
Range("C2:D6").Select
'0を省略できるからといって省略したら読みにくい
Selection.Offset(0, 2).Select
End sub
sub VBAにはLookupがないのでデータベース上で特定のセルを発見してOffsetでズラす22_2()
'結果としてA1セルを選択している
Range("B2").Offset(-1, -1).Select
End sub
sub VBAにはLookupがないのでデータベースのセル範囲の中からCellsで選ぶ22_3()
'結果としてA1セルを選択している
Range("A1:C3").Cells(1, 1).Select
End sub
'行を特定するRowsプロパティは、行を表すRangeオブジェクトを返す
sub 行を非表示にする23()
Worksheets("Hoge").Rows("5:7").Hidden = True
End sub
sub Rowsプロパティは離れた行を選択できない23_2()
' 離れた行を掴もうとするとエラーになる
Rows("1:3,6:6").Select
'Rangeの方がスゴイ
Range("1:3,6:6").Select
End sub
sub 選択されているセル範囲の行数を数える24()
Range("B5:D8").Select
MsgBox Selection.Rows.Count
'Rowプロパティは選択されているセルの行番号(整数)を返すプロパティ。RowじゃなくてRowNumberだったら分かりやすかった。
MsgBox Range("C8").Row
'cf. rowsプロパティは行を表すRangeオブジェクトを返すプロパティ。全く違う。
End sub
sub 選択されているセル範囲の列数を数える25()
Range("B5:D8").Select
MsgBox Selection.Columns.Count
'columnプロパティは選択されているセルの列番号(整数)を返すプロパティ。columnじゃなくてcolumnNumberだったら分かりやすかった。
MsgBox Range("C8").Column
'cf. columnsプロパティは列を表すRangeオブジェクトを返すプロパティ。全く違う。
End sub
sub 行数や列数が取得できたらセル範囲のサイズを変更する26()
Range("B2:C4").Select
MsgBox "選択セル範囲のサイズを変更します"
'選択されているセル範囲の行数と列数を求めてから加減する
Selection.Resize(Selection.Rows.Count + 2, Selection.Columns.Count - 1).Select
'selection.rowsとselection.columnsはrangeオブジェクトを返している
'selectionを使わないで書くと
Range("B2").CurrentRegion.Resize(Range("B2").CurrentRegion.Rows.Count + 2, Range("B2").CurrentRegion.Columns.Count - 1).Select
End sub
sub 表全体の行数から見出しの1行分小さくリサイズして1段下げる26_2()
' resizeの引数の列数を省略すると変更前と同じになる
Range("A1").CurrentRegion.Resize(Range("A1").CurrentRegion.Rows.Count - 1).Offset(1, 0).Select
End sub
'セルのデータ初期化に使いやすい
sub 表全体の行数から見出しの1行分小さくリサイズして1段下げる26_3()
With Range("A1").CurrentRegion
.Resize(.Rows.Count - 1).Offset(1, 0).ClearContents
End With
End sub
sub offset関数のやっていること27()
Range("B2:C4").Select
MsgBox "選択セル範囲のサイズを変更します"
'resizeの引数の行数(列数)を省略すると、変更前と同じになる。
Selection.Offset(0, 2).Resize(, Selection.Columns.cout + 2).Select
End sub
'アクティブセル領域とは。空白の行と空白の列に囲まれたセル範囲のこと。
'アクティブセル領域は、currentRegionプロパティで特定できる。
sub アクティブセル領域を選択する28()
Range("B2").CurrentRegion.Select
End sub
sub データベース範囲を選択する29()
'1行目の見出し行のセルには文字(見出し)が入力されているので基点セルとする。
'2行目以降だと1件もデータがない可能性がある。基点セルは見出し行のセルでなければダメ。
'見出し行を基点にする
Range("A1").CurrentRegion.Select
End sub
sub データ弁ス範囲を印刷する30()
Range("A1").CurrentRegion.Name = "顧客"
'ここでは、印刷は念のためコメントアウトしておく
'ActiveSheet.PrintOut
'印刷プレビュー
ActiveSheet.PrintPreview
End sub
sub データの登録件数を取得31()
MsgBox Range("A1").CurrentRegion.Rows.Count - 1
End sub
sub データの新規入力行を取得31_2()
MsgBox Range("A1").CurrentRegion.Rows.Count + 1
End sub
'Excelの機能「Endモード」 ctrキーでEndモードになる。マクロ辞書でCtrと矢印をすればEnd(xup)とかのEndプロパティを調べられる。
sub データベースの特定の行を選択する31_3()
'5行目のデータを選択するとする。
'Range(左上、右下)を使うと以下。
Range("A5", Range("A5").End(xlToRight)).Select
End sub
sub エンドモードで最終データが入力されているセルに移動する33()
Dim 最終行番号 As Long: 最終行番号 = ActiveSheet.Rows.Count
Cells(最終行番号, 1).End(xlUp).Select
End sub
'
'cells(rows.Count,1).end(xlup) とは、
'activesheet.cells(acivesheet.rows.Count,1).end(xlup) のことだったのである。
'cells(i,42)と書くよりも、Cells(i,"AB")と書いた方が読みやすい。数え間違いもない。
sub データが入力されている範囲を操作する33_3()
Dim i As Long
'for next のループで操作するためにendモードを使って最終データセルに移動してからその行番号を数える。
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
' Cells(i,1)に対する処理
' Cells(i,2)に対する処理
Next i
End sub
'やりがちな間違い
' With Sheets("データベース")
' For i = 1 To .Cells(Rows.Count, 1).End(xlUp).Row
' Cells(i,1)に対する処理
' Cells(i,2)に対する処理
' Next i
' End With
' 解説
' 上記の「.Cells」の親オブジェクトはデータシートなのに、
' (Rows.Count, 1).End(xlUp).Selectの「Rows.count」の親オブジェクトはactivesheetなのでズレてる。
'正しくは、rowsの前にも「.」をつけて
'With Sheets("データベース")
' For i = 1 To .Cells(.Rows.Count, 1).End(xlUp).Row
' Cells(i,1)に対する処理
' Cells(i,2)に対する処理
' Next i
'End With
sub 新規データを入力するセルに移動する34()
Dim 最終行番号 As Long: 最終行番号 = ActiveSheet.Rows.Count
Cells(最終行番号, 1).End(xlUp).Offset(1, 0).Select
End sub
'新規データ入力はOffsetで。
sub 新規データを入力するセルに移動する34_2()
Dim 最終行番号 As Long: 最終行番号 = ActiveSheet.Rows.Count
With Cells(最終行番号, 1).End(xlUp)
' .offset(1,0)=...
' .offset(1,1)=...
' .offset(1,2)=...
' .offset(1,3)=...
End With
End sub