Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : Excel 2019)
Subroutineの指定
投稿日時: 23/12/06 12:41:35
投稿者: TomVla

これはある半径の円周上に等間隔にとった点を中心にして円を描こうとしています。
全く動作しません。Subrourtineの指定が原因と思われますがよくわかりません。
ご指導お願いします。
 
Sub P11()
    Dim ws As Worksheet
    Dim shp As Shape
    Dim X1 As Single : Dim Y1 As Single
    Dim X2 As Single : Dim Y2 As Single
 
    PI=3.14159 : L=100
    For AL=0 TO 2*PI STEP PI/24
    X1=L*COS(AL)
    Y1=L*SIN(AL)
 
    Set ws = ThisWorkbook.Sheets("Sheet3")
 
    Call Sample2
 
        Set shp = ws.Shapes.AddShape(msoShapeOval, X2, Y2, 80, 80)
    Next
    End Sub
 
    Sub Sample2()
    X2=X1+320
    Y2=-Y1+200
 
End Sub

回答
投稿日時: 23/12/06 13:59:49
投稿者: simple

まずはご自分でステップ実行して、エラー解決をしてください。
無論、こちらで修正は可能ですが、まずはご自分でトライしていただきたいです。
・きちんと変数を宣言してください。
・変数の有効範囲(スコープ)という考え方を調べて下さい。
 

Option Explicit
をモジュールの一行目に挿入するようにして下さい。
そうすれば、今回のような未宣言の変数には警告が出て、
しかも場所を特定してくれますから便利です。
# 皆さんそうされているようですよ(日本人に一番有効な助言方法だそうな)。
 
http://officetanaka.net/excel/vba/beginner/06.htm
を参照してください。それを自動設定する方法も紹介されています。
   VBEの 「ツール」 − 「オプション」 − 「編集」 で
  「変数の宣言を強制する」にチェックを入れてください。
   モジュールを作成した時点で、Option Explicitが自動的に挿入されるので、
   手間が省けます。(今回は手で入力してください。)
   一度だけチェックを入れておきさえすれば、以後、気にする必要はありません。

投稿日時: 23/12/06 14:37:11
投稿者: TomVla

●を追加しましたが「Pi」が「変数」扱いになってるようで「定義されていません」となり進めません。
 
●Option Explicit
Sub P11()
    Dim ws As Worksheet
    Dim shp As Shape
    Dim X1 As Single: Dim Y1 As Single
    Dim X2 As Single: Dim Y2 As Single
 
    Pi = 3.14159: L = 100
    For AL = 0 To 2 * Pi Step Pi / 24
    X1 = L * Cos(AL)
    Y1 = L * Sin(AL)
 
    Set ws = ThisWorkbook.Sheets("Sheet3")
 
    Call Sample2
 
        Set shp = ws.Shapes.AddShape(msoShapeOval, X2, Y2, 80, 80)
    Next
    End Sub
 
    Sub Sample2()
● Dim X1 As Single: Dim Y1 As Single
● Dim X2 As Single: Dim Y2 As Single
 
    X2 = X1 + 320
    Y2 = -Y1 + 200
 
End Sub

回答
投稿日時: 23/12/06 18:30:45
投稿者: simple

Option Explicitは何を意味して、どんな効果があるのか理解されていますか?
参照記事を読まれましたか?
未宣言の変数があれば、それに警告を発する機能があります。
それが発動されているだけだと思います。Pi変数はどこで宣言していますか?
 
(Piというワークシート関数がありますが、
 LeftValueにしているということは、それを使う積りでもなさそうですし、
 使うなら、頭にApplication.なりWorksheetfunction.なりが必要です。)
 
ExcelVBAはN-BASICの上位互換ではないので、N-BASICの動きにすべて対応する
ものではありません。
ExcelVBAを使うなら、それに関する基本的なテキストを学習してください。
N-BASICではこのようにできたのだが、VBAでは動作しない、
といった類の質問を上げられても正直閉口します。
 
・プロシージャレベルの変数とモジュールレベル変数の違い、
・Subプロシージャ(やFunctionプロシージャ)への引数の渡し方、結果の受け取り方
などの基本事項は書籍に書いてありますので、学習してください。
・X1,Y1,X2,Y2をすべてモジュールレベル変数にするか、
・引数として渡すかです。
 
このケースではそもそも別のプロシージャにする必要すら無いと思います。

投稿日時: 23/12/06 20:41:52
投稿者: TomVla

Piは「円周率」で定数のつもりで使用してます。PI=3.14159です。
「Pai」と変えてみても「変数が定義されていません」という応答です。

回答
投稿日時: 23/12/06 21:27:22
投稿者: simple

