• ベストアンサー

VBA クラスにプロパティが実装できません

VBA初心者です。 現在、Excel2003-VBAでクラスにプロパティの実装を試みていますが、うまくいきません。 Publicで宣言する方法は問題なく出来たのですが…。 勉強用のため、敢えて簡単なサンプルを自分で作っています。 【状況】 下記プログラムで、メッセージを「20」と表示させたいのですが、 「スタック領域が不足しています」エラーにより、実行できません。 また「Atai」を「Suji」にかえると、メッセージとして「0」と出てきます。 あるいは、「Suji = Atai + 5」を消してみても「15」ではなく「0」と出ます。 【質問】 どちらでもうまくいかないのですが、これは (1)このコードがおかしいのか、それとも (2)単純なプログラムであるのに領域不足と出るところから、 VBA特有の不具合でどうしようもない物なのでしょうか? ご意見お待ちしています。 ===通常Module(呼び出し側)=== Option Explicit Sub 実行() Dim Haichi As New Class1 With Haichi .Suji = 15 .MSGクラス End With End Sub ===クラスMODULE(Class1)=== Option Explicit Sub MSGクラス() MsgBox Suji End Sub Public Property Let Suji(Atai As Double) Suji = Atai + 5 End Property Public Property Get Suji() As Double End Property

質問者が選んだベストアンサー

  • ベストアンサー
  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

一般的な実装 ' プロパティSujiの値を記憶しておく実体 Private dSuji as Double public Property Let Suji( Atai as Double )   dSuji = atai + 5 end Property Public Property Get Suji() as Double   Suji = dSuji End Property といった具合に実装します 質問のような記述をすると #1の回答のように 実行時に With Haichi .Suji = 15 で Class1の Public Property Let Suji(Atai As Double) ここが呼び出されます 次の Suji = Atai + 5 が Sujiへの代入なので また Public Property Let Suji(Atai As Double) の行が実行されます これが繰り返されて スタックを食いつぶすことになります

greatpurin
質問者

補足

ご回答の通りにしてみたらできました。 まだ理解が浅いので、ヘンな表現ですが、 SujiがAtaiに代入され、 Ataiを使ってdSujiが計算され、 dSujiがSujiに代入されるという感じでしょうか。 (AtaiとdSujiは一時的に値を記憶なり取得なりする?)

その他の回答 (3)

  • imogasi
  • ベストアンサー率27% (4737/17068)
回答No.4

簡単な例を挙げてみます。参考になれば。 クラスでプロパティとメソッドを作る例 VBEの画面で 挿入ークラスモジュール 2つめのクラスモジュールに作ったので名前はClass2になってます。 Nameはモジュールで1つのプロパティの名として使います。 keisanはメッソドでモジュールでメソッドとして、この名で使います。 下記はいわゆる設計図に当たります。 Dim m_strName As String Dim keisann As Integer Public Property Get Name() As String Name = m_strName End Property Public Property Let Name(ByVal NewValue As String) m_strName = NewValue End Property Public Function keisan(a As Integer) keisan = a + 5 End Function ーー 標準モジュールのModule1に Dim aaa As New Class2 Sub test01() Set aaa = New Class2 aaa.Name = "AAAAAA" MsgBox aaa.Name MsgBox aaa.keisan(10) End Sub aaaは実体化した時のオブジェクトの名前。 Set aaa = New Class2はクラスClass2をインスタント化 aaa.Name = "AAAAAA" はNameプロパティにAAAAAAにセット MsgBox aaa.Name はプロパティの値を利用している。 MsgBox aaa.keisan(10) は計算メソッドを利用している。 引数に+5している。 ーーー >Public Property Let Suji(Atai As Double) Suji = Atai + 5 End Property はプロパティでの定義でするものではないのではないか。 === VBAはApplicationであるエクセル・アクセスの操作などを対象にしたもので、普通の操作に使う、プロパティ・メソッドは既に備わっている。解説書の量で言えば、エクセルで1000ページに近い。 ですからエクセルなどでクラスの考えを使わなければならないことは ほとんどない。もっとシステム設計やアルゴリズムなどのことで勉強することがたくさん有るだろう。深入りしても無駄だと思う。VB.NETではメインの考えだろうが。

  • myRange
  • ベストアンサー率71% (339/472)
