[[20210608213521]] 『RowSource 範囲指定の方法』(あみな) ページの最後に飛ぶ

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

 

『RowSource 範囲指定の方法』(あみな)

はじめまして、今年からVBAの勉強を始めた
あみなと申します。

難しい事ばかりなので、教えていただけたら嬉しいです。

/////////////////////////////////////////////////////////////////////////
目次
1. ComboBox へのコーディングはこれでいいのでしょうか?
2. ComboBox が複数の時はどうやって書けばいいのでしょうか?
3. RowSource って、そもそも必要なのでしょうか?
4. 可読性は大事ですが、10行も同じ事を書きたくない?
/////////////////////////////////////////////////////////////////////////

◆RowSource用の、サンプルテーブルです。

    |[A] |[B] |[C] |[D] 							
 [1]|No. |B1  |C1  |D1  							
 [2]|No.1|B001|C001|D001							
 [3]|No.2|B002|C002|D002							
 [4]|No.3|B003|C003|D003							
 [5]|No.4|B004|C004|D004							
 [6]|No.5|B005|C005|D005							
 [7]|No.6|B006|C006|    							
 [8]|No.7|B007|    |    							

1. ComboBox へのコーディングはこれでいいのでしょうか?
ユーザーフォームへ、ComboBoxの配置が3個程度なら可読性も
考慮すると、これでいいのでしょうか?

 Option Explicit							
 Private Sub UserForm_Initialize()							

    Me.StartUpPosition = 0							
    Me.Top = 280							
    Me.Left = 500							

    Dim lRow(1 To 3) As Long ' lRow : 行数カウント用の変数							
    Dim myData(1 To 3)							

    With Worksheets("Sheet2")							
        lRow(1) = .Range("B" & Rows.Count).End(xlUp).Row							
        lRow(2) = .Range("C" & Rows.Count).End(xlUp).Row							
        lRow(3) = .Range("D" & Rows.Count).End(xlUp).Row							
        myData(1) = .Range("B2:B" & lRow(1)).Value							
        myData(2) = .Range("C2:C" & lRow(2)).Value							
        myData(3) = .Range("D2:D" & lRow(3)).Value							
    End With							

    With ComboBox1							
        .Locked = False							
        .ColumnCount = 1							
        .ColumnWidths = "60"							
        .ListWidth = "63"							
        .List = myData(1)							
        '.RowSource = "Sheet2!B2:B" & lRow(1)							
        .SelectionMargin = 0							
        .ListIndex = 0							
    End With							

    With ComboBox2							
        .Locked = False							
        .ColumnCount = 1							
        .ColumnWidths = "60"							
        .ListWidth = "63"							
        .List = myData(2)							
        '.RowSource = "Sheet2!C2:C" & lRow(2)							
        .SelectionMargin = 0							
        .ListIndex = 0							
    End With							

    With ComboBox3							
        .Locked = False							
        .ColumnCount = 1							
        .ColumnWidths = "60"							
        .ListWidth = "63"							
        .List = myData(3)							
        '.RowSource = "Sheet2!D2:D" & lRow(3)							
        .SelectionMargin = 0							
        .ListIndex = 0							
    End With							

    'Debug.Print lRow(1): Debug.Print lRow(2): Debug.Print lRow(3)							

 End Sub							

2. ComboBox が複数の時はどうやって書けばいいのでしょうか?
複数の時とは、ComboBoxが5個以上になる時です。
勿論、ColumnWidthsや、ListIndex等は変更しない事とします。

補足ですが下記のコードでは、RowSourceは消してしまいました。
Microsoft.comにて、MACで rowsource がない場合にの記事を参考に書きました。
※URLが長いので検索するなら下記でお願いします。
mac2011userform,comboboxでrowsourceがない。

