情 19 演習問題 解説 問題 1 (1) Dim i, j As Long, D As Double (2) Skjt
by user
Comments
Transcript
情 19 演習問題 解説 問題 1 (1) Dim i, j As Long, D As Double (2) Skjt
情 19 演習問題 解説 問題 1 (1) Dim i, j As Long, D As Double (2) Skjt$ = Cells(2, 1) (3) Sub CircleDraw(X0 As Single, Y0 As Single, R As Single) (4) i% = 10 (5) Dim Nserial, YoubiIndex As Integer, Youbi As String <Ans.> (1)i : F j : B D:D (2)Skjt : E (3)X0 : C Y0 : C (4)i : A (5)Nserial : F YoubiIndex : A Youbi : E <解説> 情 10 参照。基本なのでちゃんと覚えてください。宣言を省略、あるいは空欄にすると Variant 型になるこ と、変数名の後に&や!など特定の記号を付ける型決定の仕方があることに注意。 ※問題の例にもあるように、変数名の文字を大文字にして定義すると、マクロ本文で変数名を全て小文字で 入力したときに Excel が自動でその文字を大文字に直してくれる。つまり、大文字にならない変数名は定義 されてない、あるいはスペルミスがあるということ。趙初歩的だけど、バグ取りには有効な手段なので活用 するといいかも。 問題 2 Sub Test() '西暦年、月、何回目の何曜日かを入力したとき、 'それが何日であるかを求める。 Dim Seireki As Integer, Tsuki As Integer, Kaisu As Integer Dim Youbi As String, Hi As Integer, HiIni As Integer Dim Nserial, YoubiIndex1 As Integer, YoubiIndex2 As Integer (メモ) (メモ) Seireki、Tsuki、Kaisu は整数 Youbi は文字列、Hi、HiIni は整数 Nserial はバリアント型、YoubiIndex1、2 は整数 'データ入力 Seireki = Cells(1, 1).Value Tsuki = Cells(2, 1).Value Kaisu = Cells(3, 1).Value Youbi = Cells(4, 1) '_____________________________________________________(1)↓ Select Case Youbi Case "日" YoubiIndex1 = 1 Case "月" YoubiIndex1 = 2 Case "火" YoubiIndex1 = 3 Case "水" YoubiIndex1 = 4 Case "木" YoubiIndex1 = 5 Case "金" YoubiIndex1 = 6 Case "土" YoubiIndex1 = 7 Case Else MsgBox "日∼土までのいずれかの曜日を入力して下さい。" YoubiIndex1 = 0 End Select '_____________________________________________________(1)↑ If YoubiIndex1 <> 0 Then '_____________________________________________________(2)↓ HiIni = 1 (メモ) セル A1 の値を Seireki に代入 セル A2 の値を Tsuki に代入 セル A3 の値を Kaisu に代入 セル A4 の内容を Youbi に代入 (メモ) Youbi に代入されたデータによる場合分け Youbi に日が代入されている場合 1 を YoubiIndex1 に代入 Youbi に月が代入されている場合 2 を YoubiIndex1 に代入 Youbi に火が代入されている場合 3 を YoubiIndex1 に代入 Youbi に水が代入されている場合 4 を YoubiIndex1 に代入 Youbi に木が代入されている場合 5 を YoubiIndex1 に代入 Youbi に金が代入されている場合 6 を YoubiIndex1 に代入 Youbi に土が代入されている場合 7 を YoubiIndex1 に代入 Youbi に上記以外または空が代入されている場合 メッセージの表示 0 を YoubiIndex1 に代入 場合分け終了 (メモ) 条件 A:YoubiIndex に 0 以外が代入されている場合 (メモ) 1 を HiIni に代入 Do '1 日∼7 日の間で該当する曜日になる日を探す。 DoLoop 開始 (メモ) Nserial = DateSerial(Seireki, Tsuki, HiIni) YoubiIndex2 = WeekDay(Nserial) 関数 DateSerial で返された値を Nserial に代入 関数 WeekDay で返された値を YoubiIndex2 に代入 If YoubiIndex2 = YoubiIndex1 Then Exit Do HiIni = HiIni + 1 YoubiIndex2 が YoubiIndex1 と同じ時 DoLoop 終了 HiIni の値を 1 増やす Loop While HiIni < 8 HiIni が 8 未満の間 Do に戻る Hi = HiIni + 7 * (Kaisu - 1) Hi に HiIni + 7 If Hi > 31 Then MsgBox "あり得ない日です。データを修正して下さい。" Else MsgBox "西暦" & Seireki & "年" & Tsuki & "月の第" & _ Kaisu & Youbi & "曜日は" & Hi & "日です。" End If '_____________________________________________________(2)↑ End If (Kaisu - 1)を代入 条件B:Hi の値が 31 以上の時 メッセージを表示 それ以外の時(Hi の値が 31 未満の時) メッセージを表示 条件B終了 (メモ) 条件A終了 End Sub <Ans.> (1)プログラムの部品化(モジュール化) (2)(a)西暦 2005 年 2 月の第 5 水曜日は 30 日です。(b)あり得ない日です。データを修正してください。 (c)西暦 2005 年 8 月の第 5 水曜日は 31 日です。 (3)(a)<例> Function GetYoubi(Youbi As String) Select Case Youbi Case "日" GetYoubi = 1 Case "月" GetYoubi = 2 Case "火" GetYoubi = 3 Case "水" GetYoubi = 4 Case "木" GetYoubi = 5 Case "金" GetYoubi = 6 Case "土" GetYoubi = 7 Case Else MsgBox "日∼土までのいずれかの曜日を入力して下さい。" GetYoubi = 0 End Select 引き継ぐ変数は Youbi(1 つ) 1 を計算結果としてメインプログラムに代入する (以下同じ) End Function (b)<例> Sub GetHi(Seireki As Integer, Tsuki As Integer, Kaisu As Integer, YoubiIndex1 As Integer, Youbi As String) Dim HiIni As Integer, Nserial, YoubiIndex2 As Integer, Hi As Integer 引き継ぐ変数は 5 つ HiIni = 1 Do '1 日∼7 日の間で該当する曜日になる日を探す。 Nserial = DateSerial(Seireki, Tsuki, HiIni) YoubiIndex2 = WeekDay(Nserial) If YoubiIndex2 = YoubiIndex1 Then Exit Do HiIni = HiIni + 1 Loop While HiIni < 8 Hi = HiIni + 7 * (Kaisu - 1) If Hi > 31 Then MsgBox "あり得ない日です。データを修正して下さい。" Else MsgBox "西暦" & Seireki & "年" & Tsuki & "月の第" & _ Kaisu & Youbi & "曜日は" & Hi & "日です。" End If End Sub (4)<例> Sub Test2() '西暦年、月、何回目の何曜日かを入力したとき、それが何日であるかを求める。 Dim Seireki As Integer, Tsuki As Integer, Kaisu As Integer Dim Youbi As String Dim YoubiIndex1 As Integer 'データ入力 Seireki = Cells(1, 1).Value Tsuki = Cells(2, 1).Value Kaisu = Cells(3, 1).Value Youbi = Cells(4, 1) '____________________________________________________________________(1)↓ YoubiIndex1 = GetYoubi(Youbi) 関数 GetYoubi 実行(送る変数は 1 つ) '____________________________________________________________________(1)↑ If YoubiIndex1 <> 0 Then '____________________________________________________________________(2)↓ GetHi Seireki, Tsuki, Kaisu, YoubiIndex1, Youbi サブルーチン GetHi 実行(送る変数は 5 つ) '____________________________________________________________________(2)↑ End If End Sub <解説> ・「2 月って 28 日 or29 日までだから(1)(a)は『あり得ない日です∼』じゃないの?」という声が聞こえて きそうな引っかけ問題…。このプログラムでは、各月がそれぞれ何日までという指定はなく、全て一律に 31 日まであることとして考えていることに気づけるかどうかがポイント。カレンダーを見て考えるのも大切だ けど、基本的にはプログラミングの流れに沿って計算すること。 ・関数 DateSerial は西暦、月、日の 3 つの数字を入力すると、その入力した日が 1900/1/1 から数えて何 日目かということを計算する関数。とんでもない桁数になるので当然バリアント型。 ・関数 WeekDay は DateSerial で求めた 1900/1/1 から数えて何日目かという数字を入力すると、その日 が何曜日かということを計算する関数。結果は日曜日なら 1、月曜日なら 2、…というように出力されるの で、日、月、火、…と表示したければ(3)(a)のような場合分けによる代入を利用する。 ・HiIni + 7 (Kaisu - 1)が何を求める計算かはカレンダーを眺めながら自分で考えよう。 ・関数プロシージャは DateSerial や WeekDay のような複雑な計算をするための関数を自分で作ってみよ う!というイメージ。要するに基本的な仕事は計算なので、メインプログラムに対して何か計算した結果をひ とつだけ送ることができる。送りたい変数名と関数プロシージャの名前を同じにすることを忘れずに! ・サブルーチンプロシージャは同じ作業を何回もやるのは面倒だから外部委託しよう(?)というイメージ。要 するに基本的な仕事は普通のプログラムと一緒。ただし関数プロシージャと違って計算結果をメインプログ ラムに引き継げないことに注意。 ・サブルーチン・関数プロシージャではメインプログラムから引き継いだ数値のデータ型を最初の括弧内で 定義する。メインプログラムで送った変数の数とプロシージャで受け取る変数の数が同じになるよう確認す る。※プロシージャで受け取る側の変数名を仮引数として授業中ではLやMなどにしていたけど、正直なん でもいいんだからメインプログラムと同じ変数名のままでもまるで違う名前にしても全然問題ない。 ・If͐Then の後を改行せずに続けると、End If が省略できる。小ネタ。 ・とりあえずわかんないところがあったら Mizutani 氏に訊ねる。 問題 3 <Ans.> (1) ActiveSheet.Shapes.AddShape(msoShapeOval, 150, 150, 100, 100).Select (2) 354 , 228 (3) ActiveSheet.Shapes.AddShape(msoShapeOval, 250, 255, 90, 90).Select <解説> ・図形のサイズ決めの指令は(図形左上の X 座標 , 図形左上の Y 座標 , 横幅 , 縦幅)という形式。 ・Excel 自身が決めている ワールド座標系 はシートの左上が原点で、右方向が X 軸正、下方向が Y 軸正。 ・x2 + y2 + 10x - 2000 = 0 →(x + 5)2 + y2 = 452 中心(-5 , 0) = 295 , 300 、半径 45 ・とにかく図を書いてみて確認するのが一番。 問題 4 <Ans.> (1)Sleep 100 (2)Kernel32.dll (3)ア.75 イ.左下 ウ.400 エ.200 オ.302 カ.298 キ.Set En1 ク.En1.Delete Private Declare Sub Sleep Lib "kernel32" _ (ByVal dwMilliseconds As Long) Sub Macro1() Dim En1 As Shape, X0 As Single, Y0 As Single X0 = 325 Y0 = 125 kernel32 というライブラリから Sleep という関数を引用 関数 Sleep に送る引数が長整数型で単位はミリ秒 サブルーチンプロシージャ開始 En1 はオートシェイプなど図形、X0・Y0 は単精度浮動小数型 X0 に 325 を代入 Y0 に 125 を代入 i=1 Do Set En1 = ActiveSheet.Shapes.AddShape _ (msoShapeOval, X0, Y0, 150, 150) i に 1 を代入 DoLoop 開始 選択中のシートに円(始点 X0,Y0、横幅 150、縦幅 150)を描き(準備)、 En1 に割り当てる DoEvents Sleep 100 En1 を描く(確定) 100 ミリ秒動作を休止 En1.Delete En1 を消去 i=i+1 X0 = X0 - 2 Y0 = Y0 + 2 i に i + 1 を代入 X0 に X0 - 2 を代入 Y0 に Y0 + 2 を代入 Loop While i <= 50 i が 50 以下の時 Do に戻る End Sub サブルーチンプロシージャ終了 <解説> ・VBA の計算は人間の体感速度からしてみればすっごく早いから、パラパラ漫画を作ろうと思ったら一枚と 一枚の間で VBA には少し休む命令をいれる。Sleep という関数(機能)は VBA が持っている関数ではなく、 Windows 本体が持っている関数なので、VBA 中で使うときにはあらかじめ呼び出す必要がある。最初の行 はその命令。一つ一つ説明するとややこしいので、Sleep を使いたいときは同じモジュール(枠)内にこれも 入れないといけないんだなというくらいで覚えておくだけにとどめておいて大丈夫。(あえて説明すると、 Private は同一モジュール内からのみ参照可能であることを示す宣言、Declare は API 関数を参照すること を示す宣言、Sleep は API 関数の名前、Lib "kernel32"は参照する DLL ファイル名を指している。この一行 だけでもう一つのサブルーチンプロシージャができていることになり、つまり、Sleep 100 とはプログラム の部品化で行ったようにサブルーチンプロシージャ内で別のサブルーチンプロシージャを実行し、その際に 引数として 100 を引き継いでいるということ。) ・いくらオートシェイプをいじくり回す指令を出したところで DoEvents 命令を出さない限りオートシェイ プは変更されていないので注意。 ・49 回目のループで i = 50 、X0 = 325 - 2 49 = 227、Y0 = 125 + 2 49 = 223 となり、50 回目 のループで左上の座標が 227, 223 、中心 302, 298 の円を描き、i = 51 になり Loop を終了する。 ・別のやり方もあるので一応紹介。 Private Declare Sub Sleep Lib "kernel32"(ByVal dwMilliseconds As Long) Sub Macro2() Dim En1 As Shape, X0 As Single, Y0 As Single X0 = 325 Y0 = 125 Set En1 = ActiveSheet.Shapes.AddShape (msoShapeOval, X0, Y0, 150, 150) i=1 Do DoEvents Sleep 100 i=i+1 En1.IncrementLeft -2 右方向に-2 移動 En1.IncrementTop 2 下方向に 2 移動 Loop While i <= 50 En1.Delete End Sub