[[20170216234655]] 『ユーザーフォームについて』(あいり) ページの最後に飛ぶ

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

 

『ユーザーフォームについて』(あいり)

ユーザーフォームでどこまで出来るか教えて下さい。゚(゚´Д`゚)゚。

例えばユーザーフォームで”有”と”無”というオプションボタン
(チェックボックスでもいいのですが、選択はどちらか1つのみ)、を
選ぶボタンがあるとします。

その下にA,B,Cというコマンドボタンがあるとします。

有を選択すれば、A,B,Cどれかを選べるようにし、
無を選択すれば、ボタン選択出来なくなるようにします。

その下に表示というコマンドボタンを作り、
有無の選択と有の場合のA〜Cの選択が無ければ、
「選択されてません」などの表示がでるようにします。

最初の無の場合は、無と同じシート名のシートのみが表示され、
有の場合は、有と同じシート名のシートと、選択したA〜Cの
シート2種類が表示されるようにしたいのですが、
可能でしょうか??

もし可能でしたら、どなたかユーザーフォームのVBAの書き方か、
ヒントを教えて下さい。゚(゚´Д`゚)゚。

< 使用 Excel:Excel2013、使用 OS:Windows7 >


 >あいり さん
http://www.eurus.dti.ne.jp/~yoneyama/Excel/vba/index.html
 ヒント(22のユーザーフォームを利用するの項目に、
        ◦オプションボタンの使い方 
        などがありますので、参考にしてください。)

 >最初の無の場合は、無と同じシート名のシートのみが表示され、 
 >有の場合は、有と同じシート名のシートと、選択したA〜Cの 
 >シート2種類が表示されるようにしたいのですが、

 無と同じシート名? 有と同じシート名のシート?
 選択したA〜Cのシート?
 例えば、A〜Cは、Sheet3〜Sheet5の文字列ですか?
 無と書いてますが、Sheet1の文字列ですか?
 有と書いてますが、Sheet2の文字列ですか?例えばですが。

 ********************************************
 無のときは、リストを表示せず、
 有のときは、A〜Cのリストを表示するの部分だけ、
 マクロを使用せずに、リストを使用するのが、簡単でいいと思いますが
http://note.chiebukuro.yahoo.co.jp/detail/n149222

 他の部分は、マクロですが。
(マリオ) 2017/02/17(金) 09:41

 直接の質問テーマからは、ちょっとはずれますけど、

 >その下にA,B,Cというコマンドボタンがあるとします。 

 通常、コマンドボタンは、それをクリックしたら、何らかの処理を実行します。
 (もちろん、実行しなくてもいいのですが、普通は 実行します)

 でも、このユーザーフォームで、実際の動作というか、実行は あくまで

 >その下に表示というコマンドボタンを作り、 

 この 表示 というコマンドボタンが押され時で、A,B,C は、有、無 とともに、どのように
 実行させるかという 単なる条件ですよね?

 なので、これらはコマンドボタンにはせず、有、無 とは 別にグループ化されたオプションボタンにしておくのが
 素直なデザインだと思いますね。

(β) 2017/02/17(金) 13:53


 質問です。(マリオさんとカブるところがありますが)

 >>無と同じシート名のシート
 >>有と同じシート名のシート
 >>選択したA〜Cのシート

 これらのシート名って具体的には? 
 また、実行結果は ブックの指定されたシートのみが表示状態、あとのシートは非表示状態 になる ということですね?

 それと、有 というオプションボタンとか A,B,C というコマンドボタンとか 表示  というコマンドボタン
 といった表現をしておれれます。

 これは、本当に、そのコントロールのオブジェクト名が 有 とか A とか 表示 ということですか?
 それとも、オブジェクト名は別途あり、単に、キャプションとして表示されている文字列が 有 とか A とか 表示 ということですか?

(β) 2017/02/17(金) 14:11


マリオさま

なかなか仕事が終わらず、お返事遅くなり申し訳ございません。゚(゚´Д`゚)゚。

拙い説明ですみません!

有、無、A、B、Cはすべてシート名です。

チェックボタンのチェック内容によって、
必要なシートの表示、非表示をさせたいとおもっています。

リストというのも良いかもしれませんね(*^^*)
リストで選んだ結果によって、どのシートを表示させるか、という
マクロを組めばいいということですよね!

ただ、他の人も使うので、出来ればユーザーフォームのような形が良かったのですが。。。
もっと勉強して出直してまいります。゚(゚´Д`゚)゚。

