VBAを使用したMicrosoft Excelのルーチン自動化

すべてにご挨拶。



この投稿では、さまざまなルーチンを自動化するために、VBAとは何か、Microsoft Excel 2007/2010でVBAを使用する方法(古いバージョンの場合、インターフェイスのみが変更され、コードはほとんど同じになる)を説明します。






VBA(Visual Basic for Applications)は、多くのMicrosoft Office製品に組み込まれているVisual Basicの簡易バージョンです。 特定のドキュメントのファイルにプログラムを直接書くことができます。 さまざまなIDEをインストールする必要はありません-デバッガーを含むすべてが既にExcelにあります。



Visual Studio Tools for Officeを使用して、C#でマクロを記述し、それらを埋め込むこともできます。 FireStormに感謝します



私はすぐに言わなければならない-他の言語(C ++ / Delphi / PHP)での書き込みも可能ですが、オフィスファイルの読み取り、変更、書き込みの方法を学ぶ必要があります-ドキュメントに埋め込むことはできません。 また、MicrosoftインターフェイスはCOMを介して機能します。 すべての恐怖を理解するために、COMを使用したHello Worldを紹介します。



したがって、悲しいかな、Visual Basicを学習します。



少しの準備と問題の説明


行きましょう。 Excelを開きます。



まず、開発者パネルをリボンに追加しましょう。 フォームを構築するためのボタン、テキストフィールド、その他の要素が含まれています。





タブが表示されました。





ここで、VBAを研究する例について考えてみましょう。 最近、表のように見える価格表をうまく整理する必要がありました。 Googleにアクセスし、「価格表」を入力して、次のように装飾されたものをダウンロードします(広告の場合は考慮しないでください)。





つまり、商品を組み合わせることができる少なくとも2つのグループが必要です(この場合、これらはこの順序でタイプメーカーになります)。 提案したアルゴリズムが正しく機能するように、1つのグループの商品が最初に並んでいるように商品を並べ替えます(最初にType 、次にManufacturer )。



達成したい結果は次のようになります。





もちろん、コンピューターでのみ価格表を見る場合は、フィルターを追加できます。適切な製品を検索する方がはるかに便利です。 ただし、コーディング方法を学びたいので、タスクは非常に適切です。



コディム


最初にボタンを作成する必要があります。クリックすると、プログラムが呼び出されます。 ボタンは「開発者」パネルにあり、「挿入」ボタンに表示されます。 ボタンフォームコンポーネントが必要です。 クリックして、シートの任意の場所に置きます。 さらに、マクロ宛先ウィンドウが表示されない場合は、右クリックして「マクロの割り当て」項目を選択する必要があります。 FormatPriceと呼びましょう。 マクロ名の前に何もないことが重要です。そうしないと、ブックの名前空間ではなく、別のモジュールで作成されます。 この場合、選択したシートにすばやくアクセスすることはできません。 「新規」ボタンをクリックします。





そして、ここではVB開発環境にいます。 また、コンテキストメニューから「ソーステキスト」/「コードの表示」コマンドを使用して呼び出すこともできます。





スタブプロシージャのあるウィンドウを次に示します。 デプロイできます。 コードは次のようになります。



Sub FormatPrice()

End Sub



Hello Worldを書きましょう。



Sub FormatPrice()
MsgBox "Hello World!"
End Sub



そして、ボタンをクリックする(以前に選択を削除する)か、エディターから直接F5を押すことで開始します。



ここでは、おそらく、VBの構文に関する小さな教育プログラムに気を取られるはずです。 誰が知っているか、彼はこのセクションを最後まで安全にスキップできる。 Visual BasicとPascal / C / Javaの主な違いは、コマンドが分離されていないことです。 ただし、実際に1行に複数のコマンドを記述したい場合は、改行またはコロン( :)を使用します。 構文の基本的なルールを理解するために、抽象的なコードを提供します。



構文例

' .
' VBA
Sub foo(a As String , b As String )
' Exit Sub ' " "
MsgBox a + ";" + b
End Sub

' . Integer
Function LengthSqr(x As Integer , y As Integer ) As Integer
' Exit Function
LengthSqr = x * x + y * y
End Function

Sub FormatPrice()
Dim s1 As String , s2 As String
s1 = "str1"
s2 = "str2"
If s1 <> s2 Then
foo "123" , "456" '
End If

Dim res As sTRING ' VB . ,
Dim i As Integer
'
For i = 1 To 10
res = res + CStr(i) ' String
If i = 5 Then Exit For
Next i

Dim x As Double
x = Val( "1.234" ) '
x = x + 10
MsgBox x

On Error Resume Next ' -
x = 5 / 0
MsgBox x

