外部変形作成講座で使用した
教材(検証3)の解説
(no3.xlsのVBAを解説、Excel2000を元にしています)
VBAが超初心者の方にはチョット理解しづらい部分もあるかと思いますが、理解出来ない部分にぶつかった時は遠慮なくご質問下さい。金公もいまだに初心者の域を脱出出来ないでいますが、出来るかぎり解答させて頂こうと思 っていますので、よろしくお願い致します。 |
VBAの入口 |
エクセルに限らず、Windows
プログラムには、一つの事を実現するのに複数の命令方法があります。すべての方法を知っているのに越したことはないけど、一つも知らなければ前に進みようがありません。この先
、金公の方法と違う方法も存在することをご承知置きの上解説をご覧下さい
。 まず、なにはともあれVBAプログラムが初めての方にとっては何処にプログラムを書けばいいかも解らないですよね、そのあたりから始めようと思います。 それと用語もその都度、ある程度の内容で書いていきます。 早速、Visual Basic Editor (以下VBEと記します)を開いてみましょう。 エクセルを起動した状態で [ Alt + F11] キーを叩いてみて下さい。VBE が起動してきたでしょう。VBE は独立したソフトのような振る舞いを見せます。検証3での動作 ではエクセルが顔を見せませんよね。そのようにエクセルを無視したような動作をさせることも出来るのです。金公はVBAが主であり、ワークシートはおまけの存在と感じています。ちなみに、別売のVBでもほとんど同じインターフェイスです し、動作も大差ありません。部分的にはVBAの方がまさっている事もあります。 VBEは以下の図のような顔をしていて、大きく3つのエリアに分かれています。 |
|
右のプルダウンボックスに [ Open ]
と書かれていますが、これの意味はエクセルが起動したときに自動的に読みに行く場所で、下の Private Sub Workbook_Open()
からEnd Sub までの間に書かれたコード(命令)を実行します。 早速、検証3で書いてある最初のコードを以下のように書き込んで下さい。 |
Option Explicit Private Sub Workbook_Open() start Application.Quit End Sub |
このソースコードの意味を文章に書き換えると、 1行目 変数の宣言を強制した状態である。 と云う内容です。 Workbook_Open のような、「何かしたとき」を感じ取ってプログラムが走るようなマクロを「イベントマクロと云います」
|
|
エクセル(EXCEL.EXE no3.xls)を最小化した状態で(/MIN)、起動せよ(start)、そしてエクセルが終了するまで待て(/WAIT)。という命令です。 -------------------------------------------- ■ 呼び出された外部変形プログラムはJw_cadの画面情報を [ JWC_TEMP.TXT ] に書込する。 ---- ここからエクセルの作業 -------------
■ 既に情報の書かれた[ JWC_TEMP.TXT ] を読み込む。 ---- あるマクロ の内容 ------------------
■ 1個の線情報を4つに分けて専用の入れ物に入れる(元の開始点XY座標と終了点座標XY) ■ それを元線分の個数分繰り返しすべての線情報を一つの文字列にして[ JWC_TEMP.TXT
] に上書き保存する。 以上のような流れで外部変形作業が実行されて行くわけですが、あるマクロの部分で線分の座標値を計算、決定して行くにあたり、正方形を一つ作るだけの場合は気づかないことですが、はじめから正方形が書かれてあるような場合、正常動作で終わっても正方形が作成されていないように見える可能性があります。 重複線になってしまっているからです。原因は線分の開始座標と終了座標の関係を無視したプログラムの時に起こりえます。 ----------- 金公が気づいた座標点を指定して線を引くときの問題 線を引くとき左から右へ線を引いたときと右から左に向かって線を引いたときとでは、見た目は同じでもCADの内部で処理されている情報は全然違った物になります。今回の正方形の例から云うと、金公の希望は水平線の上に正方形を作成しようと思いました。上から下に向かって垂直線を引いた場合は右に正方形を作りたいのです。しかし、右から左に向かって水平線を引いた場合、正方形は下に出来るのです。 極論を述べますが、CADは単純です。文字やCADを構成している要素を別として、データ部に限って云うと、どんな複雑な図面でもCADから見ると線情報と円弧情報でしかないのです。ただし、操作する人の考えなど無視して正確な情報を蓄えていきます。その事 への理解が外部変形プログラムの最大の注意点ではないかと思いました。 以上の事をふまえてプログラム中心部、標準マクロ(start)の解説に入ります。 標準マクロはイベントマクロと違い自分で動き出すことはありません。
標準マクロは、イベントマクロのようにプルダウンから選択して勝手にコードが書き込まれるわけでなく、自分でマクロ名(プロシージャ)を決めて書き込まなくてはなりません。 以下、マクロコード内に解説文を直接書き込んでいきます。 ------ 標準マクロ ---------------------------------------------------------- |
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 をメモリ上から解放
ここでの作業は以下につづく動的配列に入れるために元の線分の数を調べる(数えるための部分)のが目的です。 |
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 に制御をうつす。 以上で検証3の解説は終了です、お疲れさまでした。 |
目 次 |
Copyright (C) 2003/3 F.Tohyama, All rights reserved.
あなたは累計 |
|
人目の訪問者です。 |
(本日は |
|
番目のアクセスです。 また昨日は |
|
人のご来場者がありました) |