βさま

グループ化されたオプションボタンってなんでしょう??
ごめんなさい不勉強で。゚(゚´Д`゚)゚。

有と無は実際と同じシート名です。
ABCは地名です。
具体的には、A大阪、B兵庫、C名古屋です。

実行結果は、指定されたシートのみが表示され、他は表示されない、というものです。

仕事で使う資料なのですが、組み合わせをよく間違えやすいので、
選択した結果、必要シートのみ表示されるという
フォーマットがあれば、便利かと思い質問しました(>人<;)
(あいり) 2017/02/17(金) 21:34


 >グループ化されたオプションボタンってなんでしょう?? 

 オプションボタンは、何もしなければ、たとえば 5つあったとして、どれかが選択されて ポッチ(?)がついたら
 他のオプションボタンのポッチは消えますね。
 常に 1つだけが選ばれた形になりますね。

 仮に オプションボタンで選びたいグループが 2つあったとします。

 1つのグループは 有 と 無。
 2つめのグループは A と B と C。

 つまり 有 と 無 のいずれかを選びたい。 また AかBかCのいずれかを選びたい。
 ところが何もしないで 有 を選んで 次に B を選ぶと 有 のポッチ が消えますね。
 せっかく選んだのに。

 こういう場合、オプションボタンのプロパティに GroupName というものがあるんですが(初期値は空白になっています)
 このGroupName を 有 と 無 のオプションボタンには、たとえば umu というグループ名をセット。
 A と B と C のオプションボタンのGroupName には、たとえば abc とセットしておく。

 そうすると、有、無 と A、B、Cが 別グループになって、それぞれのグループで1つ選ぶことができるようになります。

 もう1つ方法があります。

 ユーザーフォーム上に Frame を配置します。 で、その上に オプションボタンを配置します。
 それとは別のFrame を配置します。 で、その上にもオプションボタンを配置します。

 こうしておくと、それぞれのFrame上のオプションボタンだけが 1つのグループだと認識され
 それぞれで、1つ選ぶことができます。 この場合、GroupName の設定は不要です。

 こちらで A,B,C もオプションボタンにして書いたコードサンプルが2つほどあります。
 もしよかったらアップします。

 ただ、質問した事項、コントロールの名前について、回答をもらっていないので、コードが完成していません。
 たとえば 「有 というオプションボタン」、このオプションボタンのオブジェクト名は OptionButton1 といったもので
 そのキャプションとして 有 という文字が表示されているのですか?

 それとも、オブジェクト名も 有 に変更してあるのですか?

( β) 2017/02/17(金) 22:01


βさま

オプションボタンはグループで分けると、同じエクセル内でも各グループで1つづつ選べるんですね( ゚д゚)

ごめんなさい、まだ、どのボタンでいくか決めてなかったので、
配置してません(>人<;)なので、各ボタンの
オブェクト名もまだです。゚(゚´Д`゚)゚。
(あいり) 2017/02/17(金) 22:18


 少しわかりにくいかもしれませんがサンプルです。

 まず、OptionButton1 〜 OptionButton5 を配置してください。
 (コントロール名は、配置後任意の名前にしてもいいのですが、とりあえず デフォルトでつけられる名前で)

 OptionButton1 と OptionButton2 を マウスで選んで GroupName に umu とセット。
 (2つのオプションボタンに一括でセットできます)

 OptionButton3,OptionButton4,OptionButton5 をマウスで選んで GroupName に abc とセット。

 これら GroupName の文字列は任意です。お好きなものでOK。
 コードでは、一切参照していません。
 単に、オプションボタンのグループ分けのためです。

 それぞれのキャプションには "有" とか "無" とか "A" とか "兵庫" といった、わかりやすいものを
 セットしておきましょう。(なんでもOKです。コードでは、このキャプションは参照していませんので)

 CommandButton1 も配置してください。キャプションを "シート切替" とか "表示" といったものにしておきましょう。

 で、ユーザーフォームモジュールに以下。

 Private Sub CommandButton1_Click()  '表示
    Dim valABC As String
    If OptionButton1.Value Then  '有
        If OptionButton3.Value Then valABC = "A"
        If OptionButton4.Value Then valABC = "B"
        If OptionButton5.Value Then valABC = "C"
        Select Case valABC
            Case "A"
                SheetShow "有", "大阪"
            Case "B"
                SheetShow "有", "兵庫"
            Case "C"
                SheetShow "有", "名古屋"
            Case Else
                MsgBox "A,B,C が未選択です"
        End Select
    ElseIf OptionButton2.Value Then
        SheetShow "無"
    Else
        MsgBox "有、無 が未選択です"
        Exit Sub
    End If
 End Sub

 Private Sub OptionButton1_Click()   '有
    setABC
 End Sub

 Private Sub OptionButton2_Click()   '無
    setABC
 End Sub

 Private Sub setABC()
    OptionButton3.Enabled = OptionButton1.Value   'A
    OptionButton4.Enabled = OptionButton1.Value   'B
    OptionButton5.Enabled = OptionButton1.Value   'C
 End Sub

 Private Sub SheetShow(ParamArray v())
    Dim sh As Worksheet
    Dim z As Variant
    z = v
    Sheets("有").Visible = True
    Sheets("無").Visible = True
    For Each sh In Worksheets
        If IsNumeric(Application.Match(sh.Name, z, 0)) Then
            sh.Visible = True
        Else
            sh.Visible = False
        End If
    Next
 End Sub

 なお、setABC を以下にすると、また違った表示効果になります。
 お好きなほうで。

 Private Sub setABC()
    OptionButton3.Visible = OptionButton1.Value
    OptionButton4.Visible = OptionButton1.Value
    OptionButton5.Visible = OptionButton1.Value
 End Sub