3. RowSource って、そもそも必要なのでしょうか?
消しても反映されるならこれでいいのでしょうか?

 Private Sub UserForm_Initialize()							

    Me.StartUpPosition = 0							
    Me.Top = 280							
    Me.Left = 500							

    Dim lRow(1 To 3) As Long							
    Dim myData(1 To 3)							

        With Worksheets("Sheet2")							
            lRow(1) = .Range("B" & Rows.Count).End(xlUp).Row							
            lRow(2) = .Range("C" & Rows.Count).End(xlUp).Row							
            lRow(3) = .Range("D" & Rows.Count).End(xlUp).Row							
            myData(1) = .Range("B2:B" & lRow(1)).Value							
            myData(2) = .Range("C2:C" & lRow(2)).Value							
            myData(3) = .Range("D2:D" & lRow(3)).Value							
        End With							

    Dim i As Integer							
    For i = 1 To 3							
        With UserForm1.Controls("ComboBox" & i)							
            .Locked = False							
            .ColumnCount = 1							
            .ColumnWidths = "60"							
            .ListWidth = "63"							
            .List = myData(i)							
            '.RowSource = myData(i)' ERROR							
            .SelectionMargin = 0							
            .ListIndex = 0							
        End With							
    Next i							
 End Sub							

4. 可読性は大事ですが、10行も同じ事を書きたくない?
仮に、ComboBoxが10個になった時は、下記の部分を簡略してコーディング
した方がいいのでしょうか? 変数だらけになりそうです。

    With Worksheets("Sheet2")							
        lRow(1) = .Range("B" & Rows.Count).End(xlUp).Row							
        lRow(2) = .Range("C" & Rows.Count).End(xlUp).Row							
        lRow(3) = .Range("D" & Rows.Count).End(xlUp).Row							
        myData(1) = .Range("B2:B" & lRow(1)).Value							
        myData(2) = .Range("C2:C" & lRow(2)).Value							
        myData(3) = .Range("D2:D" & lRow(3)).Value							
    End With							

難しいですね。挑戦してますが…失敗の連続です。
ご教授いただけたら、嬉しいです。

よろしくお願いします。

< 使用 Excel:unknown、使用 OS:unknown >


>RowSource って、そもそも必要なのでしょうか?

必要な人には必要かもしれないけど、
私は使った事があるような気もするけど、使った記憶がない程度。
ほぼ使わない。
(JPS) 2021/06/08(火) 22:44


 コーディングの良し悪しは私にはちょっと言えませんけど..

 >RowSource って、そもそも必要
 RowSource指定なら、途中でリストの並び順を変えたい時に参照元のSortで対応できる! という。(あんまり無い話ですが)
 リストの内容を書き換えたい場合にも参照元の内容を書き換えれば連動してくれるし!! (あ、それはListでも手間同じだった...)
 あ! ColumnHeads欲しい時とか。複数列のリストを表現したい時、たまーに欲しいです! (ComboBoxではあんまり無いか)
 んとね、1列目が文字列項目で2列目が桁区切り付き右揃え数値のリストとかを作りたい時、シート上の方が作り易い!!   ...とか

 ...いや、あの。 結構便利な場面もあるんですよ? (たまに...^^;)

 >10行も同じ事を書きたくない
 Forループで何とか出来る様ならそれで。って感じですかね。
 そもそもComboBoxの名前をループに対応できる名前にすれば、その部分だけは割と短く書けると思います。
 但し、そのせいで他の部分の可読性を損なう様なら、やめておくべきでしょうけどね。
 (何のComboBoxかを分かり易い名前にした方が、結果全体としては可読性が高かったりしますし)

(白茶) 2021/06/08(火) 23:07


>複数の時とは、ComboBoxが5個以上になる時です。
>勿論、ColumnWidthsや、ListIndex等は変更しない事とします。

プロパティウィンドウで設定したらどうですか。
設定した内容をコピーしていけば同じものができますよ。
その分コードは省けます。
但し RowSource は行が増えた時を見込んで範囲を多めにとっておいた方が良いです。

>RowSource って、そもそも必要なのでしょうか?

リストが変動するものはこれを使用し変動しないものは Add Item を使用しています。

これは私流のやり方です。
(れれ) 2021/06/08(火) 23:19


>可読性は大事ですが、10行も同じ事を書きたくない?

配列にぶち込んでやれば簡単では?
例えば、
cblt = array(1,2,3,4,5,6,7,8,9)
コンボボックス1.list = cblt

2列以上なら、2次元配列を使えばいいし。