Piの意図はさすがにこちらも分かってますよ。
>Pi変数はどこで宣言していますか?
に対する返答がいただけていないので、再度おたずねします。
 
変数を宣言していないので、Option Explicitが効いてきて警告が出ているんですよ。
理解されてますか?

回答
投稿日時: 23/12/06 22:13:22
投稿者: MMYS

TomVla さんの引用:
Piは「円周率」で定数のつもりで使用してます。PI=3.14159です。
「Pai」と変えてみても「変数が定義されていません」という応答です。

TomVlaさんのお考えでは、
 Pi
 Pai
は変数ではない。なんでエラー何だろう。とお考えなんですね。だとしたら、何に対して代入されているのですか。そして、変数ではなのなら、定数や関数などの何かなのでしょうか。その何かに対して、なぜ代入が可能とお考えなのでしょう。
  
みなみに、 L 、 AL も変数定義されていません。
あと、Sample2を呼び出してますが、スコープを理解されてますか。
みなみに、VBAは他言語でいうローカル関数は使用できません。
  
なお、円周率なら、WorksheetFunction.Pi が用意されています。
https://learn.microsoft.com/ja-jp/office/vba/api/excel.worksheetfunction.pi

投稿日時: 23/12/07 04:45:43
投稿者: TomVla

Piは例えば下記プログラムと同様に使用しているつもりです。きちんと動作しているのに、なぜ今回はエラーになるのかわかりません。
 
Sub Line08()
    Dim ws As Worksheet
    Dim shp As Shape
 
    Dim X1 As Single, Y1 As Single
    Dim X2 As Single, Y2 As Single
     
    PI = 3.14159265 : D=100
    For A = 0 To 2*PI Step 2*PI/720
     
    E = D*(1+1/4*SIN(12*A))
    F = E*(1+SIN(4*A))
    X1 = 320 + F*Cos(A)
    X2 = 320 + F*Cos(A+PI/5)
    Y1 = 200 - F*Sin(A)
    Y2 = 200 - F*Sin(A+PI/5)
 
    Set ws = ThisWorkbook.Sheets("Sheet3")
     
    Set shp = ws.Shapes.AddLine(X1, Y1, X2, Y2)
 
    Next A
     
    With shp
        .Line.Weight = 2
        .Line.ForeColor.RGB = RGB(0, 0, 255)
    End With
End Sub

回答
投稿日時: 23/12/07 10:19:45
投稿者: simple

(1)
今回提示されているのは、Option Explicitを抜いているからです。
変数は宣言して使った方が、思わぬミスに時間にとられてしまうことを防ぐためにも有効です、
というのが紹介した記事の要点でした。
できるだけ標準的な使い方をされたほうがよいと思います。
 
定数として使うとすれば、

Const Pi  As Single = 3.14159
といったように宣言するのが普通です。
 
Dim Pi As Single
Pi = WorksheetFunction.Pi
などとしてもよいかもしれません。
(なお、ワークシート関数と同じ変数名は避けたほうが無難かもしれないとか、
 全体をDouble型にするとかの考えもあるかもしれません。)
 
(2)
なお、元々のN-Basicですか、それに近いSubroutineということなら、 GoSubでしょうけど、
余りお薦めできません。GoTOをできるだけ避けるのと同じ感覚です。
   (前略)
    For AL = 0 To 2 * pi Step pi / 24
        x1 = L * Cos(AL)
        Y1 = L * Sin(AL)
        GoSub myRoutine
        Set shp = ws.Shapes.AddShape(msoShapeOval, X2, Y2, 80, 80)
    Next
    Exit Sub
myRoutine:
    X2 = x1 + 320
    Y2 = -Y1 + 200
    Return
End Sub
このケースではそもそも
        x1 = L * Cos(AL)
        Y1 = L * Sin(AL)
        X2 = x1 + 320
        Y2 = -Y1 + 200
で何の問題もないはずです。
 
(3)
あと、Set ws = .... をループのなかに入れる必要もないと思いますし、
きちんとインデントをつけたほうが良いと思いました。
 
薄くて結構なので、ExcelVBAの基本書を通読されることを推奨します。

回答
投稿日時: 23/12/07 10:46:43
投稿者: MMYS

TomVla さんの引用:
Piは例えば下記プログラムと同様に使用しているつもりです。きちんと動作しているのに、なぜ今回はエラーになるのかわかりません。

下記のように、Option Explicitを追加して実行してみましょう。動きますか?
 