( β) 2017/02/18(土) 11:47


βさま

お返事遅くなりごめんなさい(>人<;)

希望していた通りの結果になり、いまパソコンの前で嬉し泣きしてます。゚(゚´Д`゚)゚。

すごいですね!!ありがとうございます!

少しコードで教えて欲しいのですが、

  >  OptionButton3.Enabled = OptionButton1.Value   'A
  >  OptionButton4.Enabled = OptionButton1.Value   'B
  >  OptionButton5.Enabled = OptionButton1.Value  

enabledって、trueかfalseで繋ぐのしか知らなかったのですが、
この場合は、オプションボタン1を選択するとABCの
ボタンを無効にしない、ということですか??

あと、

ParamArray と

 >   If IsNumeric(Application.Match(sh.Name, z, 0)) Then

の部分の意味を教えていただけますでしょうか??

ParamArray は調べたのですが、あまりよく分からず、、、(>人<;)

お忙しいところごめんなさい!
本当に暇な時でいいので、教えて欲しいです。゚(゚´Д`゚)゚。

(あいり) 2017/02/19(日) 02:02


 *****************************************************************
 >β先生
 間違ってましたら訂正お願いします。

 *****************************************************************
 >あいり さん
 うまく説明できてないかもしれませんが…。

 >この場合は、オプションボタン1を選択するとABCの 
 >ボタンを無効にしない、ということですか?? 

 そうだと思います。オプションボタン1を選択すると
 OptionButton1=Trueになる。一方、グループ化した他方の
 オプションボタン2は、OptionButton2=Falseになる。
 逆に、オプションボタン2を選択すると
 グループ化したオプションボタン1は、OptionButton1=Falseになり、
 オプションボタン2は、OptionButton2=Trueになる。
 (※OptionButton1 と OptionButton2 は、GroupName に umu とセットしました)

 もし、★仮に、グループ化をしない場合、コード内で、
 次のように記述することになるんじゃないでしょうか?
 Private Sub OptionButton1_Click()   '有
     OptionButton1.Value=True'★
     OptionButton2.Value=False'★
     setABC
 End Sub
 Private Sub OptionButton2_Click()   '無
     OptionButton1.Value=False'★
     OptionButton2.Value=True'★
     setABC
 End Sub

 余談ですが、「setABC」の箇所は、「Call setABC」と書いた方が、
 分かりやすいかも(※他のプロシージャを読み込んでいる)。
 同様に、「SheetShow "有", "大阪"」
 →「Call SheetShow ("有", "大阪")」と書いた方が、
 分かりやすいかも。
 「SheetShow "有", "兵庫"」、「SheetShow "有", "名古屋"」も同様。
 _
 _
 _
 _
 >ParamArray と 
 >   If IsNumeric(Application.Match(sh.Name, z, 0)) Then
 >の部分の意味を教えていただけますでしょうか?? 

 シートが、左から「有」「無」「大阪」「兵庫」「名古屋」の順番で
 5枚あるとすると、For Each sh In Worksheets〜Next内での処理なので、
 sh.Nameには、順番に、「有」「無」「大阪」「兵庫」「名古屋」の文字列が入る。

 「SheetShow "有", "大阪"」としているケースでは、
 Private Sub SheetShow(ParamArray v())で、受け取っている
 v配列は、「v(0)=有」、「v(1)=大阪」の2つの文字列を格納した配列になる(下記の★Debug処理参照)。
 (v(0)とあるように、番号は、0からはじまります。)
 v()配列を、なぜz配列に格納し直さないといけないのかについては、
 …?なぜだろう? 下記のコード★で、TypeNameを使って型を確認したら、
 v()配列もvariant型ですね。

  Application.Match(sh.Name, z, 0)で、sh.Nameは1つの文字列、
 zは、variant型のArray配列で、この場合、計2回、一致しているかどうかの確認をしている。一致していると、返り値として番号が返る。
 Debug(★下記参照)してみましたら、For Each sh In Worksheets〜Nextしているので、「2」,「1」の順番で番号が返りました。
 3回やって、3回とも「2」,「1」の順番だったが、「1」,「2」の順番になることもあるような…?
 IsNumericは、数字かどうかの判定です。
 **************************************************************
 Private Sub SheetShow(ParamArray v())
    Dim sh As Worksheet
    Dim z As Variant

    Debug.Print "v開始番号: " & LBound(v) '★
    Debug.Print "v終了番号: " & UBound(v) '★
    Debug.Print "v開始: " & v(LBound(v)) '★
    Debug.Print "v終了: " & v(UBound(v)) '★
    Debug.Print "vの型: " & TypeName(v) '★
    z = v
    Debug.Print "zの型: " & TypeName(z) '★

    Sheets("有").Visible = True
    Sheets("無").Visible = True
    For Each sh In Worksheets
        If IsNumeric(Application.Match(sh.Name, z, 0)) Then
        Debug.Print Application.Match(sh.Name, z, 0) '★
 **************************************************************
