[[20220809101742]] 『【ユーザーフォーム】ラベルのクリックイベントの』(おおとりさん) ページの最後に飛ぶ

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

 

『【ユーザーフォーム】ラベルのクリックイベントのまとめ方』(おおとりさん)

いつも参考にさせていただいております。

ユーザーフォームのラベルのイベント処理について
ご教示いただけますでしょうか。

ユーザーフォーム上にラベルが20個ほどあり、
それぞれにクリックイベントを作成したいと考えております。

イベント処理の中身は同じで
ラベル1がクリックされたらテキストボックス1〜10を処理
ラベル2がクリックされたらテキストボックス11〜20を処理
・・・
といった流れです。

クリックイベントのまとめ方、クリックされたラベルの取得の仕方について
ご教示いただけますと幸いです。

以上、宜しくお願いいたします。

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


 >ユーザーフォーム上にラベルが20個ほどあり、
 >ラベル1がクリックされたらテキストボックス1〜10を処理 
 >ラベル2がクリックされたらテキストボックス11〜20を処理
 でラベルが3〜20をクリックした時、テキストボックスとの関連はどうなるのですか。
 ラベル1=テキストボックス1ではないのですか。
(・・・) 2022/08/09(火) 11:06

 >クリックイベントのまとめ方、クリックされたラベルの取得の仕方
 とりあえず↑だけ考えて...

 '正攻法(共通サブに自身を渡す)
    Option Explicit

    Private WithEvents Lbl1 As MSForms.Label
    Private WithEvents Lbl2 As MSForms.Label
    Private WithEvents Lbl3 As MSForms.Label
    Private WithEvents Lbl4 As MSForms.Label
    Private WithEvents Lbl5 As MSForms.Label
    Private WithEvents Lbl6 As MSForms.Label

    Private Sub Lbl1_Click()
        LblsClicked Lbl1
    End Sub
    Private Sub Lbl2_Click()
        LblsClicked Lbl2
    End Sub
    Private Sub Lbl3_Click()
        LblsClicked Lbl3
    End Sub
    Private Sub Lbl4_Click()
        LblsClicked Lbl4
    End Sub
    Private Sub Lbl5_Click()
        LblsClicked Lbl5
    End Sub
    Private Sub Lbl6_Click()
        LblsClicked Lbl6
    End Sub

    Private Sub LblsClicked(l As MSForms.Label)
        MsgBox l.Name
    End Sub

    Private Sub UserForm_Initialize()
        Set Lbl1 = Me.Controls.Add("Forms.Label.1", "Lbl1")
        Set Lbl2 = Me.Controls.Add("Forms.Label.1", "Lbl2")
        Set Lbl3 = Me.Controls.Add("Forms.Label.1", "Lbl3")
        Set Lbl4 = Me.Controls.Add("Forms.Label.1", "Lbl4")
        Set Lbl5 = Me.Controls.Add("Forms.Label.1", "Lbl5")
        Set Lbl6 = Me.Controls.Add("Forms.Label.1", "Lbl6")
        Lbl1.Top = 3 + Lbl1.Height * 0
        Lbl2.Top = 3 + Lbl1.Height * 1
        Lbl3.Top = 3 + Lbl1.Height * 2
        Lbl4.Top = 3 + Lbl1.Height * 3
        Lbl5.Top = 3 + Lbl1.Height * 4
        Lbl6.Top = 3 + Lbl1.Height * 5
        Dim i As Long
        For i = 1 To 6
            With Me.Controls("Lbl" & i)
                .Caption = i
                .SpecialEffect = fmSpecialEffectRaised
            End With
        Next
    End Sub

 'お遊び(透明なラベルを上にかぶせてクリック位置から逆算する)
    Option Explicit

    Private Lbl1 As MSForms.Label
    Private Lbl2 As MSForms.Label
    Private Lbl3 As MSForms.Label
    Private Lbl4 As MSForms.Label
    Private Lbl5 As MSForms.Label
    Private Lbl6 As MSForms.Label
    Private WithEvents LblCv As MSForms.Label

    Private Sub LblCv_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
        If X < 0 Or Y < 0 Then Exit Sub
        If X > LblCv.Width Or Y > LblCv.Height Then Exit Sub
        If Button = 1 Then
            Dim h As Single
            h = Lbl1.Height
            MsgBox Int(Y / h) + 1 & "番"
        End If
    End Sub

    Private Sub UserForm_Initialize()
        Set Lbl1 = Me.Controls.Add("Forms.Label.1", "Lbl1")
        Set Lbl2 = Me.Controls.Add("Forms.Label.1", "Lbl2")
        Set Lbl3 = Me.Controls.Add("Forms.Label.1", "Lbl3")
        Set Lbl4 = Me.Controls.Add("Forms.Label.1", "Lbl4")
        Set Lbl5 = Me.Controls.Add("Forms.Label.1", "Lbl5")
        Set Lbl6 = Me.Controls.Add("Forms.Label.1", "Lbl6")
        Lbl1.Top = 3 + Lbl1.Height * 0
        Lbl2.Top = 3 + Lbl1.Height * 1
        Lbl3.Top = 3 + Lbl1.Height * 2
        Lbl4.Top = 3 + Lbl1.Height * 3
        Lbl5.Top = 3 + Lbl1.Height * 4
        Lbl6.Top = 3 + Lbl1.Height * 5
        Dim i As Long
        For i = 1 To 6
            With Me.Controls("Lbl" & i)
                .Caption = i
                .SpecialEffect = fmSpecialEffectRaised
            End With
        Next
        Set LblCv = Me.Controls.Add("Forms.Label.1", "LblCv")
        LblCv.Top = 3
        LblCv.Height = LblCv.Height * 6
        LblCv.BackStyle = fmBackStyleTransparent
    End Sub

 あとクラスモジュール使ってイベントをまとめる手法もありますね。
 (モジュール分かれるから個人的には好きではないですが ^^;)