Option Explicit
Sub Line08()
    Dim ws As Worksheet
    Dim shp As Shape
 
    Dim X1 As Single, Y1 As Single
    Dim X2 As Single, Y2 As Single
     
    Pi = 3.14159265: D = 100
    For A = 0 To 2 * Pi Step 2 * Pi / 720
     
        E = D * (1 + 1 / 4 * Sin(12 * A))
        F = E * (1 + Sin(4 * A))
        X1 = 320 + F * Cos(A)
        X2 = 320 + F * Cos(A + Pi / 5)
        Y1 = 200 - F * Sin(A)
        Y2 = 200 - F * Sin(A + Pi / 5)
 
        Set ws = ThisWorkbook.Sheets("Sheet3")
     
        Set shp = ws.Shapes.AddLine(X1, Y1, X2, Y2)
 
    Next A
     
    With shp
        .Line.Weight = 2
        .Line.ForeColor.RGB = RGB(0, 0, 255)
    End With
End Sub
 
※インデントとを正しく付けましょう。最初に提示されたコードも間違い箇所がありますが、正しくインデントすれば、間違いに気づく箇所があります。
 
 
なお、変数宣言が必要か不要は、下記をお読みください。
http://officetanaka.net/excel/vba/beginner/06.htm
 
 

投稿日時: 23/12/07 14:49:16
投稿者: TomVla

(1) P11()の元のN-BASICのプログラムは以下の通りです。
100 'CIRCLE
110 SCREEN 2:WIDTH 80,25:CONSOLE 0,25,0
120 PI=3.14159 : L=100
130 For AL=0 TO 2*PI STEP PI/24
140 X1=L*COS(AL)
150 Y1=L*SIN(AL)
160 GOSUB*CHG
170 CIRCLE(X2,Y2),80
180 NEXT
190 END
200 *CHG
210 X2=X1+320
220 Y2=-Y1+200
230 RETURN
 
(2)Line08()のほうは、MMYSさんのご指摘のように冒頭にOption Explicitを付けると
「コンパイルエラー 変数が定義されていません」となり動作しません。
Option Explicitを付けなければ正常に動作します。
よくわかりません。

回答
投稿日時: 23/12/07 15:23:06
投稿者: simple

> よくわかりません。
 
以下が、Option Explicitステートメントについてのヘルプです。
https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/option-explicit-statement
VBA側にコンパイルのための条件を伝えるステートメントです。
このステートメントをモジュールの最初に書いておくと、
コードの解釈にあたって変数宣言の有無をチェックし、宣言されていなければ場所を指示して、
警告を発してくれるのです。そのエラーの解決が図られない限り、コードの実行は行なわれません。
そういう仕組みが備わっています。
 
# 余りムキになってもいけなかったです。
# 自分が知らなかったものは使いたくない、というのであればそれも"一局の将棋"かもしれません。

回答
投稿日時: 23/12/07 17:50:32
投稿者: MMYS

TomVla さんの引用:

Option Explicitを付けなければ正常に動作します。
よくわかりません。

下記、2つのコードは、どちらも正常に動作します。ふたつのコードの違いはわかりますか。違いは、Option Explicitの有無なのですが。
最初のコードには、変数宣言がまったく有りませんが、正常に動作します。
 
Sub Line08()

    Pi = 3.14159265: D = 100
    For A = 0 To 2 * Pi Step 2 * Pi / 720

        E = D * (1 + 1 / 4 * Sin(12 * A))
        F = E * (1 + Sin(4 * A))
        X1 = 320 + F * Cos(A)
        X2 = 320 + F * Cos(A + Pi / 5)
        Y1 = 200 - F * Sin(A)
        Y2 = 200 - F * Sin(A + Pi / 5)

        Set ws = ThisWorkbook.Sheets("Sheet3")

        Set shp = ws.Shapes.AddLine(X1, Y1, X2, Y2)

    Next A
     
    With shp
        .Line.Weight = 2
        .Line.ForeColor.RGB = RGB(0, 0, 255)
    End With
End Sub

 
Option Explicit
Sub Line08()
    Dim ws As Worksheet
    Dim shp As Shape
    Dim X1 As Single, Y1 As Single
    Dim X2 As Single, Y2 As Single
    Dim Pi As Double
    Dim A  As Double
    Dim D  As Long
    Dim E  As Double
    Dim F  As Double

    Pi = 3.14159265: D = 100
    For A = 0 To 2 * Pi Step 2 * Pi / 720

        E = D * (1 + 1 / 4 * Sin(12 * A))
        F = E * (1 + Sin(4 * A))
        X1 = 320 + F * Cos(A)
        X2 = 320 + F * Cos(A + Pi / 5)
        Y1 = 200 - F * Sin(A)
        Y2 = 200 - F * Sin(A + Pi / 5)

        Set ws = ThisWorkbook.Sheets("Sheet3")

        Set shp = ws.Shapes.AddLine(X1, Y1, X2, Y2)
 
    Next A
     
    With shp
        .Line.Weight = 2
        .Line.ForeColor.RGB = RGB(0, 0, 255)
    End With