RowSource は、増えた場合再設定してやればいいし。
1度クリアしなければダメだったら、
RowSource = vbnullstring
とかで消して再設定。
(JPS) 2021/06/08(火) 23:38


こんにちは…

皆さま、昨夜は遅い時間にご意見をいただきまして
ありがとうございました。

>RowSource 私は使った事があるような気もするけど、使った記憶がない程度。
ほぼ使わない。(JPS)さん

はい、臨機応変にだけど…必要を感じないご意見ありがとうございました。
私も、要らないのではないかと思っておりますが…勉強します。(あみな)

>RowSource...いや、あの。 結構便利な場面もあるんですよ? (たまに...^^;) (白茶)さん

RowSource の必要性がある場面もある...ご意見ありがとうございました。
もっと多くのパターンを勉強します。(あみな)

>プロパティウィンドウで設定したらどうですか…(れれ)さん

そうですよね。1回設定しちゃえば、そうそう変更しないですよね。
ColumnWidths等は、プロパティウィンドウで設定することにします。
と言うことで、下記の部分は出来るだけスッキリさせちゃいます。(あみな)

    Dim i As Integer							
    For i = 1 To 3							
        With UserForm1.Controls("ComboBox" & i)							
            .List = myData(i)							
            .ListIndex = 0							
        End With							
    Next i							

.RowSource = myData(i)
RowSource 上記の部分は書き方が解らないのでERRORが出ちゃうので取っ払います。
ListIndex は、折角Withで書いたので残しておきます。(∀`*ゞ)エヘヘ

>RowSource リストが変動するものはこれを使用し変動しないものは Add Item を使用しています。(れれ)さん

リストが変動するものですね…ウーンComboBox連動系の時なのかな?いや違うかな?
WorksheetFunction.VLookup のような時なのかな?… 勉強します。(あみな)

>可読性は大事ですが、10行も同じ事を書きたくない?
>Forループで何とか出来る様ならそれで。って感じですかね。(白茶)さん
>配列にぶち込んでやれば簡単では?(JPS)さん

はい、ガンバッてしてますが… 笑わないでください。
どっちも失敗してますww
↓こうしてみたり

 Private Sub UserForm_Initialize()							

    Me.StartUpPosition = 0							
    Me.Top = 280							
    Me.Left = 500							

    Dim lRow As Long							
    Dim myData(1 To 3)							
    Dim i As Integer: Dim j As Integer							

    For i = 1 To 3							
        For j = 2 To 4							
            With Worksheets("Sheet2")							
                lRow = .Range(Cells(2, j), Cells(Rows.Count).End(xlUp)).Row							
                myData(1) = .Range("B2:B" & lRow).Value							
                myData(2) = .Range("C2:C" & lRow).Value							
                myData(3) = .Range("D2:D" & lRow).Value							
            End With							
            With UserForm1.Controls("ComboBox" & i)							
                .List = myData(i)							
            End With							
        Next j							
    Next i							

 End Sub							

↓ちょっとハッキリわすれましたが…こうしてみたり

            For Each v In Array("B2:B" & lRow, "C2:C" & lRow, "D2:D" & lRow)							
            .RowSource = v							

無謀でしたね >< …勉強します。(あみな)

(あみな) 2021/06/09(水) 12:58


>For Each v In Array("B2:B" & lRow, "C2:C" & lRow, "D2:D" & lRow)

RowSource = "文字列"
が基本だからいけると思います。
んで、シートも指定。
(JPS) 2021/06/09(水) 13:41


(JPS)さん返信をありがとうございます。

この部分で
lRow = .Range(Cells(2, j), Cells(Rows.Count).End(xlUp)).Row

Range(Cell1, Cell2) Cell1とCell2は、

「セル範囲の左上隅と右下隅のセルを指定」
と考えてしたのですが...

 Debug.Print lRow をすると lRow = 1 あれれ?

↓確認するとやはり

 For Each v In Array("B2:B" & lRow, "C2:C" & lRow, "D2:D" & lRow)

 Debug.Print v 範囲が v = B2:B1 上に向かってしまいました?

|落|Å`*)・゚・。o○(落ちこみギミ・・)