(白茶) 2022/08/09(火) 11:20


 >ユーザーフォーム上にラベルが20個ほどあり、
 >ラベル1がクリックされたらテキストボックス1〜10を処理 
 >ラベル2がクリックされたらテキストボックス11〜20を処理
 でラベルが3〜20をクリックした時、テキストボックスとの関連はどうなるのですか。
 ラベル1=テキストボックス1ではないのですか。
(・・・)

返信ありがとうございます。

ラベル3以降もテキストボックス21〜30と10単位で増加していきます。
処理の中身はラベルをクリックしたら、クリックしたらラベルの文字色(forecolor)を赤、
ラベルと関係のないテキストボックスは入力不可 enabled = False、Locked = True と処理しています。

例)
ラベル1をクリック

ラベル1の文字色を赤
ラベル2〜20の文字色を黒
テキストボックス1〜10を Enabled = True Locked = False
テキストボックス11〜200を Enabled = False Locked = True

上記の処理をラベル分作成するのが大変なため、まとめたいと考えております。

(おおとりさん) 2022/08/09(火) 11:51


(白茶)さん

返信、コードの提案ありがとうございます。

正攻法のコードで処理が可能か試させていただきます。

(おおとりさん) 2022/08/09(火) 11:53


標準モジュールModule1に

Public sumControls() As New UserForm1

Sub SummationControls()

    '
    Dim uf As UserForm
    Dim ctrl As Control
    Dim cnt As Long, idx As Long
    Dim ctrlName As String

    '
    Set uf = UserForm1

    With uf
        cnt = .Controls.Count
        For idx = 1 To cnt
            Set ctrl = .Controls(idx - 1)
            ctrlName = ctrl.Name
            With Module1.sumControls(idx)
                Select Case True
                    Case ctrlName Like "Label*"
                        Set .Lbl = ctrl
                    Case ctrlName Like "Text*"
                        Set .Txt = ctrl
                    Case Else
                End Select
            End With
        Next idx
    End With