回答No.3

'-------- Class-------------- Private myData As Double Public Sub MSGクラス()   MsgBox myData End Sub Public Property Let Suji(Atai As Double)   myData = Atai + 5 End Property '-------------------------------    

greatpurin
質問者

補足

参考になりました。 ありがとうございます。

  • lovesens
  • ベストアンサー率30% (48/158)
回答No.1

ざっと見ただけですが… >Public Property Let Suji(Atai As Double) >Suji = Atai + 5 >End Property Sujiをずっと呼び続けることになりませんか。 +、+と延々繰り返してメモリエラーになるような。 あと、 >MSGクラス >Sub 実行() 日本語混じりは今から使わないよう癖つけといたほうがいいと思います。

greatpurin
質問者

補足

解決できました。ありがとうございます。 日本語混じりも気を付けたいと思います。

関連するQ&A

  • VBAでクラス設定

    (標準モジュール) Option Explicit Sub test() Dim Class As Class1 Set Class = New Class1 Class.Obj = 1000 Set Class = Nothing Set Class = New Class1 Range("a1").Value = Class.Obj Set Class = Nothing End Sub (クラスモジュールClass1) Option Explicit Private a As Integer Public Property Get Obj() As Integer Obj = 2000 End Property Public Property Let Obj(ByVal NewNumber As Integer) a = NewNumber End Property 上のマクロではやり取り1変数になってますがこれを配列に変えたいのですがどうすればいいでしょうか?

  • エクセルのマクロでクラスのプロパティについて

    エクセルでセルがダブルクリックされたら フォームを表示し、フォーム内のリストボックス のクリック時の値をクラスのプロパティに実装 できるのでしょうか? 以前、仕事でそのようなクラスを呼び出して 使ったことがあるので。 エクセル側 Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) Dim cls As New Class1 ' cls.ListSet ' End Sub ↑フォームの表示まで クラスモジュール Option Explicit Public listVal As String Public Function ListSet() As Boolean ' On Error GoTo ErrFunc ' ListSet = True ' With UserForm1 With .ListBox1 .AddItem "a" .AddItem "b" .AddItem "c" End With ' .Show ' End With ' Exit Function ' ErrFunc: ListSet = False End Function Public Property Let val(ByVal data As String) listVal = data End Property Public Property Get val() As String val = listVal End Property フォーム側のListBox1_Clickで どうすればよいか分からなくなりました。 根本的に間違っているのでしょうか? ネットでさがしたのですが参考になる サイトが見つかりません。 解決方法、宜しくお願い致します。

  • VBA クラスモジュールについて

    http://www.excellenceweb.net/vba/class/what_vba_class.html を見ながらクラスモジュールの勉強をしているのですが 躓きました。 新規にクラスモジュールを挿入し オブジェクト名に果物売上と名付けました。 そこに、 Sub TEST() Dim Apple As 果物売上 Set Apple = New 果物売上 End Sub と入力しました。 そして標準モジュールを挿入し、 そこに Sub TEST() Dim Apple As 果物売上 Set Apple = New 果物売上 With Apple .名前 = "リンゴ" .価格 = 100 .在庫 = 20 .仕入数 = 50 End With With Apple Debug.Print .名前 End With End Sub を入力しました。 そして、デバッグすると 「Apple As 果物売上」の部分が コンパイルエラーになってしまいます。 全然クラスモジュールの使い方がわからないのですが どこを直せばいいのでしょうか?

  • VBAクラスで、プロパティを使わずに、データを受け渡すには?

    はじめまして。 最近、クラスモジュールを使い始めたのですが、 別のクラスに、プロパティを使わずに、 データを受け渡すには、どうすればいいのでしょうか? たとえば、次の2つのクラスがあったとします。 (両方ともString型の読み取り専用のプロパティがある) 'クラスA Private m_Str_A as string Public Property Get Str_A() as String Str_A = m_Str_A End Property 'クラスB Private m_Str_B as string Public Property Get Str_B() as String Str_B = m_Str_B End Property ここで、クラスAで使用したm_Str_Aのデータを クラスBのm_Str_Bへ渡したいのですが、、、、。 別のプロパティを作ればいいだろうと考えたのですが、 それでは、値の変更が可能になってしまいます。 使用環境は、Excel2000 VBA、Windows2000です。 いろいろ調べてみたところ、他の言語か、VB.NETでない と無理そうなことが書かれていました。 仕事場では、他の言語は使用できないので、困ってます。 何か良い方法がありましたら、よろしくおねがいします。

  • VBA クラスモジュールの使い方わかりません。

    為替データで検証中なのですがネットで使いたいクラスモジュールがあり、値の渡し方などわからなくて困ってます。 過去1ヶ月のデータで日付、始値、高値、安値、終値並んでいる値を標準モジュールからTRと言う名のクラスモジュールに渡して計算したいのですがわかりません。 標準モジュールのみで簡単なマクロを作れるレベルです。 下がTRクラスモジュールです。 どなたかお助けください。 Option Explicit Public Version As Long Public Description As String Public NumInSequences As Long Public NumParams As Long Private Sub Class_Initialize() Version = &H10000 Description = "TR(真のレンジ)" NumParams = 0 NumInSequences = 4 End Sub Public Sub Calc(A() As Double, O() As Double, H() As Double, L() As Double, C() As Double) Dim I As Integer Dim LastClose As Double '前日の終値 For I = LBound(A) To UBound(A) If C(I) = Invalid Then A(I) = Invalid GoTo NextElem End If Dim D1 As Double '今日の高値と安値の差 Dim D2 As Double '前日の終値から今日の高値までの差 Dim D3 As Double '前日の終値から今日の安値までの差 If LastClose = Invalid Then A(I) = Invalid LastClose = C(I) GoTo NextElem End If ' 3つのパターンのレンジを計算 D1 = H(I) - L(I) D2 = H(I) - LastClose D3 = LastClose - L(I) If D1 > D2 Then A(I) = D1 Else A(I) = D2 End If If (A(I) < D3) Then A(I) = D3 End If LastClose = C(I) NextElem: Next End Sub

  • VBAのクラスのインスタンス化のタイミングについて

    こんにちはvbaのクラスのインスタンス化について質問があります。 私は普段使えないイベントを使用するときにクラスモジュールに WithEventsを使ってイベントを作成し それをプロシージャからインスタンス化して 作成したイベントを有効にするという手法をよく使います。 Excelのように最初からワークブックにイベントがある場合は、 ワークブックを開いたと同時にWorkbook_Openプロシージャから クラスをインスタンス化して作成したイベントを有効にするということが可能なのですが、 CATIAやInventorなど、一部のアプリケーションでは、 最初から使えるイベントが見つからず、 Subプロシージャでインスタンス化する方法しかみつかりません。 しかし、Subプロシージャを実行させるためには、 ボタンなどユーザー側に何らかのアクションとってもらうしかなく、 自動化するために作成したイベントなのに、そのイベントを有効にするために ユーザーにボタンを押してもらうという矛盾した構成になってしまいます。 クラスをインスタンス化する方法はSubプロシージャに記述するしかないのでしょうか? 自分がよく使っているコードを下に記述します。 下の例は、Excelで新しくブックを開いたときにメッセージを出すプログラムです。 アプリケーションレベルのイベントをクラスモジュールで作成しています。 これを有効にするためには標準モジュール内の Event_ONプロシージャを実行しなければなりません。 モジュールを実行する前まではいくら新しいブックを開いてもメッセージは出ません これをどのうようにしたらいいかご教授ください。 Excelの例 Classモジュール「Class1」に記述 -------------------------------------------------------------------- Private WithEvents APP As Application Private Sub APP_NewWorkbook(ByVal Wb As Workbook) MsgBox "新しいブックが開かれました" End Sub Private Sub Class_Initialize() Set APP = Application End Sub -------------------------------------------------------------------- 標準モジュール「Module1」に記述 -------------------------------------------------------------------- Dim CLS As class1 Public Sub Event_ON() Set CLS = New class1 End Sub --------------------------------------------------------------------

  • VB2008: クラスの既定のプロパティの活用イメージに関して?

    本日でちょうど60日目というVB.NET 初学者です。 未だ Sub Main() での基本事項の確認に終始しています。 3日まえより基本事項の最終課題にクラスを選んで挑戦中。 ですから、少し、質問しなければ判らないことだらけです。 今回の質問は、<既定のプロパティ>についてです。 ' ========================== ' クラス; 既定のプロパティ ' ========================== Module theDefault   Sub Main()     Dim T1 As New TEST1     T1(0) = "Kenji"     Debug.Print(T1(0))     Debug.Print(T1.MembersFriends(0))   End Sub End Module このように、確かに、既定のプロパティは省略した構文で書けるので便利。 それはわかります。 が、問題は、その具体的な活用イメージがサッパリです。 「例えば、こういうケースに使うととっても便利」という具体例があれば教えてください。

  • EXCEL VBA でユーザー定義型データーをproperty get let を使って受け渡しをしたい

    Excel2002Sp3を使用しています。 (WindowsはXpSp3です) ユーザー定義型の各メンバーに対して、property get/let/set を使用してデーターの受け渡しを行いたいのですが、うまくいきません。 以下に作成したプログラムを載せてみます。 main1()とmain2()がありますが、 main2()だとうまくいきます。 しかし、メンバー個別のやりとりにはなっていません。 main1()のようにメンバー個別でやりとりできるようにする方法がわかりません。 property get/let/setの書き方でできるようになるのでしょうか。 それとも、メンバー個別でのやり取りは仕様上できないのでしょうか。 もしできるのであれば、サンプルコードを教えていただけると助かります。 よろしくお願いします。 ------------------- Class1 ------------------- Option Explicit Private m_xx As X Public Property Get xx() As X xx = m_xx End Property Public Property Let xx(p As X) m_xx = p End Property ------------------- Module1 ------------------- Option Explicit Type X a As Long b As Long End Type Sub main1() '個別にやり取り Dim cc As New Class1 Dim p As Long Dim q As Long cc.xx.a = 5 cc.xx.b = 2 p = cc.xx.a q = cc.xx.b MsgBox p & "," & q End Sub Sub main2() 'yyを用意してまとめてやり取り Dim cc As New Class1 Dim p As Long Dim q As Long Dim yy As X yy.a = 5 yy.b = 2 cc.xx = yy p = cc.xx.a q = cc.xx.b MsgBox p & "," & q End Sub ----------------------------------------

  • プロパティープロシージャーについて

    簡単な年齢計算プログラムです。 書籍のサンプルなのでうまく動いています。 クラスの変数がPrivate strnameだったりするので そこへアクセスするためにプロパティプロシージャーを使っているというところまでは 判ったような気がしますが、 getとsetの関係がわかりません。 まず、 1.何をGetしているのか 2.なぜGetが先に来るのか、 3.Setの前にGetのReturnで返してますが実態は何を返しているのでしょうか?普通に考えると逆のような気がします。 根本がわかっていないのだと思いますが、どなたかお教え願います。 呼ぶ方 Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim person As New Class1() person.Name = TextBox1.Text person.Birthday = DateTimePicker1.Value.Date MessageBox.Show(person.Name & "さんの年齢は" & person.GetAge()) End Sub クラスの方。 Public Class Class1 Private strname As String Private datBirthday As Date Public Property Name() As String Get Return strname End Get Set(ByVal pro_name As String) strname = pro_name End Set End Property Public Property Birthday() As Date Get Return datBirthday End Get Set(ByVal pro_birthday As Date) datBirthday = pro_birthday End Set End Property Public Function GetAge() As Integer Return Int(DateTime.Today.Subtract(Birthday).Days / 365.25) End Function End Class

  • VB.NET クラス内でプログラムを終了するには?

    VBAでは、エラーでプログラムを終了する時には Endステートメントを記述していましたが、 このVBAをVB.NET(クラスライブラリ、DLL)に 書き換えていますが VB.NETでClass1クラスの中にtest()メソッドを作って この中にEndステートメントを記述すると 「クラスライブラリプロジェクトで  Endステートメントを使用することができません。」 というメッセージが表示されますが エラーでプログラムを終了するには どのように記述すればいいのでしょうか。 Public Class Class1  Public Sub test(ByVal a As String)   If a = "" Then    MsgBox("致命的なエラーです")    End <===エラー発生   End If  End Sub End Class よろしくお願いします。(WindowsXP,VS2010)