• 締切済み

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 --------------------------------------------------------------------

みんなの回答

回答No.3

#1-2です。 > InventorやCATIA 設問をきちんと理解せずにお応えしてしまっていたようです。 質問を読むことは日頃から大事に考えているつもりなのですが、 他所の別件の質問と混同してしまっていたみたいです。 すみません。 InventorやCATIAに関して、私にお答えできることは、ありませんでした。 申し訳ありません。大変失礼いたしました。

回答No.2

#1です。 編集ミスがありましたので、訂正です。 誤) Classモジュール「Class1」に記述 -------------------------------------------------------------------- Public Sub Event_ON()   If CLS Is Nothing Then     Set CLS = New class1   End If End Sub -------------------------------------------------------------------- 正) 標準モジュール「Module1」に記述 -------------------------------------------------------------------- Dim CLS As class1 Private Sub Event_ON()   If CLS Is Nothing Then     Set CLS = New class1   End If End Sub -------------------------------------------------------------------- 以上のように訂正をお願いします。 失礼しました。

回答No.1

こんにちは。 通常は、 ThisWorkbookモジュール「ThisWorkbook」に記述 -------------------------------------------------------------------- Private Sub Workbook_Open()   Application.OnTime Now, "Event_ON" End Sub -------------------------------------------------------------------- のようにします。 普通にEvent_ONをCallしても良さそうですが、 Excelブック側の各種インスタンスが揃い、必要な再計算などが終った後に、 (例えばAuto_Open等、他のイベントトリガーを優先させて、その後ろにおキューを置く) 他のプロシージャとは独立して実行させる為に、 application.OnTime メソッドを使う方がトラブルフリーになります。 これで、ブックを開けば、Event_ONが実行されるようになります。 もしも、作業中(ブックが開いている間)に、   ●VBE画面でリセットボタンを押す   ●デザインモードに切り替える   ●エラー処理を逃れたエラーダイアログから[終了]を選ぶ 等の状況によって、VBProjectがリセットされた場合は、 CLSのインスタンスも解放されてしまいます。 こういった場合の復旧まで考慮に入れるなら、 Classモジュール「Class1」に記述 -------------------------------------------------------------------- Public Sub Event_ON()   If CLS Is Nothing Then     Set CLS = New class1   End If End Sub -------------------------------------------------------------------- のように書いておいて、 ThisWorkbookモジュール「ThisWorkbook」に記述 -------------------------------------------------------------------- Private Sub Workbook_WindowActivate(ByVal Wn As Window)   Application.OnTime Now, "Event_ON" End Sub -------------------------------------------------------------------- 等、、 運用に合わせて適当な既存のタイミング(トリガ)を、 Workbook_Openの代りに、選んでみて下さい。 因みに、以上の例に合った形にするなら、 Private Sub Event_ON() のようにスコープを変更した方が、紛れがなくなり、ベターです。 以上です。

iori16
質問者

お礼

返事が遅くなりまして申し訳ありません。 Excelの場合は、「WindowActivate」のように最初から使えるイベントがあるので問題はないのですが、 InventorやCATIAの場合、デフォルトで使えるイベントの中にイベントが存在しておりません。 そこで、デフォルトのイベント以外で自動でインスタンス化する方法を探しておりました。 ほかにもEXCELの場合においてもイベント以外のやり方はいろいろあるようなので、 InventorやCATIAでも同様の方法がないか探してみます。 解答ありがとうございました。