End Sub

でユーザーフォームUserForm1に

Public WithEvents Lbl As MSForms.Label
Public WithEvents Txt As MSForms.TextBox

Private Sub Lbl_Click()

    'ここに処理を記述
    'Lbl.index でそれぞれのインデックスが取得できる

End Sub

Private Sub Txt_Click()

    'ここに処理を記述
    'Txt.index でそれぞれのインデックスが取得できる

End Sub

ではどうですか?
(ngk) 2022/08/09(火) 13:47


複数のオプションから一つを選択したいということですよね。
ならば、ラベルではなく、オプションボタンを使うのが適していると思います。
Windowsの標準のUIに沿った設計の方がユーザーも戸惑わないと思います。
また、その方がコードもスッキリします。

ユーザーフォーム上にフレーム「Frame1」を配置します。その中に、オプションボタンを20個配置します。(OptionButton1 〜 OptionButton20)
フレーム内にオプションボタンを配置することでグループ化されてその中の一つだけ選択できるようになります。

テキストボックス名は Textbox1 〜 Textbox200 とします。

 Private Sub OptionButton1_Click()
    optCheck
 End Sub

 Private Sub OptionButton2_Click()
    optCheck
 End Sub

'中略・・・・

 Private Sub OptionButton20_Click()
    optCheck
 End Sub

 Public Sub optCheck()
    Dim opt As Control, i As Long, j As Long

    For Each opt In Me.Frame1.Controls
        If opt.Value = True Then
            opt.ForeColor = vbRed
            For i = 1 To 200
                With Me.Controls("Textbox" & i)
                    .Enabled = False: .Locked = True
                End With
            Next
            j = Mid(opt.Name, 13) * 10 - 10
            For i = 1 To 10
                With Me.Controls("Textbox" & i + j)
                    .Enabled = True: .Locked = False
                End With
            Next
        Else
            opt.ForeColor = vbBlack
        End If
    Next    
 End Sub

もし、フレーム内に配置したくないという場合、オプションボタンの GroupNameプロパティを同じに設定すればグループ化されます。
(hatena) 2022/08/09(火) 14:21


 ついでに、ありきたりな手法をもうひとつ ^^;

 各コントロールのTagプロパティに、あらかじめグループ名を入れておいて
 そのグループ名をキーにして巡回処理を共通化する。という...

    Private CurrentTagStr As String
    Private Property Get CurrentGroup() As String
        CurrentGroup = CurrentTagStr
    End Property
    Private Property Let CurrentGroup(newGroup As String)
        If newGroup = CurrentTagStr Then Exit Property
        CurrentTagStr = newGroup
        Dim c As Control
        For Each c In Me.Controls
            If TypeOf c Is MSForms.Label Then c.ForeColor = IIf(c.Tag = CurrentTagStr, vbRed, &H80000012)
            If TypeOf c Is MSForms.TextBox Then
                c.Enabled = CBool(c.Tag = CurrentTagStr)
                c.Locked = Not c.Enabled
            End If
        Next
    End Property

    Private Sub Label1_Click()
        CurrentGroup = "G1"
    End Sub
    Private Sub Label2_Click()
        CurrentGroup = "G2"
    End Sub
    Private Sub Label3_Click()
        CurrentGroup = "G3"
    End Sub

(白茶) 2022/08/09(火) 14:24


(ngk)さん
(hatena)さん
(白茶)さん

皆様、コードをご提案いただきありがとうございます。
同じ結果でも多様な方法があると改めて勉強になっております。

私の知識不足で調べてみないとわからない部分もあるため、
ひとつひとつ理解しながら試して最良なコードを探してみます。

合わせてオプションボタンへの変更も検討してみたいと思います。

(おおとりさん) 2022/08/09(火) 14:48


