「みんな教えて! 選手権!!」開催のお知らせ

UserForm1の中で使うワークシート変数を統一したいと思っています。

そのため宣言セクションで画像のように宣言してみましたが、エラーが出ます。

要するに「変数の宣言は出来るけれど、変数への代入は宣言セクションでは出来ない」
ということだと思います。

この場合「Ls_sh」という変数をワークシート変数として宣言したので、
UserForm1のプロシージャーの中では「Ls_sh」という変数名を
長整数型や文字列型で使えないというメリットがあるのは理解出来ます。

ですが宣言セクションで変数にシート名を割り当てることができないため

Set Ls_sh = Worksheets("Sheet10")

を各プロシージャーに毎回書くことになってしまいます。
おまけに、間違えて

Set Ls_sh = Worksheets("Sheet11")

とセットしてしまう可能性があり、あまり意味がないように思います。

ワークシート名(変数)の間違い防止のため、ユーザーフォームの中での
シート名の変数を一括管理したいのですが、
こういう場合、上級者の方はどういう方法で管理しているのでしょうか?

やっぱり各プロシージャーの中で、毎回

Set Ls_sh = Worksheets("Sheet10")

を行って、変数の割り当てをしているのでしょうか?

抽象的な質問なので返答しにくいと思いますが
何かアドバイスやお勧めの方法があれば教えて下さい。

以下のサイトも見たのですが、ちょっと違うような気がするので
質問してみました。

http://officetanaka.net/excel/vba/tips/tips94.htm

追記
可能でしたら、コードで説明して頂ければうれしいです。
※急いでおりません。

「【VBA】UserForm1の中で使うワ」の質問画像

A 回答 (4件)

No.1です。



でもユーザーフォームモジュールのみでも

Dim Ls_sh As Worksheet

Private Sub UserForm_Initialize()
Set Ls_sh = Worksheets("Sheet1")
End Sub

Private Sub CommandButton1_Click()
MsgBox Ls_sh.Name
End Sub

Private Sub UserForm_Terminate()
Set Ls_sh = Nothing
End Sub

ユーザーフォームが開かれる際のイベントでセットを行なえば、個々のイベントで宣言の必要はなくなるからこちらの方が楽ですかね。

でも標準モジュールの方でPublicで宣言すれば、ユーザーフォームを複数作成したとか標準モジュール内でも使用させたい時には有利になりますし、
目的次第って所かもです。

・標準モジュール
Option Explicit

Public Ls_sh As Worksheet

・ユーザーフォームモジュール(ユーザーフォーム1)
Private Sub UserForm_Initialize()
Set Ls_sh = Worksheets("Sheet1")
End Sub

Private Sub CommandButton1_Click()
MsgBox Ls_sh.Name
UserForm2.Show
End Sub

Private Sub UserForm_Terminate()
Set Ls_sh = Nothing
End Sub

・ユーザーフォームモジュール(ユーザーフォーム2)
Private Sub CommandButton1_Click()
MsgBox Ls_sh.Name
End Sub

みたいな。
あとは確か・・・クラスモジュールと組み合わせたい時とかでも使われたような気はします。
    • good
    • 1
この回答へのお礼

Thank you

今回はいろいろ、教えて頂きありがとうございます。
非常に参考になりました。

機会がありましたら、またお願いします。

お礼日時:2018/05/21 08:07

No.1のお礼に対して。



No.3さんの回答を読んで『そういう事態もあり得るんだ』とちょっとビビってしまっている状態ではあるのですが。
取り敢えず疑問点について。

>Private Sub UserForm_Initialize()
>Private Sub UserForm1_Initialize()

仮に複数のユーザーフォームをデザイン画面で作成したとしても、『UserFoam』と言う大元のオブジェクト名は変わる事はないため、
任意にFoamコントロールのオブジェクト名を変更してもその部分は変えられないと思います。

