外部変形作成講座で使用した
教材(検証3)の解説
(no3.xlsのVBAを解説、Excel2000を元にしています)

VBAが超初心者の方にはチョット理解しづらい部分もあるかと思いますが、理解出来ない部分にぶつかった時は遠慮なくご質問下さい。金公もいまだに初心者の域を脱出出来ないでいますが、出来るかぎり解答させて頂こうと思 っていますので、よろしくお願い致します。

VBAの入口

エクセルに限らず、Windows プログラムには、一つの事を実現するのに複数の命令方法があります。すべての方法を知っているのに越したことはないけど、一つも知らなければ前に進みようがありません。この先 、金公の方法と違う方法も存在することをご承知置きの上解説をご覧下さい 。

まず、なにはともあれVBAプログラムが初めての方にとっては何処にプログラムを書けばいいかも解らないですよね、そのあたりから始めようと思います。

それと用語もその都度、ある程度の内容で書いていきます。
VBAとは、Visual Basic for Application といい、マイクロソフト社のプログラム開発言語のひとつです。ここではエクセルにおまけで付いてくる物とお考え下さい。 おまけのくせにすごいことが出来るので、使わない手はありません。
そして、VBAプログラムを作成するお道具やソースを書き込むところを Visual Basic Editor といいます。

早速、Visual Basic Editor (以下VBEと記します)を開いてみましょう。

エクセルを起動した状態で [ Alt + F11] キーを叩いてみて下さい。VBE が起動してきたでしょう。VBE は独立したソフトのような振る舞いを見せます。検証3での動作 ではエクセルが顔を見せませんよね。そのようにエクセルを無視したような動作をさせることも出来るのです。金公はVBAが主であり、ワークシートはおまけの存在と感じています。ちなみに、別売のVBでもほとんど同じインターフェイスです し、動作も大差ありません。部分的にはVBAの方がまさっている事もあります。

VBEは以下の図のような顔をしていて、大きく3つのエリアに分かれています。
左上はプロジェクトといいい、現在のブックの構成を表しています。ワークシートが3枚ある事が解りますよね。ワークシートの下にあるThisWorkbookは自分自身を表しています。
プロジェクトの下はプロパティーでオブジェクトの各要素のプロパティーを設定する事が出来ます。
右のエリアがプログラムの作業場です。
この三つのエリアを使ってプログラムしていくわけですが、画面構成もカスタマズ出来ますので自分好みの配置で結構です。
下の図では既にThisWorkbookのソースコードを書き込む準備が出来ていますが、この状態にするにはプロジェクト内のThisWorkbookと書かれた文字をダブルクリック します。すると作業エリアに新たな窓が現れてくるので、その窓の左上プルダウンからWorkbookを選択してください。窓内に自動的にマクロの名前が書き込まれます。
1行目のOption Explicit は「変数の宣言を強制する」という意味のコードで、自分で直接書き込むことが出来ますが、ツール→オプションでカスタマズしておくと、新規にコードを書こうとすると き、自動で書き込ませるようにすることも可能です。書かなくてもいいけど、これを書いておくといろんな場面で作者のミスによる間違いを見つけてくれるので、書き込んでおいたほうがいいです。
 


 

右のプルダウンボックスに [ Open ] と書かれていますが、これの意味はエクセルが起動したときに自動的に読みに行く場所で、下の Private Sub Workbook_Open() からEnd Sub までの間に書かれたコード(命令)を実行します。
早速、検証3で書いてある最初のコードを以下のように書き込んで下さい。
 
Option Explicit

Private Sub Workbook_Open()
    start
    Application.Quit
End Sub
このソースコードの意味を文章に書き換えると、

1行目 変数の宣言を強制した状態である。
2行目 エクセルが起動したときに自動的にここを読み実行せよ。
3行目 start と云うサブマクロを探してそこに書かれてある内容を実行せよ。
4行目 エクセルを強制終了せよ。
5行目 命令はここでおしまいだ。

と云う内容です。