(マリオ) 2017/02/19(日) 08:47

 マリオさんから説明がアップされましたけど、メモしましたので。

 まず、

 >>OptionButton3.Enabled = OptionButton1.Value   

 これについてのみ。ParamArray については、レスを分けます。

 左辺の OptionButton3.Enabled は OptionButton1 というオブジェクトが持っている Enabled という名前のプロパティを示します。
 ふつうの変数 と考えてください。与えることができる値は TrueかFalseのいずれかですね。

 こんなコードがわかりやすいでしょうか。

 変数1 = True
 変数2 = 変数1

 変数2 には True が格納されますね。

 やりたかったことは。OptionButton1(有)が選ばれていたら OptionButton3.Enable の値を True にしたい、
 選ばれていなかったら OptionButton3.Enabled の値を False にしたい。こういうことですね。

 で、『たまたま』ですけど、OptionButton1 が選ばれていれば、OptionButton1.Value は True です。
 選ばれていなければ False です。
 そういった値が OptionButton1.Value というプロパティに入っています。
 これは、まさしく、条件によってOptionButton3.Enabled にセットしたい値と一致してますね。

 なので、変数2 = 変数1 の記述で、セットすべきものがセットされるということです。

 わかりにくいですかね?

 あぁ、レスするためにコードを眺めていましたら、おバカだなぁというところに気が付きました。

    OptionButton3.Enabled = OptionButton1.Value   'A
    OptionButton4.Enabled = OptionButton1.Value   'B
    OptionButton5.Enabled = OptionButton1.Value   'C

 もちろん、これでもいいのですが、仮に右辺 OptionButton1.Value の参照を
 別のものに変えたとします。
 (別のオプションボタンを判定、あるいは 初期値としての OptionButton1 という名前を opt有 という名前に変えた)

 そうすると、3行の右辺を変更しなければいけません。

 OptionButton3〜5 の Enabled は、一蓮托生、同じ値ですから

    OptionButton3.Enabled = OptionButton1.Value   'A
    OptionButton4.Enabled = OptionButton3.Enabled   'B
    OptionButton5.Enabled = OptionButton3.Enabled   'C

 このように書いておくと、コード変更は最初の1行だけで済みますね。

 同様に

    OptionButton3.Visible = OptionButton1.Value
    OptionButton4.Visible = OptionButton1.Value
    OptionButton5.Visible = OptionButton1.Value

 これも

    OptionButton3.Visible = OptionButton1.Value
    OptionButton4.Visible = OptionButton3.Visible
    OptionButton5.Visible = OptionButton3.Visible

 と書いたほうがよかったです。