VisualBasic(.NET)の似たようなイベント(Load)では、Foamの名前を変更すれば

Private Sub abcdefg_Load(ByVal ~

みたいに変わるのですがね。
VBAはもっと古いVBをベースにしているので、開発の際に『そこまでの必要性』が当時なかったのではないか・・・と思います。(言い切れなくてごめんなさい)

No.3さんのご意見はVB.NETには標準モジュールに似たクラスを追加すれば私が回答した方法もできますが、まずその方法を行なうような解説は見つからなかったですね。
キチンとFoam間での明確な値のやり取りを解説されてます。
その点から行くとやはりお薦めできる方法ではなかったのかもですが、であればどうコード化するか?となっても直ぐには思いつかなかったです。
    • good
    • 1
この回答へのお礼

ご解答ありがとうございます。

再度、ご解答を頂きありがとうございます。

>Private Sub UserForm_Initialize()
>Private Sub UserForm1_Initialize()

仮に複数のユーザーフォームをデザイン画面で作成したとしても、『UserFoam』と言う大元のオブジェクト名は変わる事はないため、
任意にFoamコントロールのオブジェクト名を変更してもその部分は変えられないと思います。


わかりました。
プロシージャーの名前というより、

>Private Sub UserForm_Initialize()

自体がコマンドのようなものですね。

No.3さんのご意見を見て驚いたのですが、お礼に記載したとおり、
特に深刻な問題ではありません。

なのでNo.2で教えて頂いたテクニックを
一部のワークシートで部分的に使ってみようと思います。

バージョンアップ時に、ワークシートの変数名の整理の
目印になる部分があった方がいいと思いますので。

今回はご解答頂きありがとうございます。
機会がありましたら、またお願いします

※何かあるかもしれないので、しばらく質問は開けておきます。

お礼日時:2018/05/20 20:22

こんにちは。



ふつうは、モジュール・スコープでも、オブジェクト型の変数はしないですね。
テクニックでは、#1,#2さんで、示された通りですが、

Office Tanaka で示されているのは、
http://officetanaka.net/excel/vba/tips/tips94.htm

プロシージャで引き数で渡す方法(参照渡し)で、なぜそうするかといとう、モジュール・スコープでも、グローバル変数(用語に問題あり)でも、オブジェクト型は、壊れやすいからです。そのために、確実に渡す方法以外は、それをプロシージャ間で回して使うことはしません。*グローバル変数とはいっても、通常は、1つのプロジェクト内だけです。そして、私自身は、ほとんどグローバル定数(Const) のみに限られます。

クラスモジュールで定義する方法もありますが、クラスでインスタンス生成のように変化・変性しないものならともかく、一般的なオブジェクトは、とても長期では保持できるものではないと思うのです。
何らかのエラーが、オブジェクトの取りこぼしにつながるケーズが本当に多いのです。つまり、どこかでエラーが走れば、オブジェクト型の変数はこわれてしまうのです。

実際に私が以前書いていた、とてもみっともないコードですが、プロシージャの始めに、
以下のようなチェックプログラムを置くことになってしまいました。
If sh Is Nothing Then
  Set sh = Worksheets("Sheet1") '実際はもうちょっと複雑でサブルーチンにしました。
End If

その愚かさに気づくのに、数年掛かりました。とても大掛かりなものだったので、最初のAuto_Open から書き直す気持ちが起きませんでした。限られたモジュール内では、もしかしたらトラブルなく通せるかもしれませんが、なかなかそうはいかないように思うのです。これがベストとは言いません。プログラムが大きくなればなるほど、そのように考えたくなるのはやむを得ないことです。

言葉で說明してもなかなか実感が分からないと思います。何度となく試してみることで、自分なりのスタイルが見つかるかもしれません。
    • good
    • 1
この回答へのお礼

ご解答ありがとうございます。

ふつうは、モジュール・スコープでも、オブジェクト型の変数はしないですね。
テクニックでは、#1,#2さんで、示された通りですが、

Office Tanaka で示されているのは、
http://officetanaka.net/excel/vba/tips/tips94.htm

プロシージャで引き数で渡す方法(参照渡し)で、なぜそうするかといとう、モジュール・スコープでも、グローバル変数(用語に問題あり)でも、

オブジェクト型は、壊れやすいからです。そのために、確実に渡す方法以外は、それをプロシージャ間で回して使うことはしません。


知りませんでした。

今まで、いろいろ教えて頂いているのですが、みなさんのコードは変数を使ったり
withステートメントを使ったりで能率化されています。

なので、今回も「こうしているよ」みたいな方法があると思っていたので意外でした。

正直なところ、変数の名前が統一されていませんが
大きな問題はありません。

変数の名前が違うのはリストや表を作成する時に、
デザインや機能が決まってないからです。

「動作する」、「自力で作れる」ということが一番大事なので、
※みなさんに教えて頂いておりますが(笑)
とりあえず能率アップ出来そうなところから取り組んでいます。

作りながら「やっぱり必要ない」ということもあれば、
「こういう表示がいる」ということが出てきたりします。

変数名はその時の機能でわかりやすい名前を割り当てているため違うのですが、
動作上も問題ないし、ちょっと考えればわかるので問題はありません。

ですがデザインや機能が固まってくると、変数名のルールもおのずと決まってくるため、
気分的に「統一した方がいいかも」という程度です。

今回はインターフェイスの変更で、標準モジュールにあったコードを
順次、ユーザーフォームに引っ越すことになったので、
この機会に上級者のみなさんがどうされているのか聞いてみました。

今回はいろいろ教えて頂き、ありがとうございます。
機会がありましたら、またお願いします。

すごくためになりました。

お礼日時:2018/05/20 19:54

変数に対してSheetが固定で良いなら。



・『標準モジュール』で Private ではなく Public で変数『だけを』宣言します。

Option Explicit

Public Ls_sh As Worksheet

・ユーザーフォームモジュールにて

Private Sub UserForm_Initialize() 'ユーザーフォームが開かれる際のイベントでセット
Set Ls_sh = Worksheets("Sheet1")
End Sub

Private Sub CommandButton1_Click() '任意のイベントで変数を使用
MsgBox Ls_sh.Name
End Sub

Private Sub UserForm_Terminate() 'ユーザーフォームが閉じられる際のイベントで解放
Set Ls_sh = Nothing
End Sub

とかならやりますよ。(上級者ではなく初級レベルの者ですので、必ずこれが良いとは胸を張っては言えませんけど)
    • good
    • 1
この回答へのお礼

ご解答ありがとうございます。
返信が遅くなりすいません。

こんな方法があるんですね。
知りませんでした。

1つ教えて頂きたいことがあります。

動作チェックのために

Private Sub UserForm_Initialize() 'ユーザーフォームが開かれる際のイベントでセット
Set Ls_sh = Worksheets("Sheet1")
End Sub

Private Sub UserForm_Terminate() 'ユーザーフォームが閉じられる際のイベントで解放
Set Ls_sh = Nothing
End Sub

をコピー&ペーストしたところ問題なく動作しました。

ところが、「これは便利!」と思って、
プロシージャーの名前を

Private Sub UserForm1_Initialize()

にすると

実行時エラー91
オブジェクト変数またはWithブロック変数が設定されていません

というエラーメッセージで止まってしまいます。

読み込むだけで、ボタン等で呼び出すわけではないので、

Private Sub ○○△△()  
~~
End Sub

「○○△△」の部分は標準モジュールのSubプロシージャーのように、
任意の名前にできると思ったのですが違うのでしょうか?

お手数ですが、この件について
何かアドバイスがあれば教えて下さい。

ご面倒でしたらスルーでOKです。

お礼日時:2018/05/20 14:51

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報