Workbook_Open のような、「何かしたとき」を感じ取ってプログラムが走るようなマクロを「イベントマクロと云います」
「何かした」 = イベント と云うことですね。


ここで no3.bat の最終行にあるエクセルを呼び出すバッチコマンドも簡単に説明しておきます。 これはバッチコマンドですからエクセルのVBAとは別物ですが。


REM 金公の超初心者外変検証3
@echo off
REM #jww
REM #cd
REM #h4
REM #e
start /MIN /WAIT EXCEL.EXE no3.xls
 


エクセル(EXCEL.EXE no3.xls)を最小化した状態で(/MIN)、起動せよ(start)、そしてエクセルが終了するまで待て(/WAIT)。という命令です。

--------------------------------------------
【 全体の流れ 復習もかねて 】

■ 呼び出された外部変形プログラムはJw_cadの画面情報を [ JWC_TEMP.TXT ] に書込する。
■ その後、[ JWC_TEMP.TXT ] を加工させる為にエクセルを起動させる。
■ エクセルはその外部変形プログラムの指令をうけて起動する。
■ 起動時に実行しなければならない命令を自分でソースコードを読み始める。

---- ここからエクセルの作業 -------------

■ 既に情報の書かれた[ JWC_TEMP.TXT ] を読み込む。
■ その内容から線分情報の個数を調べる。(直線が何本あるか。)
■ 線の個数が解れば、その個数(回数)分、あるマクロを繰り返す

---- あるマクロ の内容 ------------------

■ 1個の線情報を4つに分けて専用の入れ物に入れる(元の開始点XY座標と終了点座標XY)
■ 専用の入れ物に分けられた1本の線情報(座標2点)から正方形を作る為の未知の座標2点を計算させる
■ 計算結果を入れる入れ物は正方形を形成する為の元の線分を除いた3本の線情報なので3×4=12個の入れ物に入れていく。
■ 各1本の線情報である2点の座標値(X、Y)をJw_cadが認識出来るように半角スペースで区切る形で組立る。
■ 組立られた1本の線情報を専用の入れ物に入れ、元の線分が複数の場合はJw_cadが認識出来るよう、間に改行コードを付ける。
---------------------------------------

■ それを元線分の個数分繰り返しすべての線情報を一つの文字列にして[ JWC_TEMP.TXT ] に上書き保存する。
■ すべての命令に対する作業をこなしたエクセルは自分で強制終了する。
■ エクセルに託した[ JWC_TEMP.TXT ] 加工作業の終了を待っていた外部変形プログラムは加工済みの[ JWC_TEMP.TXT ] を見ながらJw_cadに作図していく。

以上のような流れで外部変形作業が実行されて行くわけですが、あるマクロの部分で線分の座標値を計算、決定して行くにあたり、正方形を一つ作るだけの場合は気づかないことですが、はじめから正方形が書かれてあるような場合、正常動作で終わっても正方形が作成されていないように見える可能性があります。 重複線になってしまっているからです。原因は線分の開始座標と終了座標の関係を無視したプログラムの時に起こりえます。

----------- 金公が気づいた座標点を指定して線を引くときの問題

線を引くとき左から右へ線を引いたときと右から左に向かって線を引いたときとでは、見た目は同じでもCADの内部で処理されている情報は全然違った物になります。今回の正方形の例から云うと、金公の希望は水平線の上に正方形を作成しようと思いました。上から下に向かって垂直線を引いた場合は右に正方形を作りたいのです。しかし、右から左に向かって水平線を引いた場合、正方形は下に出来るのです。

極論を述べますが、CADは単純です。文字やCADを構成している要素を別として、データ部に限って云うと、どんな複雑な図面でもCADから見ると線情報と円弧情報でしかないのです。ただし、操作する人の考えなど無視して正確な情報を蓄えていきます。その事 への理解が外部変形プログラムの最大の注意点ではないかと思いました。

以上の事をふまえてプログラム中心部、標準マクロ(start)の解説に入ります。