( β) 2017/02/19(日) 08:58


 ParamArray の説明の前に。

 >「setABC」の箇所は、「Call setABC」と書いた方が、 分かりやすいかも

 たしかに わかりやすいかもしれませんね。 あぁ、これは別のサブプロシジャを実行してるんだなと 視覚的にわかりますからね。

 MsgBox "Hello" と書きますね。Call MsgBox("Hello") とは、あまり書きませんね。
 まぁ、 MsgBox という超有名な関数名と setABC という、なんじゃこれ? という名前の 認知度の違いもありますから
 setABC の場合は Call 文 で記述したほうがわかりやすいでしょうね。

 > v()配列を、なぜzに格納し直さないといけないのか

 私もそう思いますね。でも、エラーになるからしょうがない。
 ほかにもありますね。たとえば Typeステートメントを シートモジュール等のプライベートモジュールに記述すると
 コンパイラーから叱られますね。Private Type として記述しなければいけない。
 変数なんかは プライベートモジュールであっても Public 記述をして、別モジュールのコードから
 記述されたモジュール名.その変数 で参照できるのに。

 まぁ、コンパイラーにはコンパイラーの事情があるんでしょうから、仕様として受け入れるしかないでしょうけど。

 で、本題です。

 Application.Match(sh.Name, z, 0) については マリオさんの説明通り、そのシートが表示対象かどうかを
 判定しているところですので、もうおわかりですね。

 ●ParamArray

 たとえば 行番号と列番号を与えて処理するサブプロシジャを書こうとすると

 Sub abc(i As Long, j As Long)
    MsgBox Cells(i, j).Address
 End Sub

 こんな、引数2つのサブプロシジャにしますね。

 で、使う場合は Call sbc(10,20)  こんなように記述しますね。

 この場合引数が2つと決まっていますから、サブプロシジャ側の引数規定も2つ書くわけです。

 今回、書きたいなと思ったサブプロシジャは、いくつかわからないけど、必要なシートを、必要なだけ記述して
 それを表示させる。1シートかもしれないし、100シートかもしれない。

 こういった場合、サブプロシジャ側の引数規定に Optional を付けておくことで、指定してもいいし、省略してもいい
 という記述にすることができます。(この場合 データ型は VAriantにしておく必要があります)

 Sub abc(Optional s1 As Variant, Optional s2 As Variant, ・・・・・,Optional s100 As Variant)

 こうしておけば サブプロシジャ内で 

 If Not IsMissing(s1) Then

    s1 処理
  End If

 If Not IsMissing(s2) Then

    s2 処理
  End If

   ・
   ・
   ・

 If Not IsMissing(s100) Then

    s100 処理
  End If

 こんな処理ができますし、使うほうは Call abc("Sheet1","Sheet3") とか Call abc("Sheet5") とか Call abc("Sheet2","Sheet4","Sheet80")
 と書くことで利用可能です。

 でも、もし、101個の指定をしたかった場合、サブプロシジャの引数規定を変更しなければいけませんね。
 なにより、サブプロシジャ側のコード記述が煩雑というか、もう大変。非現実的なものになりますね。

 こんなとき便利なのが、サブプロシジャ側で 引数を ParamArray として宣言しておくこと。
 こうしておけば、使う側が Call abc(●,□,▼,○,・・・・・) といくつ指定しようが、それを 1次元配列に格納して
 サブプロシジャに渡してくれます。サブプロシジャ側では、この渡された配列を、ごくごく普通の配列として参照できますから
 使う側で与えた引数をすべて取得できるわけで、コードとしてもすっきりします。

 (もっとも、マリオさんがふれたように、別関数の引数として、その配列を与えるとコンパイラーエラーになる、それだけが例外です)