関連するQ&A

  • アプリケーションのイベント(エクセルVBA)

    エクセルを起動した時に、自動的にマクロを起動したいと思っています。どの、ブックを開いても同じマクロが起動させる(別のパソコンで同じファイルを起動した場合は、起動しなくても構いません。)には、アプリケーションのイベントを使う必要があると考え、クラスモジュールを使ってアプリケーションのイベントプロシージャを作ることは、本を読んで何とか理解しました。 -------clasモジュール-------- Public WithEvents App As Application Private Sub App_SheetBeforeRightClick(省略・・)  処理したい内容 Cancel = True end sub -------標準モジュール-------- Sub SetAppEvent() Set myclass.App = Application End Sub と書いて、SetAppEventを実行すると、以降右クリックでイベントが発せいしました。しかし、初めてエクセルを起動した時に一々SetAppEventを実行する必要があります。何か?いい方法は無いでしょうか?ご指導のほど宜しくお願い致します。

  • 内部クラスのインスタンスを外部クラスが保持する場合

    C++での内部クラスの宣言の仕方なのですが、例えば、 class Outer { private:    class Inner; public:    Outer();    ~Outer(); }; class Outer::Inner { public:    Inner();    ~Inner(); }; のように単純に内部クラスが宣言されているだけならば、 その具体的な定義を外側に書くことは可能と思うのですが、 class Outer { private:    class Inner    {    public:       Inner();       ~Inner();    }; public:    Outer();    ~Outer();    Inner inner; //内部クラスのインスタンス }; のように外部クラスが内部クラスのインスタンスを保持していた場合には、 上記のようにインスタンス作成より上で外部クラスの宣言内に内部クラスの定義を書かないと、 コンパイルが通らない(VC++2008)と思います。具体的な中身がないままインスタンスを 作っているのでエラーを吐く理由もわからないでもないですが、 見易さ的に上の例のようにかけないのかなとも思ったりします。 インスタンスを外部クラスに持たせずともどうとでもなるのですが、 あえて上のようなことをしたくなった場合には下のような方法で記述する以外ないのでしょうか?

  • Access VBAのイベント共有について

    こんにちは。 初めて質問をさせて頂きますcimappleと申します。よろしくお願いいたします。 現在、業務にて使用するデータベースをAccessにて作成しておりまして、VBAにてフォームの各処理を記述しています。 ちなみに、当方Access、VBAについて超初心者ですので、そもそもの誤解がある部分もあるかと思いますが、ご容赦ください。 さて、質問の内容ですが、今回フォーム上にある14個のラベルを、マウスカーソルが乗った時(MouseMoveイベント)にそのラベルの背景色を変えるコードを組みたいと考えています。 現状としては、それぞれのラベルのMouseMoveイベントに背景色を変えたり、戻したりといったコードを記述していますが、当然非効率かつ面倒なのです。 そこで、このイベントを共有化したいと考え、いろいろと検索したところ、クラスモジュール(Private WithEvents)にてそういったことができそう・・・というところまでは辿り着いたのですが、その先が全く分かりません。 Excelについてのクラスモジュールの記事はたくさん見つけて、コピーペースト見よう見まででマネてはみたのですが、当然うまくいかず、そこから先に進めないでおります。 クラスモジュールについて基礎から勉強しなさいと言われればその通りなのですが、どうかお知恵をお貸し頂きたく質問させていただきました。 よろしくお願いいたします。 以下、見よう見まねの現在のコードです。 ちなみに、フォーム名はFRM1、ラベル名はそれぞれLbl○、クラスモジュール名はCLS1となっています。 Form(FRM1)のコード ======================================================= Option Compare Database Option Explicit Dim MyLbl(14) As CLS1 Private Sub Form_Load() Dim Lbl As Access.Label Dim i As Integer For i = 1 To 14 Set Lbl = Me.Controls("Lbl" & i) Set MyLbl(i) = New CLS1 Set MyLbl(i).Label = Lbl Next End Sub ======================================================= Class(CLS1)のコード ======================================================= Option Compare Database Option Explicit Public WithEvents Label As Access.Label Private Sub Label_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single) Label.BackColor = 225 End Sub ======================================================= 長文かつ駄文で申し訳ありませんでした。

  • 別のクラスのインスタンスの作り方

    現在、javaからrubyに移行するために勉強しているのですが、別のファイルに定義したクラスのインスタンスが作成できなくて、困っています。 具体例をあげると require './B' class A end def initialize b = new B end end --別のファイル class B def initialize p 'hello' end  public : initalize end こんな2つのファイルがあったとして、Aのインスタンスを作成すると、 undefined method `B’ というエラーがでます。 私としてはこのエラーの原因がinitializeがデフォルトでprivate宣言なのが原因だと考えているのですが、publicと指定してもエラーとなることから、いくつか疑問が湧いたので質問させていただきます。 1、そもそもBクラスのインスタンスが作成できないのはinitializeがデフォルトでprivate宣言なのが原因なのか? 2、1があっていたと仮定するとBクラスのinitializeをpublic指定しているのになぜ呼び出せないのか? 3、rubyはなぜデフォルトでinitializeがprivateなのか?(javaではコンストラクタをprivateにするということは普通はしない。使うときはシングルトンやUtilのようなクラスを作るときに限る) 以上です。よろしくお願いします。

    • ベストアンサー
    • Ruby
  • エクセルVBAでのwitheventsについて

    お世話になります。 エクセルVBAでクラス側で ListBoxにたいしてwitheventsは使用 できないのでしょうか? Private WithEvents lst As ListBox Public Sub Class_Initializa() Set lst = UserForm1.ListBox1 End Sub 上記コーディングで実行時に 「オブジェクトはオートメーションイベントを 発生させることができません」 になります。 クラス側でダブルクリックイベントを拾いたいのですが。 宜しくお願い致します。

  • VB6.0のクラスで、自分自身のインスタンスを作成するメリット

    クラスのメソッドで、自分自身のインスタンスを作成している、コードをよく見かけます。 どんなメリットがるのでしょうか? 簡単に、クラスファイルのコードを書きました。 【A.cls】 Option Explicit Dim pstrID As Long Dim pstrName As String Public Function fncCreate() As Object     Set fncCreate = New clsA  '★自分自身のインスタンスを作成する End Function Public Function fncID() As Boolean     pstrName = "ID" End Function Public Function fncName() As Boolean     pstrName = "STRING" End Function Private Sub Class_Initialize()     pstrID = 0     pstrName = "" End Sub

  • クラスとインスタンスについて

    はじめまして。Javaをはじめて3か月の超初心者です。 早速ではございますが、質問をさせていただきます。 以下のサンプルで、 class Foo { private int i = 0; Foo(int i) { this.i = i; } void func1() { System.out.println(this.i); } void func2(Foo foo) { System.out.println(foo.i); } } class Main { public static void main(String[] args) { Foo obj1 = new Foo(100); Foo obj2 = new Foo(500); obj1.func1(); obj1.func2(obj2); } } privateフィールドのスコープは同一クラス内からしか アクセスできないと参考書には記述されているの ですが、そのクラス内に上のサンプルのように this.iやfoo.iというように、クラスは同じでも インスタンスが異なるものがiにアクセスするとき、 上のサンプルは、どちらもアクセス制限のエラーが表 示されません。なぜなのでしょうか? this.iというアクセスは、現在実行中のインスタン ス内でのアクセスなので、privateスコープ内での アクセスであるというような感じがするのですが、 foo.iというアクセスの方は、現在実行中のインスタンスとは異なるインスタンス内でのアクセスなので、 privateスコープからはずれているような感じがして なりません。

    • ベストアンサー
    • Java
  • 押されたキーにてポップアップメニューを切り替える

    OS:XP SP2 アプリ:Excel 2002 ワークシート上で右クリックにてポップアップメニューが表示されますが、Ctrl+右クリック、Shirf+右クリック、Alt+右クリックにて、独自のポップアップメニューを表示させようてしています。 プロジェクトにクラスモジュールを追加し下記の様に宣言しています。 Private WithEvents App As Application Private Sub Class_Initialize() Set App = Application End Sub 右クリックイベント内で現在押されているキーを判断することはできないでしょうか? Private Sub App_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean) ここで押されたキーにて表示するメニューを切り替える End Sub 独自のポップアップメニューの追加/表示はできています。 ご教授のほど宜しくお願いします。

  • 自作クラスのイベントを外部ハンドラでスレッドセーフ

    ■.NETモジュールプロジェクト(DLL) Public Class MyClass   Public Event hoge( ByVal sender As Object, ByVal e As EventArgs )   Private WithEvents Timer As Timers.Timer   Private Sub New()     Timer = New Timers.Timer : Timer.Interval = 10 : Timer.Start()   End Sub   Private Sub fuga( ByVal sender As Object, ByVal e As EventArgs ) Handles Timer.Elapsed     RaiseEvent hoge( Me, New EventArgs ) ' 一定時間ごとにイベントを発生させる   End Sub End Class ■上の.NETモジュールを参照している Windows Form アプリケーションプロジェクト(EXE) Public Class Form1   Private WithEvents foo As MyClass.MyClass   Public Sub New()     InitializeComponent()     foo = New MyClass.MyClass   End Sub   Private Sub bar() Handles foo.hoge     TextBox1.Text = "baz" ' TextBox1 は デザイナで Form1 に貼り付け済み   End Sub End Class という 2 プロジェクトを含むソリューションを作成しました。実行すると、 有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'TextBox1' がアクセスされました。 というエラーが出てきます。 foo が MyClass ではなく、system.windows.forms.dll などに入っている Button や Form といったコントロールの場合は、上記の bar() のような書き方でもスレッドセーフに扱えるので、MyClass もForm1 のコードを修正する事なく、利用できたらなと思っています。 その場合、どのように MyClass を書けばいいでしょうか。環境は VS2008 で、.NET2.0 ベースです。

  • 【ppt、VBA】ファイル開閉時のマクロ自動ロード

    自作のコマンドバーを作成して、アドイン化しました。 うまく動作していますが、一つ困っています。 以下のようにクラスをつくり、Open時にコマンドバーを作成し、 Close時にコマンドバーを削除しています。 しかし、複数のファイルを開いている際、そのうちの1つを閉じただけでコマンドバーが消えてしまいます。 どのようにすれば、パワーポイントプロセスの起動・終了に連動させることができるでしょうか? よろしくお願いします。 Public WithEvents App As Application Private Sub App_PresentationOpen(ByVal Pres As Presentation) Call MakeToolBar End Sub Private Sub App_PresentationClose(ByVal Pres As Presentation) Call RemoveToolBar End Sub

専門家に質問してみよう