On Error GoTo Err ' Err
x = 5 / 0
MsgBox "OK!"
GoTo ne

Err:
MsgBox "Err!"

ne:
On Error GoTo 0 '

' ,
Do While True
Exit Do

Loop 'While True
Do 'Until False
Exit Do
Loop Until False
' , , .
' Val Integer
Select Case LengthSqr(Len( "abc" ), Val( "4" ))
Case 24
MsgBox "0"
Case 25
MsgBox "1"
Case 26
MsgBox "2"
End Select

' .
' ReDim (Preserve) - . google
Dim arr(1 to 10, 5 to 6) As Integer
arr(1, 6) = 8

Dim coll As New Collection
Dim coll2 As Collection
coll.Add "item" , "key"
Set coll2 = coll ' Set
MsgBox coll2( "key" )
Set coll2 = New Collection
MsgBox coll2.Count
End Sub


熊手-1。 IDEからコードを(英語のExcelで)コピーすると、すべてのテキストが1252 Latin-1に変換されます。 したがって、ロシア語のコメントを保存する場合は、ワニをLatin-1として保存し、1251で開く必要があります。



レーキ2。 なぜなら VBでは未宣言の変数を使用できます。OptionExplicitは常にコードの先頭(すべての手順の前)に配置します。 このディレクティブは、インタープリターがそれ自体で変数を開始するのを防ぎます。



すくい3。 グローバル変数は、最初の関数/プロシージャの前でのみ宣言できます。 ローカル-プロシージャ/ファンクション内の任意の場所。



InPosMidTrimLBoundUBoundといった便利な追加機能がいくつかあります。 また、関数の操作/そのパラメーターに関するすべての質問に対する回答は、MSDNで入手できます。



これで、コードを怖がらず、自分でコンピューターサイエンスの宿題を書くのに十分であることを願っています。 投稿中に、目立たないように新しいデザインを紹介します。



私たちはExcelの下でたくさんコーディングします


このパートでは、Excelのシートで機能するもののコーディングを既に開始します。 まず、 resultという名前の別のシートを作成します(データシートはdataと呼ばれます )。 さて、おそらく、このシートの内容をクリアする必要があります。 また、データシートを「選択」して、シートを使用して配列に長い呼び出しを書き込まないようにします。



Sub FormatPrice()
Sheets( "result" ).Cells.Clear
Sheets( "data" ).Activate
End Sub



セル範囲を操作する


Excel VBAでのすべての作業は、セル範囲で行われます。 それらはRange関数によって作成され、タイプRangeのオブジェクトを返します。 彼はデータやデザインを扱うのに必要なすべてを持っています。 ところで、シートのCellsプロパティもRangeです。



範囲の

Sheets( "result" ).Activate
Dim r As Range
Set r = Range( "A1" )
r.Value = "123"
Set r = Range( "A3,A5" )
r.Font.Color = vbRed
r.Value = "456"
Set r = Range( "A6:A7" )
r.Value = "=A1+A3"


それでは、コードのアルゴリズムを理解しましょう。 したがって、2番目から始まるデータシートの各行には、興味のないデータ( ID名前 、および価格 )があり、それが属する2つのネストされたグループ( typeおよびmanufacturer )があります。 さらに、これらの行はソートされます。 新しいグループを始める前にギャップを忘れてしまいますが、それは簡単です。 私はこのようなアルゴリズムを提案します:



  1. 次の行からグループをカウントしました。
  2. すべてのグループを優先度の高い順に並べます(最初の大きなグループ)
    1. 現在のグループが一致しない場合、 AddGroup(i、name)プロシージャを呼び出します。ここで、 iはグループ番号(現在の番号から最大まで)、 nameはその名前です。 ヘッダーだけでなく、すべてのヘッダーを作成するには、いくつかの呼び出しが必要です。
  3. 必要なヘッダーをすべて描画した後、別の行を作成してデータを入力します。


作業を簡素化するために、次の削減関数を定義することをお勧めします。



Function GetCol(Col As Integer ) As String
GetCol = Chr(Asc( "A" ) + Col)
End Function

Function GetCellS(Sheet As String , Col As Integer , Row As Integer ) As Range
Set GetCellS = Sheets(Sheet).Range(GetCol(Col) + CStr(Row))
End Function

Function GetCell(Col As Integer , Row As Integer ) As Range
Set GetCell = Range(GetCol(Col) + CStr(Row))
End Function



次に、グローバル変数「現在の行」を定義します: Dim CurRow As Integer 。 手順の始めに、それは統一に等しくする必要があります。 また、変数「 データの現在の行」、現在の前の行のグループ名を持つ配列が必要です。 次に、「行の最初のセルが空でない間に」サイクルを書くことができます。