ごめんなさい、redimを忘れてました

    With uf
        cnt = .Controls.Count
        Redim module1.sumControls(cnt) ←これ書き忘れてました

        For idx = 1 To cnt
            Set ctrl = .Controls(idx - 1)

(ngk) 2022/08/09(火) 16:12


 こんにちは、質問ですが

 テキストボックス200個は、UserForm1 に
 全部...並んでるんですか?

(あみな) 2022/08/09(火) 16:31


テキストボックス200個作成するのは大変だったでしょう。
でどのような感じで使用しているのでしょうか。
(・・・) 2022/08/09(火) 16:49

(ngk)さん

ご丁寧にありがとうございます。
追記しコードを試させていただきます。

(あみな)さん

はい、10列20行の形で並んでいます。
業務の処理上、この形が一番見やすいので上記で配置しています。

テキストボックスの入力処理はfor文とcontrolsで処理が可能なので
今回のクリックイベントの共通化を理解することができればとても楽になります。
(おおとりさん) 2022/08/09(火) 16:56


(・・・)さん

テキストボックスの配置については10個 * 20 行分といった形なので
10個分を作成したらコピペで配置できたのでそこまで大変ではありませんでした。

購買業務で使用しています。
1品種につき20社分の見積情報から購入先を選定する際に一覧表示できるように作成しています。
伝わりづらければ申し訳ありません。。。
(おおとりさん) 2022/08/09(火) 17:05


>伝わりづらければ申し訳ありません。。。
そうでしたか。分かりました。
(・・・) 2022/08/09(火) 17:20

TextBox 200個
こちらの方こそ、クラスモジュールに
纏めないと大変ではないですか?

AddinBox/擬似からの脱却
http://addinbox.sakura.ne.jp/Breakthrough_P-Ctrl_Arrays.htm

汎用モジュール/clsBPCA を使って
サンプルコード を参考にすれば
かなり楽になると思いますよ。
(clsBPCA 自体は一切編集する必要はありません)
(AddinBox_角田) 2022/08/10(水) 10:32


(AddinBox_角田)さん

コメントありがとうございます。

テキストボックスの処理については 処理列とテキストボックスの番号を合わせることで
そこまでコードを書かなくても処理ができております。
(最適なコードであるかはわかりませんが。。。)

例)
UserForm.Controls("textbox" & j).Value = Worksheets.Cells(行, j)
UserForm.Controls("textbox" & j).ControlSource= Worksheets.Cells(行, j)Address(RowAbsolute:=False, ColumnAbsolute:=False)

汎用モジュール/clsBPCA の件、URLまでありがとうございます。
初めて聞く処理のため理解が必要ですが、今回のラベルのクリックイベントでも使用できるかもしれません。
テキストボックスの処理の改善も含め、早速読んでみたいと思います。

(おおとりさん) 2022/08/10(水) 12:28


 こんばんは、
 テキストボックス200個は、UserForm1 に全部並んでるんですね。

 業務では、処理スピードと、見やすさも重要かと
 思われるので...やりやすい方法が一番良いのですが

 ユーザーフォームの画面が大きいので大迫力だな〜と
 想像しております。

 そちらの処理と、全画面がわからないので...良し悪しがわかりませんので
 一案ではありますが…どうなのでしょうか?^^;

 マルチページを使用して、テキストボックスを10個ずつ
 処理と、表示をさせることを検討されてはと思ったので
 参考程度ですが

 私が、「 ファイルなう 」と言うサイトへ… アップロードしたファイルです。                                                                               
 Windowsフォトビューアーで画像だけが閲覧可能です。

 クリックイベントでも、オプションボタンでもよいのですが
 ユーザーフォームの初期画面から、選択して Opt1 を選択

 ◇1 ダウンロードURL: 購買管理初期値.JPG(53 KB)             
https://d.kuku.lu/1c9587d49

 Opt1 選択後、コマンドボタンクリックから
 画面を表示切替して、テキストボックスへ処理反映させたのが

 ◇2 ダウンロードURL: Opt1.JPG(49 KB)             