現在のコードは下記になってます。

 Private Sub UserForm_Initialize()

    Me.StartUpPosition = 0
    Me.Top = 280
    Me.Left = 500

    Dim lRow As Long
    Dim myData As Variant
    Dim i As Integer: Dim j As Integer: Dim v As Variant

    For i = 1 To 3
        For j = 2 To 4
            With Worksheets("Sheet2")
                lRow = .Range(Cells(2, j), Cells(Rows.Count).End(xlUp)).Row
                Debug.Print lRow ' lRow = 1
                For Each v In Array("B2:B" & lRow, "C2:C" & lRow, "D2:D" & lRow)
                Debug.Print v ' v = B2:B1
                myData(i) = v.Value
                Next
            End With
            With UserForm1.Controls("ComboBox" & i)
                .List = myData(i)
                .ListIndex = 0
            End With
        Next j
    Next i
 End Sub

アドバイスをいただけませんでしょうか?
よろしくお願いします。
(あみな) 2021/06/09(水) 16:58


>Range(Cells(2, j), Cells(Rows.Count).End(xlUp)).Row

Cells(Rows.Count).End(xlUp)
どこの列を指定しているのか解らないし。
まずは、どんな結果が返ってくるのか部分的に試して理解してからコードに組み込む事をお勧めします。
(JPS) 2021/06/09(水) 17:12


(JPS)さん返信ありがとうございます。

ヒントをいただいてから、いっぺんにすると
どうせできないから途中まで...

範囲の参照を把握してから次を検討することにしました。

イミディエイトウィンドウに下記のコードを実行すると
2〜11,2〜9,2〜7の値が入るのでなんか良さそうな気がしてきました。

 Private Sub UserForm_Initialize()

    Me.StartUpPosition = 0
    Me.Top = 280
    Me.Left = 500

    Dim lRow(1 To 3) As Long
    Dim myData As Variant
    Dim i As Long: Dim j As Integer: Dim v As Variant: Dim x As Variant

    For j = 2 To 4
        For i = 2 To Cells(Rows.Count, j).End(xlUp).Row
            Debug.Print i
        Next i
    Next j

 End Sub

さて...ここからどうしよう。

閲覧いただいている方もお見えでしたら、方向性はこれで良いのか?
アドバイスをお願いします。
(あみな) 2021/06/09(水) 21:43


 >方向性はこれで良いのか? 

 ええと、最初はドベタコードが書ける事が前提です。
 で、ドベタコードを見てこれ繰り返せるんじゃないか?
 とかがきっかけになります。
 それから、同じ繰り返しをする規則性のあるパターンを探す事から始まります。
 パターンが見つかったら、それを当てはめる。
(JPS) 2021/06/09(水) 22:31

こんばんは、(JPS)さん返信をありがとうございます。

なるほど...ドベタコードって言うのですね。大事なんですね。

メモメモ… φ(・Å・´*)ヵキヵキ♪

ここから時間がかかるかも知れません。
出来るか解りませんが...頑張ります。
(あみな) 2021/06/09(水) 22:53


おはようございます。

ドベタコードから少し前進したような気がします。
...が、引き出しの狭い私ではここから先に進む気がしません。><

下記のコードを実行すると、Debug.Printには
ComboBox1〜3に表示したい情報が全部入ります。

B001〜B007
C001〜C006
D001〜D005

全部の情報をMyDataに格納したんだからそうでしょ!!
ってなりますが...

プロパティの配列のインデックスが無効です (エラー 381)
ですと言われても、何をどうしたら良いのか?解りません。

1列ずつ格納できないから最初のコードの下記の書き方に
なってしまいます。

 Dim lRow(1 To 3) As Long							
 Dim myData(1 To 3)

        With Worksheets("Sheet2")							
            lRow(1) = .Range("B" & Rows.Count).End(xlUp).Row							
            lRow(2) = .Range("C" & Rows.Count).End(xlUp).Row							
            lRow(3) = .Range("D" & Rows.Count).End(xlUp).Row							
            myData(1) = .Range("B2:B" & lRow(1)).Value							
            myData(2) = .Range("C2:C" & lRow(2)).Value							
            myData(3) = .Range("D2:D" & lRow(3)).Value							
        End With