グローバル変数

Option Explicit '
Dim CurRow As Integer
Const GroupsCount As Integer = 2
Const DataCount As Integer = 3


フォーマット価格

Sub FormatPrice()
Dim I As Integer ' data
CurRow = 1
Dim Groups(1 To GroupsCount) As String
Dim PrGroups(1 To GroupsCount) As String

Sheets( "data" ).Activate
I = 2
Do While True
If GetCell(0, I).Value = "" Then Exit Do
' ...
I = I + 1
Loop
End Sub


次に、 グループ配列にデータを入力する必要があります



省略記号の代わりに

Dim I2 As Integer
For I2 = 1 To GroupsCount
Groups(I2) = GetCell(I2, I)
Next I2
' ...
For I2 = 1 To GroupsCount ' VB
PrGroups(I2) = Groups(I2)
Next I2
I = I + 1


そしてヘッダーを作成します:



前の部分の省略記号の代わりに

For I2 = 1 To GroupsCount
If Groups(I2) <> PrGroups(I2) Then
Dim I3 As Integer
For I3 = I2 To GroupsCount
AddHeader I3, Groups(I3)
Next I3
Exit For
End If
Next I2


AddHeaderプロシージャを忘れないでください。



フォーマット前価格

Sub AddHeader(Ty As Integer , Name As String )
GetCellS( "result" , 1, CurRow).Value = Name
CurRow = CurRow + 1
End Sub


次に、すべての情報を結果に転送する必要があります



For I2 = 0 To DataCount - 1
GetCellS( "result" , I2, CurRow).Value = GetCell(I2, I)
Next I2



列を幅に合わせ、 結果シートを選択して結果を表示します



FormatPriceの最後のループの後

Sheets( "Result" ).Activate
Columns.AutoFit


それだけです 最初のバージョンを楽しむことができます。





glyいですが、それはそうです。 フォーマットを処理しましょう。 まず、 AddHeaderプロシージャを変更します。



Sub AddHeader(Ty As Integer , Name As String )
Sheets( "result" ).Range( "A" + CStr(CurRow) + ":C" + CStr(CurRow)).Merge
'
' With
With GetCellS( "result" , 0, CurRow)
.Value = Name
.Font.Italic = True
.Font.Name = "Cambria"
Select Case Ty
Case 1 '
.Font.Bold = True
.Font.Size = 16
Case 2 '
.Font.Size = 12
End Select
.HorizontalAlignment = xlCenter
End With
CurRow = CurRow + 1
End Sub



すでに良い:





境界を描くためだけに残っています。 ここでは、すでにすべての結合されたセルを操作する必要があります。そうでない場合は、1つだけが境界線を持ちます。





したがって、境界線スタイルを追加してコードをわずかに変更します。



Sub AddHeader(Ty As Integer , Name As String )
With Sheets( "result" ).Range( "A" + CStr(CurRow) + ":C" + CStr(CurRow))
.Merge
.Value = Name
.Font.Italic = True
.Font.Name = "Cambria"
.HorizontalAlignment = xlCenter

Select Case Ty
Case 1 '
.Font.Bold = True
.Font.Size = 16
.Borders(xlTop).Weight = xlThick
Case 2 '
.Font.Size = 12
.Borders(xlTop).Weight = xlMedium
End Select
.Borders(xlBottom).Weight = xlMedium ' : xlThick, xlMedium, xlThin, xlHairline
End With
CurRow = CurRow + 1
End Sub





新しいグループを開始する前にパスを達成するためだけに残ります。 これは簡単です:



FormatPriceの開始時

Dim I As Integer ' data
CurRow = 0 '
Dim Groups(1 To GroupsCount) As String


見出しループで

If Groups(I2) <> PrGroups(I2) Then
CurRow = CurRow + 1
Dim I3 As Integer




まさに彼らが望んだもの。



この記事が、VBAのExcelプログラミングに少し慣れるのに役立つことを願っています。 宿題-見出し「 ID、タイトル、価格 」を結果に追加します。 ヒント: CurRow = 0 CurRow = 1



ファイルはここ (min.us)またはここ (Dropbox) からダウンロードできます。 マクロの実行を有効にしてください。 誰かが人間のファイルホスティングを促す場合は、そこにアップロードします。



ご清聴ありがとうございました。


コメントで建設的な批判ができればうれしいです。


UPD: Dropboxとmin.usでサンプルリロードしました。


UPD2:実際には、 1つのパラメーターを使用してプロシージャを呼び出すときに、括弧を付けることができます。 または、 Call Fooコンストラクト(「bar」、1、2、3)を使用します -ここでは、ブラケットが常に必要です。

Source: https://habr.com/ru/post/J112080/


All Articles