https://d.kuku.lu/c90521478

 切替は、購買管理画面に戻り… Opt3 を選択後に表示切替させたのが下記URL

 ◇3 ダウンロードURL: Opt3.JPG(48 KB)             
https://d.kuku.lu/fb374b516

 ◆「 ファイルなう 」運営者情報                                       
 くくさま @kukusama                                                 
https://twitter.com/kukusama    

(あみな) 2022/08/10(水) 22:02


.ControlSource でセルと連結しているなら、ユーザーフォーム上には、
オプションボタン20個、テキストボックス20個を配置しておいて、
オプションボタンを選択したときに、テキストボックスの .ControlSource を切り替えるという
設計でもよさそう。

200個のデータをすべて一覧表示させておく必要があるのならだめですが、シートには一覧表示されているのなら、なくてもよさそうに思いますがいかがでしょう。

ちなみに、下記のコードの1行目は不要では。ControlSourceでリンクさせれば、セルの値は自動で反映されますので。

 UserForm.Controls("textbox" & j).Value = Worksheets.Cells(行, j)
 UserForm.Controls("textbox" & j).ControlSource= Worksheets.Cells(行, j).Address(RowAbsolute:=False, ColumnAbsolute:=False)

(hatena) 2022/08/11(木) 12:28


上の回答の、

オプションボタン20個、テキストボックス20個を配置しておいて、

上記の部分は下記に訂正です。

オプションボタン20個、テキストボックス10個を配置しておいて、

コードとしては下記になります。

 Private Sub OptionButton1_Click()
    optCheck
 End Sub
 Private Sub OptionButton2_Click()
    optCheck
 End Sub
'中略・・・・
 Private Sub OptionButton20_Click()
    optCheck
 End Sub

 Public Sub optCheck()
    Dim opt As Control, i As Long, j As Long
    For Each opt In Me.Frame1.Controls
        If opt.Value = True Then
            opt.ForeColor = vbRed
            j = Mid(opt.Name, 13)
            For i = 1 To 10
                Me.Controls("Textbox" & i).ControlSource = Worksheets(1).Cells(i, j).Address(False, False)
            Next
        Else
            opt.ForeColor = vbBlack
        End If
    Next
 End Sub

(hatena) 2022/08/11(木) 12:46


(あみな)さん

サンプル画面の作成をしていただきありがとうございます。
業務用のエクセルなので直接画面を乗せることができませんが、
200個のテキストボックスがすべて並んだ状態が見やすい形となっています。
10個ずつとなると少し見やすさに欠けてしまう状態となってしまいます。。。
わざわざ作成していただいたのにすみません。。。

(hatena)さん

コメントありがとうございます。
すべてのテキストボックスが並んでいることが最良な形となっています。
シートにも一覧表示されていますがシート画面の状態ですと見づらいため
今回のユーザーフォーム画面を作成しています。

1行目のコード不要の件、ご指摘ありがとうございます。
動作可能か試させていただきます。

皆様に挙げて頂いたコードを読みながら自分が実装できる範囲で作成しております。
現在、以下の形でおおよそ理想な処理ができるようになりました。

 Private Sub Label1_Click(): call 購入処理(1): End sub
 Private Sub Label2_Click(): call 購入処理(2): End sub
 Private Sub Label3_Click(): call 購入処理(3): End sub

〜 20まで

 Private Sub 購入処理(ラベル番号)

select case ラベル番号

     case 1
          開始番号 = 1
          終了番号 = 10
     case 2
          開始番号 = 11
          終了番号 = 20
     case 3
          開始番号 = 21
          終了番号 = 30

〜 20まで

for i = 1 to 200 'テキストボックス処理用

     select case i
          case 開始番号 to 終了番号
               該当テキストボックス処理
          Else case 
               非該当テキストボックス処理
     end case
next

(おおとりさん) 2022/08/12(金) 10:38


コメント返信:

[ 一覧(最新更新順) ]


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