ドラえもんのポケットような広い引き出しをお持ちの上級者の皆さま...
どうしたら良いでしょうか?アドバイスをお願いします。

現在のコード↓ここからArrayを使用するなんて無理ですよね?
現在のコードを掲示します。

 Private Sub UserForm_Initialize()

    Me.StartUpPosition = 0
    Me.Top = 280
    Me.Left = 500

    Dim myData
    Dim lRow As Long ' 最終行格納
    Dim MyCol As Integer   ' 列格納
    Dim i As Integer

    For MyCol = 2 To 4
        With Worksheets("Sheet2")
            For lRow = 2 To Cells(Rows.Count, MyCol).End(xlUp).Row
                myData = .Range(Cells(lRow, MyCol), Cells(lRow, MyCol)).Value
                Debug.Print myData
            Next lRow
        End With
    Next MyCol

    For i = 1 To 3
        With UserForm1.Controls("ComboBox" & i)
            .List = myData
            .ListIndex = 0
        End With
    Next i
 End Sub

よろしくお願いします。

(あみな) 2021/06/10(木) 09:20


 最後のコードだけ読んで「こんな感じなのかなぁ...」ってちょっと書いてみました。
 やろうとなさってる事からハズれてる様ならスルーして下さい。
 (途中あんまり読んでないもので... スミマセン^^;)

    Private Sub UserForm_Initialize()
        Dim myData
        Dim lRow As Long
        Dim MyCol As Long
        Dim i As Long

        Const START_ROW = 2& 'データは2行目からの意
        Const START_COL = 2& 'データは2列目からの意

        For i = 1 To 3
            MyCol = START_COL + i - 1
            With Worksheets("Sheet2")
                lRow = .Cells(.Rows.Count, MyCol).End(xlUp).Row
                If lRow >= START_ROW Then
                    myData = .Range(.Cells(START_ROW, MyCol), .Cells(lRow, MyCol)).Value
                    If Not IsArray(myData) Then myData = Array(myData) 'データ1件しか無かった時の対策
                    With UserForm1.Controls("ComboBox" & i)
                        .List = myData
                        .ListIndex = 0
                    End With
                End If
            End With
        Next i
    End Sub

(白茶) 2021/06/11(金) 00:18


こんにちは
(白茶)さんありがとうございます。

アドバイスをいただいた、(JPS)さん(れれ)さん
ありがとうございました。

(白茶)さんがコーディングを完成してくださいました。
目指したとおりのアプリケーションです。
ComboBoxは、利用頻度が高いので嬉しいです。

ComboBox が5個になっても10個になっても、1箇所変更するだけで済みます。
.+゚♪。これで楽チン(∀`人●)(★人´∀)ルンルン。♪゚+.

(白茶)さんへ…もしお時間あれば下記の解釈が間違っていたら教えてください。
よろしくお願いします。

▼定数宣言して… Const START_COL = 2&
▼代入するんですね。MyCol = START_COL + i - 1

▼なるほど…ここからFor ~ Next で回すんですね。
勉強になりました。
私が言うのも可笑しい話しですが、綺麗なコーディングだと思います。

▼そしてIF文で条件判定ですか…下のコード部分は解釈はこうですかね?
※もし…2行目以降が lRowによって選択されていたら?
myDataは、その範囲の Value ですよ?ちゃんと格納してね…

 If lRow >= START_ROW Then						
 myData = .Range(.Cells(START_ROW, MyCol), .Cells(lRow, MyCol)).Value						

▼配列か判定。データ1件しか無かった時の対策

 If Not IsArray(myData) Then myData = Array(myData)						

(myData)が配列で無ければ?…頭の中が…プチ「こんがらがる」です。
なるほどしか言葉が出てこない…笑

本当にありがとうございました。
ネットで結構探しても無かったんですよね。
うるうる...。°(´∩ω∩`)°。。. ( ´。•ω•。` )感動っ

また、解らないことが有れば質問をさせていただきます。
よろしくお願いします。

(あみな) 2021/06/11(金) 14:06


コメント返信:

[ 一覧(最新更新順) ]


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