( β) 2017/02/19(日) 09:48


 >あいり さん

 余談ですが、■*****以降のコードを追加すると、次のようになります。

 ・エクセルファイルを最大化表示で起動した後に自動で、
   フォームがA1セルの左上に合わせた位置で立ち上がります。
   シートは「無」だけになる。
 (フォームが立ち上がったとき、「無」ラジオボタンが選択された状態にしている)

 ・「有」または「無」シートのA1セルを左ダブルクリックすると、
 フォームが立ち上がります。

 ・フォームで「表示ボタン」を押した後に、フォームを閉じます。

 ■UserForm1に記述するコード
 *****************************************************************
 ◆(1)既存のプロシージャ【Private Sub SheetShow(ParamArray v())】
    の最後のEnd Subの前の行に、次の1行を追加。
    Unload UserForm1

 ◆(2)次のプロシージャを新規に記述
  Private Sub UserForm_Initialize()
    With UserForm1
        .Caption = "Excel シート選択"
        '------- 画面中央に表示 -------
        '.StartUpPosition = 2
        '------- A1セルの左上に合わせて表示 ------------------
         .StartUpPosition = 0
         .Left = ActiveWindow.PointsToScreenPixelsX( _
                 Range("A1").Left) * (72 / 96) - 2 '-2は微調整
         .Top = ActiveWindow.PointsToScreenPixelsY( _
                Range("A1").Top) * (72 / 96)
        '-----------------------------------------------------
    End With

    OptionButton2.Value = True '「無」を選択
 End Sub
 *****************************************************************
 '_
 '_
 ■ThisWorkbookに記述するコード
 *****************************************************************
 Option Explicit

 Private Sub Workbook_Open()
    Application.WindowState = xlMaximized 'Excelを最大化表示

    ThisWorkbook.Sheets("無").Visible = True
    Dim sh As Worksheet
    For Each sh In Worksheets
        If Not (sh.Name = "無") Then sh.Visible = False '特定のシート以外を非表示
    Next

    Call UserForm1表示
 End Sub
 *****************************************************************
 '_
 '_
 ■Module1に記述するコード
 *****************************************************************
 Option Explicit

 Sub UserForm1表示()
    UserForm1.Show vbModeless
 End Sub

 '---- おまけ ---------------
 Sub 全てのシートを表示()
    Dim sh As Worksheet
    For Each sh In Worksheets
         sh.Visible = True
    Next
    MsgBox "全シート表示!"
 End Sub
 *****************************************************************
 '_
 '_
 ■シート(「シート名:有」「シート名:無」)に記述するコード
 *****************************************************************
 Option Explicit

 Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
     If Target.Count > 1 Then Exit Sub
     If Target.Address <> "$A$1" Then Exit Sub
     Cancel = True
     Call UserForm1表示
 End Sub
 *****************************************************************

(マリオ) 2017/02/19(日) 18:07


βさま
マリオさま

お二人とも、このたびは誠にありがとうございました(>_<)

コードを提示して頂いたうえ、そのご説明まで丁寧にして
くださり、本当に感謝です(;_;)

実は配列がめっちゃ苦手で、変数も多くなるととたんに分からなくなるの
ですが、お二人の説明がとても分かりやすかったので、
読んでいて本当にためになり、
ワクワクして読み進めました!

とはいえ、まだまだ未熟なので、
100%の理解に達していないので、もう少し
じっくり読み進めたいと思いますが、
取り急ぎ、お礼を言わせてください☆彡

本当にありがとうございました!

(あいり) 2017/02/19(日) 22:43


コメント返信:

[ 一覧(最新更新順) ]


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