[[20211204150352]] 『VBA フォーム 動的に生成したボタンのプロパティ』(ほわ) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『VBA フォーム 動的に生成したボタンのプロパティを後から変更したい』(ほわ)

フォームに「縦n」「横n」というテキストボックスがあり、そこに数字を入力して「作る」というボタンを押すとその分だけボタンが生成されます。
フォームの名前は「Form」です。

Private Sub 作る_Click()

Dim gyo As Long: gyo = 縦n.Value
Dim retu As Long: retu = 横n.Value
Dim i As Long, j As Long

For i = 1 To gyo
For j = 1 To retu

    ReDim Btn(i, j)

    Dim BtnName As String: BtnName = "Btn_" & i & "_" & j
    With MineSweeperForm
        Set Btn(i, j) = .Controls.Add("Forms.CommandButton.1", BtnName, True)

        With Btn(i, j)
            .Top = 15 * i + 30
            .Left = 15 * j - 5
            .Height = 15
            .Width = 15
            .Font.Size = 8
        End With
    End With
Next j
Next i

End Sub

「塗る」というボタンがあり、「縦n」「横n」に入力したボタンのキャプションを空欄から「●」へ変更したいです。
試したコードは下記のとおりです。

Private Sub 塗る_Click()

Dim gyo As Long: gyo = 縦n.Value
Dim retu As Long: retu = 横n.Value
BtnName = "Btn_" & gyo & "_" & retu

Form.BtnName.Caption = "●"

End Sub

「メソッドまたはデータメンバーが見つかりません」のエラーが出て
Form.BtnName.Caption = "●"
の行で止まってしまいます。

試しに3×3のボタンを生成して
Form.Btn_3_3.Caption = "●"
としても同じエラーが出てしまうので、オブジェクトの指定方法が誤っている可能性があります。
フォームに手動で「Btn_3_3」という名前でボタンを作ってみると同様の書き方でキャプション変更できました。

< 使用 Excel:Office365、使用 OS:Windows10 >


BtnNameをMSForms.Commandbutton型に対応するオブジェクト変数にしてください。
また、モジュールレベルで宣言する、WithEventsでイベント対応させる等の措置も必要かもしれません。

参考
http://officetanaka.net/excel/vba/variable/05.htm
https://docs.microsoft.com/ja-jp/dotnet/visual-basic/language-reference/modifiers/withevents
(きまぐれおじさん) 2021/12/04(土) 16:09


 参考に

 Private Sub 塗る_Click()
    Dim gyo As Long: gyo = 縦n.Value
    Dim retu As Long: retu = 横n.Value
    Dim BtnName As String

    BtnName = "Btn_" & gyo & "_" & retu
    Me.MineSweeperForm.Controls(BtnName).Caption = "●"
 End Sub

(ピンク) 2021/12/04(土) 17:10


 ピンクさんとまる被りですが、せっかく書いたので、

 Private Sub 塗る_Click()
    Dim gyo As Long: gyo = 縦n.Value
    Dim retu As Long: retu = 横n.Value
    Dim btnName As String
    btnName = "Btn_" & gyo & "_" & retu
    Me.Controls(btnName).Caption = "●"
 End Sub

 MineSweeperFormというのはユーザフォーム名という前提。

 マインスイーパーを作ろうとしているなら、
クラスモジュールによるイベントの共通化について調べるといいでしょう。

