プログラミング系のネタをまとめていきます。

基本

グローバル定数


Private Const CONST_VAL_0 = 10
Public Const CONST_VAL_1 = 20	' Public 定数は宣言できないっぽい。エラーになる。

Const CONST_STR As String = "文字列定数"

列挙型


Public Enum ParamType
    None = 0
    TypeInt = 1
    TypeStr = 2
End Enum

Null関連

vbNullStringString型の初期値
EmptyVariant型の初期値。何も値が入っていない状態。
Null
(vbNull)
Variant型に格納できる特殊な値。
Nothingオブジェクト変数の初期値
Empty

Dim myVar As Variant
Debug.Print VarType(myVar)   '--> 0(定数vbEmpty)と表示される
Debug.Print TypeName(myVar)  '--> Empty と表示される
Debug.Print IsEmpty(myVar)   '--> True と表示される

Dim myVar As Variant                    '初期値はEmpty
If myVar = 0 Then Debug.Print "True"    '--> True と表示される
If myVar = "" Then Debug.Print "True"   '--> True と表示される
Null

Dim myVar As Variant        '初期値はEmpty
myVar = Null                'Nullを代入
Debug.Print VarType(myVar)  '--> 1(定数vbNull)と表示される
Debug.Print TypeName(myVar) '--> Null と表示される
Debug.Print IsNull(myVar)   '--> True と表示される
Nothing

オブジェクトの初期状態を判定して処理する。
If myObj Is Nothing Then
    Set myObj = Forms![フォーム1]
End If

構造体


Type Point
    x As Long
    y As Long
End Type

関数

返り値呼び出し
Sub無しCall Subプロシージャ
Functionあり(Call) Functionプロシージャ
Subプロシージャ

Sub Test()
	Dim str As String
	str = "text"
	Call SubTest(str)
End Sub

Sub SubText(str As String)
	MsgBox "テキスト : " + str
End Sub

プロシージャの途中でリターンするときは、Exit Subを使う。

Functionプロシージャ

Call ステートメントでの呼び出しも可能。

Sub Test()
	Dim v As Integer
	v = FuncAdd(10, 20)
End Sub

Function FuncAdd(a As Integer, b As Integer) As Integer
	FuncAdd = a + b		' 計算結果を返す
End Function

プロシージャの途中でリターンするときは、Exit Functionを使う。

引数の参照渡し

Sub Test()
	Dim str As String
	str = "text"
	Call Func(str)
End Sub

Sub Func(ByVal a As String)
   a = "suzuki"         ' 受け取った値を書き換える
End Sub

TextBoxを引数として渡す

Sub TestFunc(textBox As MSForms.textBox)
    textBox.Text = "text"
End Sub

基本処理

文字列→数値変換


Dim a As String
Dim v As Integer
a = "123"
v = val(a)

数値→文字列変換


Dim a As Integer
Dim t As String
a = 123
t = str(a)

文字列比較

同値判定

If ActiveCell.Value = "text" Then
	MsgBox "等しい"
Else
	MsgBox "等しくない"
End If

If ActiveCell.Value <> "text" Then
	MsgBox "等しくない"
Else
	MsgBox "等しい"
End If
文字列が含まれているかどうか

If InStr(ActiveCell.Value, "text") > 0 Then
	MsgBox "含まれている"
Else
	MsgBox "含まれていない"
End If

パターンマッチ

Like、「*」、「?」 を使って判定する。

' abc, xyz の間に任意の文字列が入ってもOK
If ActiveCell.Value Like "abc*xyz" Then	'

' 1〜5で始まる文字列
If ActiveCell.Value Like "[1-5]*" Then

' 都道府県名のうち、北海道、東京都、神奈川県、和歌山県、鹿児島県 以外がtrueになる
If Not c.Value Like "??[県府]" Then

Windows API 呼び出し


' kernel32.dllのGetTickCount()を使えるようにする
Private Declare Function GetTickCount Lib "kernel32" () As Long

Sub test()
  MsgBox GetTickCount
End Sub

コレクション、動的配列

可変長リスト


Dim list As Collection
Set list = New Collection

' listに要素を追加する
Dim col As Integer
col = 1
Do While ActiveSheet.Cells(1, col) <> ""
	list.Add ActiveSheet.CelllS(1, col)
	col = col + 1
Loop

' リストの要素を順に処理する
Dim str As String
str = ""
For Each v In list
	str = str & v.Value
Next

Dictitonary


Dim dict As Scripting.Dictionary
Set dict = CreateObject("Scripting.Dictionary")

dict.Add "A1", ActiveSheet.Cells("A1")
dict.Add "A2", ActiveSheet.Cells("A2")
dict.Add "A3", ActiveSheet.Cells("A3")

Dim key As Variant
For Each key In dict.Keys
	Debug.Print key, dict(key).Value
Next

