前回の
BricsCAD VBAを使ってみよう[3] UserFormその2
からの続篇です。
VBAの検討を進めていくときに参考として、①マクロVBAの構成と②BricsCADのコマンドの構文を、そのつどあれこれ調べるのも時間がかかりますので、忘備録で順次こちらに残してくようにします。(時間が経つとけっこういろいろと忘れますので)
1,VBマクロの構成
1,各モジュールへのプロシージャの配置
VBマクロのコード記述場所
ThisDrawing内のコードはこの図面内でのクラスモジュール
ユーザーフォームはフォームモジュールを使用
汎用的な活用では標準モジュールを使用
2,メインルーチンとサブルーチン
モジュール内で実行する(メインルーチンの)プロシージャ内で、一度に長いプログラムを作成すると、プログラムの「可読性」が低くなり、バグが混入しやすくなり、バグの原因特定やバグフィックスに時間が掛かる原因になります。
「可読性」を高くする一つの手段として、サブルーチン化して、そのプロシージャを呼び出すCallステートメントを使用します。呼び出す側のメインルーチンと対比してサブルーチンと呼ばれます。
次のコード例では、test_2とtest_3はtest_1に呼び出されるサブルーチンです。
サブルーチンのプロシージャは、Private Sub・・・としておくと、マクロの一覧には表示されません。
Option Explicit Dim sBuf As String Sub test_1() Call test_2 Call test_3 End Sub Private Sub test_2() sBuf = "テスト2" MsgBox (sBuf) End Sub Private Sub test_3() sBuf = "テスト3" MsgBox (sBuf) End Sub
3,プロシージャ間のスコープ
Publicで宣言したプロシージャはすべてのモジュール間で有効となります。
Moduleを分けて、別のModuleからFunctionプロシージャを呼び出せます。
他の作成したVBAマクロで、共通の処理が行えるプロシージャを使いまわしができるようになります。
Option Explicit Sub test_4() Dim txt As String txt = "テスト4" MsgBox (addtxt(txt)) End Sub
Option Explicit Public Function addtxt(txt As String) As String addtxt = txt & "を確認しました" End Function
2,変数の型
データ型 | 変数の範囲 | |
Byte | バイト型 | 0~255の範囲の単精度の正の数値 |
Long | 長整数型 | -2,147,483,648 ~ 2,147,483,647 |
Single | 単精度浮動小数点数型 | -3.402823E38 から -1.401298E-45 (負の値) 1.401298E-45 から 3.402823E38 (正の値) |
Double | 倍精度浮動小数点数型 | -1.79769313486231E308 から -4.94065645841247E-324 (負の値)4.94065645841247E-324 から 1.79769313486232E308 (正の値) |
String | 文字列型 | 0 〜 約 20 億 |
Boolean | ブール型 | 真 (True) または偽 (False) |
Object | オブジェクト型 | オブジェクト |
Variant | バリアント型 | すべてのデータ |
上記以外その他の変数型もありますが、
主に使用するデーター型
整数:Long
小数:Double
文字列:String
真・偽:Boolean
配列、オブジェクト Variant
変数はDim
Dim “変数名” As “データー型”
定数はConst
Const “変数名” As “データー”=”値”
3,プロシージャ間の「値渡し」と「参照渡し」
プロシージャが持つ値に、「変数」「定数」「式」がありますが、通常は「変数」を引き渡します。
引き渡す値に「値渡し:ByVal」と「参照渡し:ByRef」があります。
Option Explicit Dim Cnt As Integer Sub test_9() Cnt = 1 Call test_10(Cnt) MsgBox (Cnt) End Sub ''Private Sub test_10(ByVal Cnt As Integer) Private Sub test_10(ByRef Cnt As Integer) Cnt = Cnt + 1 End Sub
Sub test_10の、CntでMsgBox (Cnt)は、
ByVal の場合・・・・1
ByRef の場合・・・・1+1で2
となります
数字だけでなく文字列でも同様です。
ByValを指定すると値が渡され、ByRefを指定すると(処理後の)参照が渡されます。
・・・それほど複雑な大きなプログラムは組みませんので、subプロシージャ間でやり取りする程度では(無いとエラーになる場合を除いて)特には気にしません。しかし関数のFunctionプロシージャは、内部で引数で処理して戻り値を渡す作業を行いますので注意が必要です。
Function プロシージャ名(引数 As データ型) As 戻り値のデータ型
プロシージャ名=戻り値
End Function
戻り値がなかったり、引数がなかったり引数が複数の場合があります。
変数に関しては、まだ記載しておきたいこともありますが、以降の検討中に記載するようにします。
検討していたお題で面白そうなテーマで・・・
4,キーボードのイベントを取得するsubプロシージャ
テンキー入力のイベントを取得し作図するコード例
このコード例では、テンキー入力のイベントを取得する、GetAsyncKeyState関数を使用しています。
例えば、
If GetAsyncKeyState(vbKeyNumpad0) Then・・・・で、
テンキーの0が押されているか、押されたを示す値が返ります。
【テンキー入力 → 挿入点クリック → 指示した数の同心円を描画】
Option Explicit 'Win32API宣言(64bit) 'キー情報関数 Declare PtrSafe Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer Dim keynum As Long Sub GetTenKey() Dim Pt() As Double keynum = 0 On Error Resume Next ''図形挿入基準点を指示 Pt = ThisDrawing.Utility.GetPoint(, "テンキー入力:挿入点をクリック ") Call Getkeynum ''キャンセルの場合 If Err Then ''エラー処理を戻す On Error GoTo 0 Exit Sub End If ''MsgBox (keynum) Dim myCircle As AcadCircle Dim dHeight As Double dHeight = 100 Set myCircle = ThisDrawing.ModelSpace.AddCircle(Pt, dHeight) Dim offsetObj As Variant Dim i As Byte ''円の間隔を文字高さの1/10にする For i = 1 To keynum offsetObj = myCircle.Offset(dHeight / 10 * i) Next '作図図形範囲にZoom ThisDrawing.Application.ZoomExtents '図面を更新 ThisDrawing.Application.Update End Sub Private Sub Getkeynum() If GetAsyncKeyState(vbKeyNumpad0) Then keynum = 0 ElseIf GetAsyncKeyState(vbKeyNumpad1) Then keynum = 1 ElseIf GetAsyncKeyState(vbKeyNumpad2) Then keynum = 2 ElseIf GetAsyncKeyState(vbKeyNumpad3) Then keynum = 3 ElseIf GetAsyncKeyState(vbKeyNumpad4) Then keynum = 4 ElseIf GetAsyncKeyState(vbKeyNumpad5) Then keynum = 5 ElseIf GetAsyncKeyState(vbKeyNumpad6) Then keynum = 6 ElseIf GetAsyncKeyState(vbKeyNumpad7) Then keynum = 7 ElseIf GetAsyncKeyState(vbKeyNumpad8) Then keynum = 8 ElseIf GetAsyncKeyState(vbKeyNumpad9) Then keynum = 9 End If End Sub
実行直後に、先にテンキーで追加する繰り返し描画回数を指示します。画面をクリックすると同心円を描きます。
ここではテンキーで追加する円の数を決めて描きますが、テンキーだけでなくほかのキーも使え、その他何らかの処理をするのに面白そうです。
5,Functionで「ByVal」と「ByRef」使用の例
前述の「値渡し:ByVal」と「参照渡し:ByRef」の参考コードです。
2点をクリックしてその間隔を計測します。
Option Explicit Sub Get2PointsDistance() Dim gp1 As Variant, gp2 As Variant On Error Resume Next Do gp1 = ThisDrawing.Utility.GetPoint(, "1点目をクリック : ESCで終了 ") 'キャンセルの場合 If Err Then On Error GoTo 0 Exit Sub End If gp2 = ThisDrawing.Utility.GetPoint(, "2点目をクリック: ") MsgBox ("2点間は " & Calcdist(gp1, gp2) & " ㎜です") Loop End Sub Function Calcdist(ByRef gp1 As Variant, ByRef gp2 As Variant) As Double Dim x As Double, y As Double, z As Double x = gp1(0) - gp2(0): y = gp1(1) - gp2(1): z = gp1(2) - gp2(2) Calcdist = Sqr((Sqr((x ^ 2) + (y ^ 2)) ^ 2) + (z ^ 2)) End Function
でも・・・実は、CAD本体のVBAでひらえるんです。。。
まぁ、それはそれ、これはこれとして。。。
Option Explicit Sub Get2PointsDistance() Dim Distance As Double Distance = ThisDrawing.Utility.GetDistance(, "2点をクリックして計測") MsgBox "2点間は " & Distance & " ㎜です" End Sub
6,Win32API関数
Windows APIはWindowsの各機能にアクセスするための機能を提供します。
上記の例で、テンキー入力を取得・コード実行を一時中断していますが、その他多種多様な機能の関数があり、VBAの動作の幅を広げることにとても有用です。
使用するうえでの注意点として、VBAのバージョンで記述が異なることです。
MSOffice2007以前では、VBA 6.x用の記述(32bit)
MSOffice2010以降では、VBA 7.x 用の記述(32bit/64bit両対応)
(現在使用中のMSOffice2019でもVBA 7.1ですね)
VBA 7.x 用の記述リファレンスの参考資料として、Microsoft公式のもので下記のヘルプファイルがダウンロードできます。
「Office 2010 Help Files: Win32API_PtrSafe with 64-bit Support」
の下の赤いボタンをクリックしてダウンロード
ダウンローされたSitemapCreator5Setup.exeをダブルクリック
Cドライブ直下に解凍されます。
→Office 2010 Developer Resourcesフォルダー
→Documentsフォルダー
→Office2010Win32API_PtrSafeフォルダー内に
以下のファイルがあります。
VBA 7.x 用の記述は、解凍したファイルの中の「Win32API_PtrSafe.TXT」内に記載されています。(テキストファイルをPDFにして検索して使っています。)
GetAsyncKeyStateを検索すると、
と出てきます。
上記のコードです。
Declare PtrSafe Function GetAsyncKeyState Lib “user32” Alias “GetAsyncKeyState”(ByVal vKey As Long) As Integer
VBEのコードウインドウにこのコードを張り付けると・・・・
Declare PtrSafe Function GetAsyncKeyState Lib “user32” (ByVal vKey As Long) As Integer
になります。(のでそのまま使っています。)
たぶん、なんだぁ同じ名前じゃないかぁ~!とおこられてるんですね。
呼び出し宣言の書式
Declare PtrSafe Function 関数名 Lib “DLL名” Alias “API名” (引数…) As 戻り値の型
PtrSafe キーワード(64bitVBAにコンパイルする)
DeclareステートメントにはPtrSafeキーワードを含める必要があります。 PtrSafe キーワードは、Declare ステートメントを 64 ビットの開発環境で安全に実行できることを示すキーワードです。
関数名
基本的にC言語で宣言されたAPIと同じものを使用します。
Lib キーワード
Libの後に、呼び出す関数を含む DLL の名前と場所を指定します。
Alias キーワード
API名がDLLの中では別の名前で公開されている場合は、Alias 節で公開されている関数名を宣言します。
例えばウィンドウのキャプションタイトルを取得するAPIは
Declare PtrSafe Function GetWindowText Lib “user32” _
Alias “GetWindowTextA” (ByVal hwnd As Long, _
ByVal lpString As String, ByVal cch As Long) As LongPtr
となります。
ウインドウ関係のAPIでは、Alias が使われています。
アドレス参照(ポインターおよびハンドルを格納する場合) の引数は、32Bit版では、Long型ですが、64Bit版では、LongPtr型 または Longlong型になる・・・とのことらしいです。。。
と、いろいろ調べながら進めています。
次ページでは、(すでにいろいろと使ってますが)繰り返し動作、分岐処理について検討しました。
BricsCAD VBAを使ってみよう[5] VBAの基本コード②
今回の件で、VBAでいろいろと考えている中で、Win32APIがVBAと共に使いこなせれば面白そうだなぁと思いました。テンキー以外でもスペースとか使えそうですね。
ちょっとした操作でも数があれば、少しでもさっと処理ができると、とてもメリットがあります。
またいろいろと調べて、ほかの機能も組み込んでいけるようにしたいです。
BricsCAD VBAを使ってみよう INDEX
BricsCAD VBAを使ってみよう[1] VBAのインストール
BricsCAD VBAを使ってみよう[2] UserFormその1
「BricsCAD VBA 」Creating UserForm
BricsCAD VBAを使ってみよう[3] UserFormその2
「BricsCAD VBA 」SerialNumber drawing with UserForm
BricsCAD VBAを使ってみよう[4] VBAの基本コード①
BricsCAD VBAを使ってみよう[5] VBAの基本コード②
BricsCAD VBAを使ってみよう[6] Excelとの連携①
「BricsCAD VBA to Excel」Get_CoordinateValues
BricsCAD VBAを使ってみよう[7] Excelとの連携②
「Excel VBA to BricsCAD」Get_Area
BricsCAD VBAを使ってみよう[8] Excelとの連携②-2
「Excel VBA to BricsCAD」Draw_ChannelSteel
BricsCAD VBAを使ってみよう[9] TABLEの自動作成と値入力
「BricsCAD VBA 」AutomaticCreation of TABLE
BricsCAD VBAを使ってみよう[10] Excelとの連携②-3
「Excel VBA to BricsCAD」SerialNumber_Ⅱ
BricsCAD VBAを使ってみよう[11] Excelとの連携②-4
「Excel VBA to BricsCAD」Draw_Rectang
BricsCAD VBAを使ってみよう[12] Excelとの連携②-5 指定画層にOffset
「Excel VBA to BricsCAD」Continuous Offset to Specified Layer
BricsCAD VBAを使ってみよう[13] Excelとの連携②-6 指定画層にHATCH
「Excel VBA to BricsCAD」Continuous Hatch to Specified Layer
以下検討中です。
◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
「この特集記事の内容につきましては、
こちらの環境のみの検討結果です。
動作保証は出来かねますため、ご参考
資料としてお扱いください。
Windows10(64bit)
BricsCAD pro V20(64bit)
Office2019(64bit)
◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