標準マクロはイベントマクロと違い自分で動き出すことはありません。
誰かに呼ばれて動き出すマクロの事を云います。
ソースコードを書き込む場所(モジュール)も違います。
まず、モジュールを表示させましょう。挿入→標準モジュール で作業エリアに新しい窓が出てきます。

標準マクロは、イベントマクロのようにプルダウンから選択して勝手にコードが書き込まれるわけでなく、自分でマクロ名(プロシージャ)を決めて書き込まなくてはなりません。
金公は start と自分の意志で名前を決め書き始めましたが、貴方の好きな名前でいいのです。その時は Workbook_Open 内のマクロ呼出する部分の文字も同じ名前を指定しましょう。

以下、マクロコード内に解説文を直接書き込んでいきます。

------ 標準マクロ ----------------------------------------------------------


Option Explicit

Sub start()
  Dim TmpFile As String
  Dim FileNo As Integer
  Dim x1(3) As Double
  Dim x2(3) As Double
  Dim y1(3) As Double
  Dim y2(3) As Double
  Dim moji() As String
  Dim moji2 As String
  Dim i As Integer
  Dim j As Integer
  Dim Dchck As Boolean
 

Dim は変数の宣言部分で、プログラム内で使用する変数(入れ物)の名前をここで最初に宣言しておくのがルールです。
Dim TmpFile As String は、「この入れ物には文字だけを入れるので、TmpFile と云う名前の入れ物を一つ用意して下さい。」という意味になります。
Integer(整数型) ---- 整数を入れる変数を宣言する時に記述(-32768〜32767の範囲の値が扱える)
Long(長整数型) ---- 整数を入れる変数を宣言する時に記述(-2147483648〜2147483647の範囲の値が扱える)
String(文字列型)----文字列(文字)を入れる変数を宣言する時に記述
Doubl(倍精度浮動小数点数型)-----1.79769313486232E308 〜 -4.94065645841247E-324 (負の値) および 4.94065645841247E-324 〜 1.79769313486232E308 (正の値) の範囲の値が扱える。
Variant(バリアント型) ---- どんな型のデータでも入る入れ物で便利なようですが、数値を入れるべきところに文字を入れてしまっても、その間違いは教えてくれない、と云うような落とし穴があります。メモリも最大 で必要になります。
Boolean (ブール型) ---- 真 (True) または偽 (False) の値を持つデータ型です。

x1(3)とあるのは配列宣言でx1(0)、x1(1)、x1(2)、x1(3)の4つの変数を宣言するのと同じ意味です。
moji()は動的配列で、現時点で数値が指定出来ないが、プログラムの途中でその数値が決定されるような場合に使います。数値が決定された時点で再度宣言します。プログラム内で何度も数値を変えることも可能です。
配列はワークシートのセルに似ています。セルのように計算式を入れることは出来ませんが値を記憶しておくことが出来ます。セルの場合はRange("A1") = 1でA1セルに1と云う数字を入れることが出来ますが、配列の場合だとx1(0,0) = 1と云う感じです。セルは見えることが出来ますが、配列の値はデバッグ中か、見る為のプログラムを作らないかぎり見ることは出来ません。そう考えるとワークシートはよく出来てますよね。
 

TmpFile  = ThisWorkbook.Path & "\JWC_TEMP.TXT"
 
TmpFile と云う名前の入れ物に
自分自身のパスの文字 + \JWC_TEMP.TXT
と云う文字列を入れる。

If Dir(TmpFile , vbNormal) <> vbNullString Then
 

TmpFile(自分自身のパスの文字 + \JWC_TEMP.TXT)が実在する場合、以下の命令を実行せよ。
 

    i = 0
    FileNo = FreeFile
    Open TmpFile For Input As #FileNo
    Dchck = False
    Do While Not EOF(1)
      Line Input #FileNo, moji2
      If Dchck = True Then i = i + 1
      If moji2 = "#" Then Dchck = True
    Loop
    Close FileNo
 
 i と云う、整数用の入れ物に 0 を入れて初期化。