Excel操作

Rangeを起点に選択

オフセット指定

Dim r As Range
Set r = ActiveSheet.Range(Cells(1, 1), Cells(3, 3))	' 3x3 を選択
r.Offset(1,1).Select ' 3x3の範囲を行、列方向に+1移動した範囲が選択される
Rangeの一部を選択

Dim r As Range
Set r = ActiveSheet.Range(Cells(1, 1), Cells(3, 3))	' 3x3 を選択
r(1,1).Select ' 3x3の左上1セルを選択
r(0,0).Select ' 3x3の左上からさらに1行1列左上のセルを選択

セル範囲を選択


Sub Test()
	' 現在のActiveSheetに対して操作
	Range(Cells(1,1), Cells(3,3)).Select	' 選択する
End Sub

セルの幅と高さを変更


Sub Test()
	' 現在のActiveSheetに対して操作
	Range(Cells(1,1), Cells(3,3)).ColumnWidth = 5	' ポイント指定
	Range(Cells(1,1), Cells(3,3)).RowHeight = 5		' ポイント指定
	' 同じポイント数でも、セルの形状が正方形になるとは限らない。
	' 環境によって縦横比が違う。
End Sub

セルを正方形にする


Sub Test()
	' ColumnWidthをセットした後、そのセルのWidthをRowHeightにセットすると、正方形になる?
	Range(Cells(1, 1), Cells(3, 3)).ColumnWidth = cellSize
	Range(Cells(1, 1), Cells(3, 3)).RowHeight = Cells(1, 1).Width
End Sub

※動作を把握できていないので、後ほど調査する。

シート内の使用中最終セルを取得


'A1セルを基準にして最終列を求める
Set rangeEnd = ActiveSheet.Range("A1").SpecialCells(xlLastCell)

セルの検索


Dim rangeS As Range
Set rangeS = ActiveSheet.Cells.Find("検索したい文字列", 
                                    LookIn:=xlValues, 
                                    LookAt:=xlWhole, 
                                    SearchOrder:=xlByRows, 
                                    MatchCase:=True, 
                                    MatchByte:=True)
参考サイト

その他のセル検索

行、列方向にセルの切れ目を検索

Range("A1").End(xlDown)   ' 下方向にセルの値の有り/無しが切り替わる直前まで検索
Range("A1").End(xlRight)  ' 右方向にセルの値の有り/無しが切り替わる直前まで検索
指定したセルを起点に、データが格納されている範囲を選択

Range("C3").CurrentRegion.Select

ユーザーフォームを作成


とりあえず…

テクニック

テキストボックスの入力を数値のみにする


Private Sub TextBox1_Change()
    If Len(TextBox1.Text) = 0 Then
        Exit Sub
    End If
    
    ' 一番右の文字が数値であれば何もしない
    If IsNumeric(Right(TextBox1.Text, 1)) = True Then
        Exit Sub
    End If
    
    ' 数値でなかった場合、その一文字を削る
    TextBox1.Text = Left(TextBox1.Text, Len(TextBox1.Text) - 1)
End Sub

※問題点:テキストボックス内でカーソルを移動し、数値の中間で数値以外の文字を入力できてしまう。
  • 参考サイト
http://www.moug.net/tech/exvba/0150021.html

フォーム関連

モードレスフォーム

フォームを表示する際に、vbModelessを指定します。

UserForm1.Show vbModeless
  • 参考サイト
http://www.shoeisha.com/book/hp/pc/office/Excel/fi...

シート上のアクティブセルを取得


ActiveCell.Address

カーソル位置のセルが返ってきます。
"A1" という形式。

マウス座標を取得

フォームのMouseMoveイベントから

マウスカーソルがフォーム上に存在するときにイベントが発生し、座標を取得できます。
フォーム外では取得できません。
デスクトップの左上を(0,0)とした値になります。

' 2次元座標構造体
Private Type POINT
    x As Long
    y As Long
End Type

' API宣言
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINT) As Long

' フォームのMouseMoveイベント
Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal y As Single)
    Dim p As POINT
    Dim msg As String
    
    ret = GetCursorPos(p)
    msg = "(" & p.x & "," & p.y & ") - (" & x & "," & y & ")"
    LabelMousePos.Caption = msg
End Sub
  • 参考サイト
http://www5d.biglobe.ne.jp/~tomoya03/shtml/vbapi/C...

罫線を引く


Private Sub DrawBorder(r As Range)
    With r
    	' 実線
        .Borders(xlEdgeTop).LineStyle = xlContinuous		' 選択範囲の上辺
        .Borders(xlEdgeBottom).LineStyle = xlContinuous		' 選択範囲の下辺
        .Borders(xlEdgeRight).LineStyle = xlContinuous		' 選択範囲の右辺
        .Borders(xlEdgeLeft).LineStyle = xlContinuous		' 選択範囲の左辺
        ' 太線
        .Borders(xlEdgeTop).Weight = xlMedium
        .Borders(xlEdgeBottom).Weight = xlMedium
        .Borders(xlEdgeRight).Weight = xlMedium
        .Borders(xlEdgeLeft).Weight = xlMedium
    End With