(hatena) 2021/12/04(土) 17:16


 >MineSweeperForm
 ユーザフォーム名でしたか、てっきりフレーム名かと早とちり(;^_^A
 Me.Controls(BtnName).Caption = "●"  で十分でしたね

(ピンク) 2021/12/04(土) 17:31


 フレーム名かも知れないですね。

 > フォームの名前は「Form」です。

 と質問者さんは言われているので。

(hatena) 2021/12/04(土) 17:46


すみません。
フォームの名前は「MineSweeperForm」でした。
投稿の際に恥ずかしいなと思って「Form」にしたのですがコードに「MineSweeperForm」が残っていました汗
(ほわ) 2021/12/04(土) 18:38

きまぐれおじさん様
モジュールレベルで宣言しておく手がありましたか
動的な変数宣言についてあまりよくわからないまま書いております。
参考になるサイトまでありがとうございます。

ピンク様、hatena様
フォームの名前で混乱させてしまい、すみません。
いただいたコードで想定通りの動きになりました。
大変助かりました。
Controls()とは何なのか...?もう少し勉強します。

数日悩んでいたことが(理解は追いついていませんが)とりあえず解決して幸せです。
本当にありがとうございました。
(ほわ) 2021/12/04(土) 19:39


 解決済みですが、いくつか、補足を。

 UserForm.Controls はフォーム上のコントロールのコレクション(配列のようなもの)です。

 .Controls(1) とインデックスで特定のコントロールを参照できます。
また、.Controls("コントロール名") というようにコントロールの名前の文字列で参照することも可能です。
今回の回答は、この名前の文字列で参照する方法を使っています。


最初の質問のコードでちょっと気になる部分があったので、指摘しておきます。

    For i = 1 To gyo
        For j = 1 To retu
            ReDim btn(i, j)
            Dim BtnName As String: BtnName = "Btn_" & i & "_" & j
            With Me
                Set btn(i, j) = .Controls.Add("Forms.CommandButton.1", BtnName, True)
                With btn(i, j)
                    .Top = 15 * i + 30
                    .Left = 15 * j - 5
                    .Height = 15
                    .Width = 15
                    .Font.Size = 8
                End With
            End With
        Next j
    Next i

 上記のコードですが、ループ内で、繰り返し、ReDim btn(i, j) してますが、
 意味ないです。ReDim すると配列の内容はリセットされるので、中身は空っぽの
 配列の最後に、コマンドボタンを一つ代入しているだけです。

 ここは配列にしなくても、CommandButtonオプジェクトの変数として宣言すればOKです。

    Dim btn As MSForms.CommandButton

    For i = 1 To gyo
        For j = 1 To retu
            Dim BtnName As String: BtnName = "Btn_" & i & "_" & j
            With MineSweeperForm
                Set btn = .Controls.Add("Forms.CommandButton.1", BtnName, True)
                With btn
                    .Top = 15 * i + 30
                    .Left = 15 * j - 5
                    .Height = 15
                    .Width = 15
                    .Font.Size = 8
                End With
            End With
        Next j
    Next i

 あるいは、変数宣言じたいせずに、下記のようにWithステートメントで参照するようにできます。

    Dim i As Long, j As Long
    For i = 1 To gyo
        For j = 1 To retu
            Dim btnName As String: btnName = "Btn_" & i & "_" & j
            With Me.Controls.Add("Forms.CommandButton.1", btnName, True)
                    .Top = 15 * i + 30
                    .Left = 15 * j - 5
                    .Height = 15
                    .Width = 15
                    .Font.Size = 8
            End With
        Next j
    Next i

 もし、配列を使うなら、モジュールレベルの変数として宣言しておいて、
後から利用できるようにするといいでしょう。

 Option Explicit
 Private Btn() As MSForms.CommandButton

 Private Sub 作る_Click()
    Dim gyo As Long: gyo = 縦n.Value
    Dim retu As Long: retu = 横n.Value
    ReDim Btn(1 To gyo, 1 To retu)

    Dim i As Long, j As Long
    For i = 1 To gyo
        For j = 1 To retu
            Dim BtnName As String: BtnName = "Btn_" & i & "_" & j
            Set Btn(i, j) = Me.Controls.Add("Forms.CommandButton.1", BtnName, True)
            With Btn(i, j)
                .Top = 15 * i + 30
                .Left = 15 * j - 5
                .Height = 15
                .Width = 15
                .Font.Size = 8
            End With
        Next j
    Next i
 End Sub

 Private Sub 塗る_Click()
    Dim gyo As Long: gyo = 縦n.Value
    Dim retu As Long: retu = 横n.Value
    Btn(gyo, retu).Caption = "●"
 End Sub

 なお、現状のコードは、作るボタンは1回のみクリックするという前提です。
 何回もクリックするなら、最初に追加したコントロールを削除するコードが必要になります。

(hatena) 2021/12/04(土) 21:48


hatena様

御礼が遅くなりました。
ご指摘ありがとうございます。
大変勉強になります。

理想のマインスイーパーに一歩近づきました。
(ほわ) 2021/12/06(月) 14:48


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.