FileNo に JWC_TEMP.TXTを開くにあたり、空いているファイル番号を指定する
JWC_TEMP.TXTを開く(メモリ上に)
Dchck にFalseを入れる(フラグを下げるとも云うらしい)
開いたファイルの最後の行まで繰り返せ(繰り返し作業開始)
1行だけ取り出して moji2 へ入れる
もし、DchckにTrueが入っていれば(フラグが立っていたら)以下の命令を実行せよ。(i に1を足す)
もし、moji2の中身が # と云う文字だったらDchckにTrueをいれる(フラグを立てる)
繰り返し作業が終わったら、読み込んでいる JWC_TEMP.TXT をメモリ上から解放

ここでの作業は以下につづく動的配列に入れるために元の線分の数を調べる(数えるための部分)のが目的です。
結果は i に線分の個数が入ります。


    If i = 0 Then Exit Sub
    ReDim moji(i - 1)
    j = 0
 
もし、線分が1本もなかったら以下のマクロを実行せずこのプロシージャから出なさい。
動的配列mojiに線分の個数をいれる。
 jを初期化。

動的配列に線分の個数を入れる際( i - 1 )となっているのは線分の個数は1から始まるが、配列は0から始まるので1を引かないと実際の線分個数と配列に入れる個数の数が合わなくなる為です。

    Dchck = False
    Open TmpFile For Input As #FileNo
    Do While Not EOF(1)
      Line Input #FileNo, moji2
      If Dchck = True Then
DchckにFalseを入れる。
再度、JWC_TEMP.TXTをメモリ上に開く
最終行まで繰り返せ(繰り返し開始)
moji2 に1行取り込む
もし、DchckにTrueが入っていれば(フラグが立っていたら)以下の命令を実行せよ。

と、ここまでは先ほどのマクロとほぼ同じことをしています。

          moji2 = Trim(moji2)
          x1(0) = Val(Left(moji2, InStr(moji2, " ") - 1))
          moji2 = Mid(moji2, InStr(moji2, " ") + 1)
          y1(0) = Val(Left(moji2, InStr(moji2, " ") - 1))
          moji2 = Mid(moji2, InStr(moji2, " ") + 1)
          x2(0) = Val(Left(moji2, InStr(moji2, " ") - 1))
          y2(0) = Mid(moji2, InStr(moji2, " ") + 1)          
 
取り込んだ線分1本の座標値データの前後のスペースを取り除く(念のため)
x1(0)と云う配列変数に開始座標xの値を入れる。

JWC_TEMP.TXTに書かれてある数字は数値ではなく文字なので、Val関数で文字を数値に変換している。
x1(0)は数値を入れると宣言しているので、文字のまま入れるとエラーになります。
なぜ、数値に変換するかと云うと、このあとこの値を足し算や引き算するからです。
以降、各変数y1(0)、x2(0)、y2(0)に1本の線分情報を取り込む。
 
         x1(1) = x1(0)
          y1(1) = y1(0)
          x2(1) = x1(0) + y1(0) - y2(0)
          y2(1) = y1(0) + x2(0) - x1(0)
          moji(j) = x1(1) & " " & y1(1) & " " & x2(1) & " " & y2(1)
 
新たに作成する3本の直線の1本目の座標を決める。
x1(1)、y1(1)には1本目の線分開始点のX、Y座標値を入れるわけですが、元の線分の開始座標値を代入しています。
と云うことは、元の線分が水平線だと仮定した場合、新たな線分を上から下じゃなく、下から上に向かって作図しようとしているのがお解りでしょうか。「座標点を指定して線を引くときの問題」と説明したのはこのことなのです。
x2(1) = x1(0) + y1(0) - y2(0)は小学生の算数「図形の合同」などを思い出して欲しいです。とにかくこの式により未知の座標点を知ることが出来ます。(小学生の算数は高度な事をしてるわ、金公は苦手です)
こうして出来た1本目の線分を表す座標データをJw_cadが認識出来る半角スペースで挟んで4つのデータを文字の動的配列moji(j)に代入して、記憶させておきます。

          x1(2) = x2(0) + y1(0) - y2(0)
          y1(2) = y2(0) + x2(0) - x1(0)
          x2(2) = x2(0)
          y2(2) = y2(0)
          moji(j) = moji(j) & vbCrLf & x1(2) & " " & y1(2) & " " & x2(2) & " " & y2(2)
 