End Sub

回答
投稿日時: 23/12/07 21:00:07
投稿者: simple

つかぬことをお聞きします。
どうもコミュニケーションが取れないような気がするのですが、
2名から紹介があった
http://officetanaka.net/excel/vba/beginner/06.htm
は、通読されているのでしょうか。
それを読まれたうえで質問を続けられているのですか?私には正直信じられない感じがします。

投稿日時: 23/12/07 21:26:32
投稿者: TomVla

MMYSさん、simpleさん
コメントありがとうございます。十分にフィードバックしないで応答してしまいました。申し訳ありません。少し時間をください。別途また報告します。

回答
投稿日時: 23/12/11 18:39:37
投稿者: たかさん@富山

こんばんは。
 
私も変数宣言は初めの頃は
とりあえずで、型宣言は面倒だと
思っていました。
 
Option Explicit
 
Sub DrawCircleInExcel()
    Dim PI As Double
    Dim L As Integer
    Dim AL As Double
    Dim X1 As Double, Y1 As Double
    Dim X2 As Double, Y2 As Double
     
    PI = 3.14159
    L = 100
     
    ' Set up Excel
    Dim excelApp As Object
    Set excelApp = CreateObject("Excel.Application")
    excelApp.Visible = True
    excelApp.Workbooks.Add
    excelApp.Worksheets.Add
     
    ' Draw circles
    For AL = 0 To 2 * PI Step PI / 24
        X1 = L * Cos(AL)
        Y1 = L * Sin(AL)
        Call ChangeCoordinates(X1, Y1, X2, Y2)
        DrawCircleInExcelSheet excelApp, X2, Y2, 80
    Next AL
End Sub
 
Sub ChangeCoordinates(ByRef X1 As Double, ByRef Y1 As Double, ByRef X2 As Double, ByRef Y2 As Double)
    X2 = X1 + 320
    Y2 = -Y1 + 200
End Sub
 
Sub DrawCircleInExcelSheet(ByRef excelApp As Object, ByVal X As Double, ByVal Y As Double, ByVal Radius As Double)
    Dim circleShape As Object
    Set circleShape = excelApp.ActiveSheet.Shapes.AddShape(msoShapeOval, X - Radius, Y - Radius, Radius * 2, Radius * 2)
    circleShape.Fill.Visible = msoFalse
    circleShape.Line.ForeColor.RGB = RGB(0, 0, 0)
End Sub
 
やりたいことは、これで解決しますか

投稿日時: 23/12/11 19:35:50
投稿者: TomVla

たかさん@富山
ありがとうございます。解決しました。
Option Explicitについて色々コメント頂いていますので、引き続き検討します。
もう少し時間をいただきます。
 

投稿日時: 23/12/12 10:50:46
投稿者: TomVla

http://officetanaka.net/excel/vba/beginner/06.htm
によれば、
>[編集]タブの[変数の宣言を強制する]チェックボックスをオンにすると、各モジュールでコードペインの先頭にOption Explicitが自動的に入力されます。
>まず最初にやるべきことは、[変数の宣言を強制する]のオプションをオンにすることです。
とあるので、「チェックボックスをオン」にすれば、プログラムの冒頭でOption Explicitを宣言しなくてもよくなるとも読めます。
 
今回ご提示いただいた皆様のプログラムにはOption Explicitが宣言されているので、
「チェックボックスをオン」はしているが、Option Explicitも宣言しているということでしょうか。

回答
投稿日時: 23/12/12 13:24:00
投稿者: simple

私はチェックボックスをOnにしているので、自動的にOption Explicitが挿入されています。
回答の際にそれを回答に入れる場合もあれば、それがポイントではない場合、入れないこともあります。
回答の際どうするかは、あなたにとって関係が無いことです。
 
それよりも、チェックボックスをOnにして、
・新しいxlsmブックを作成して下さい。
 そのときにコードペインの先頭に、自動的にOption Explicitが挿入されているかどうか、
 確認してください。
・また既存のxlsmブックで、標準モジュールを追加してみて、
 Option Explicitの有無を確認してください。
そのことが重要なことです。

回答
投稿日時: 23/12/12 23:33:42
投稿者: MMYS

モジュールを新規挿入した際に、「Option Explicit」を自動で記入されるか、無記入にするかを選ぶオプションです。
  
ご自身で、Option Explicit と手作業でコード入力すれば同じです。

投稿日時: 23/12/13 05:15:14
投稿者: TomVla

みなさま
未消化の部分もかなり残りますが、長くなるのでこのへんでクローズさせていただきます。
所望の結論も得られました。ありがとうございました。