End Sub
線の位置
xlDiagonalDown
右下がり斜め
xlEdgeTop
上辺
xlDiagonalUp
j右上がり斜め
xlEdgeLeft
左辺
xlInsideHorizontal
内側水平線
xlInsideVertical
内側垂直線
xlEdgeRight
右辺
xlEdgeBottom
下辺
線の種類
xlContinuous実線
xlDash破線
xlDashDot一点鎖線
xlDashDotDot二点鎖線
xlDot点線
xlDouble二重線
xlSlantDashDot斜め一点鎖線
xlLineStyleNone無し
線の太さ
xlHairlineごく細
xlThin細い
xlMedium
xlThick太い

名前定義


Dim r As Range ' 名前定義に登録したいセル範囲
ActiveWorkbook.Names.Add Name:="名前", RefersTo:=r

入力規則(プルダウンリスト)


Dim r As Range ' 入力規則を設定したいセル範囲
With r.Validation
    ' 設定済みの入力規則を削除する
    .Delete
    
    ' 設定
    .Add Type:=xlValidateList,      ' リストからの値を設定
         Formula1:="=定義した名前"  ' 名前定義からの指定。セル範囲等の指定も可能。
End With
実行時エラー'1004'

「実行時エラー '1004' : アプリケーションの定義またはオブジェクト定義のエラー」
が発生する原因。
  • セル範囲は複数行、複数列ではダメ。単一の列、行である必要がある。


クラスモジュール


C++やJavaのクラスに当たるもの。

作り方


Visual Basic Editor(VBE)の [挿入] - [クラスモジュール] で新規作成。
追加されたクラスモジュールを選択して、プロパティの (オブジェクト名)で名前変更。


●TestClass
Private v0 As Integer
Private v1 As Integer

Public Sub SetParam(a As Integer, b As Integer)
    v0 = a
    v1 = b
End Sub

Public Sub Output()
    MsgBox "add : " & (v0 + v1) & vbCrLf & "sub : " & (v0 - v1)
End Sub


●呼び出し
Dim testClass As TestClass
Set testClass = new TestClass

Call testClass.SetParam(10, 20)
Call testClass.Output

外部プログラム呼び出し


外部プログラムを呼び出せます。
パラメータを渡したり、実行結果を受け取ったり出来ます。

Exec


Execは実行結果を受け取りたいときに使用します。

Runのように、外部プログラム呼び出し時にそのウィンドウを非表示にする制御は出来ないようです。
Runは表示/非表示等のウィンドウの制御が出来ます。


●外部プログラムを実行し、コンソールに出力される情報を1行ずつ取得してセルに書き込むサンプル。

    Dim wsh, exec As Object
    Set wsh = CreateObject("WScript.Shell")
    
    Dim command As String
    command = "dir /B"
    Set exec = wsh.exec("%ComSpec% /c " + command)
    
    Dim items As Variant
    Dim count As Integer
    count = 0
    
    ' 実行結果を1行ずつ読み込んでセルに出力する
    Dim lineStr As String
    Do Until exec.StdOut.AtEndOfStream
        lineStr = exec.StdOut.ReadLine
        ActiveSheet.Cells(count + 1, 1).value = lineStr
        count = count + 1
    Loop
    
    Set exec = Nothing
    Set wsh = Nothing


●外部プログラムを実行し、処理が全て終わってから標準出力をまとめて取得する

Private Declare Sub Sleep Lib "kernel32" (ByVal waitTime As Long)	' WindowsAPIの宣言。ソース先頭の方で宣言しておく

    Dim wsh, exec As Object
    Set wsh = CreateObject("WScript.Shell")
	
    Dim command As String
    command = "ipconfig"
    Set exec = wsh.exec("%ComSpec% /c " + command)
    
    ' 外部プログラムが終了するまでループする
    Do Until exec.Status
      Sleep 10
    Loop
    
    ' 標準出力をまとめて取得する
    result = exec.StdOut.ReadAll
    
    Set exec = Nothing
    Set wsh = Nothing

参考サイト


MS-DOSコマンドの標準出力を取得する
http://officetanaka.net/excel/vba/tips/tips27.htm

VBAで外部プログラムを非表示で実行するには
※DoEvents は使わずに、Sleep 推奨という話題です。
http://okwave.jp/qa/q8490086.html
タグ

Menu

メインコンテンツ

プログラミング

機器

Macツール

各種情報

Wiki内検索

おまかせリンク

Androidアプリ

AdSense

技術書


管理人/副管理人のみ編集できます