新たに作成する3本の直線の2本目の座標を決める。
今度は、元の線分の終点座標と今作成する終点座標が同じになるようにしています。元の線分が水平線だと仮定するなら、上から下へ向かって作図する線分です。
出来た2本目の線分を表す座標データを1本目と同様Jw_cadが認識出来る半角スペースで挟んで4つのデータを文字の動的配列moji(j)に代入するわけですが、全く先程と同様のコードだと上書きされてしまい、1本目の線分座標データは消えてしまいます。又1本目の線分データと2本目の線分データの間には改行も必要です。
そういった場合、プログラムでは[ 変数 = 変数 & vbCrLf & 新データ ] と云う書き方が出来るのです。[ vbCrLf ]は改行コードの事です。そうして2本の線分座標データを記憶させておきます。

          x1(3) = x2(1)
          y1(3) = y2(1)
          x2(3) = x1(2)
          y2(3) = y1(2)
          moji(j) = moji(j) & vbCrLf & x1(3) & " " & y1(3) & " " & x2(3) & " " & y2(3)
 
3本目の線分は新たに作られた座標点同士をつなぐわけですから、既に出来上がっている座標点を指定してやります。
そして2本目同様のコードで3本目を追加した文字列として配列moji(j)に記憶させておきます。

          j = j + 1
       End If
     If moji2 = "#" Then Dchck = True
    Loop
 
元の線分の1本に対する正方形の座標データは記憶を完了しましたので、元の線分2本目を取り込む為の準備としてjに1を足し、次の作業に入り、それを元の線分の個数だけ繰り返し作業を行い、すべての元の線分に対する正方形の座標データを 配列内に記憶していきます。

Dchck が Falseであるかぎり、線分の計算や記憶作業は行われず、If moji2 = "#" Then Dchck = True の部分へいきなりやってきてmoji2のデータに"#"が入っているかチェックします。


    Close FileNo
 
繰り返し作業を抜けたら、メモリ上からJWC_TEMP.TXTを解放します。

    Open TmpFile For Output As #FileNo
    For j = 0 To i - 1
      Print #FileNo, moji(j)
    Next j
 
いよいよプログラム終盤です。すべての元の線分に対する正方形の配列内に記憶した座標データを書き出していきます。
Open TmpFile For Output As #FileNo の Output は上書きモードでテキストファイルを開くときに使用します。
 j が 0 から i - 1 になるまで(元の線分の数だけ)繰り返せ。
記憶してある元の1本分の線分に対する正方形の座標データを書き込め。
最後まで繰り返せ。

    Close #FileNo
 
繰り返し作業を抜けたら、メモリ上からJWC_TEMP.TXTを解放し、同時に上書き保存。

  End If

End Sub
 

プロシージャ start のすべてのプログラムは終了、呼出元である Workbook_Open に制御をうつす。
その後、Workbook_Open 内のstartの次の行 Application.Quit が実行されエクセルは終了。
それを待っていた外部変更プログラム(no3.bat)が JWC_TEMP.TXT のデータが変更されていることを関知して JWC_TEMP.TXT のデータを元に Jw_cad に作図開始。
外部変形プログラムの終了。

以上で検証3の解説は終了です、お疲れさまでした。

目 次

Home

 


Copyright (C) 2003/3 F.Tohyama, All rights reserved.


あなたは累計
人目の訪問者です。

(本日は   番目のアクセスです。 また昨日は 人のご来場者がありました)