[[20160919210449]] 『ユーザーフォームで検索』(ひなの) ページの最後に飛ぶ

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

 

『ユーザーフォームで検索』(ひなの)

お世話になっています。
[[20160701213502]] 『2-UserForm、ListBoxに指定の値の該当値を別のLis』

前回いろいろと教えていただいてありがとうございます。
あれから実用化したなかで、いくつか変更しないとちょっと大変な部分がでてきで、また質問に参りました。今回も教えていただけると嬉しいです。

 変更の部分は↓この部分です。

 Q2.ListBox1の値をクリック後ListBox2に売上の値を表示
  ・売上表示条件(同じ商品NO・同じ金額の場合=一行にする
          同じ商品NO・違う金額の場合=そのまま表示する)

  ↑これを↓

 Q.請求書B4のセルと商品A列に検索かけ
 客NOある時は該当する客NOの列をlistbox2 に表示に変更したいです。
 客NOない時は商品K列をlistbox2 に表示に変更したいです。

  '該当する客NOの列を検索
    With Sheets("商品")

          Ap = Application.Match(Worksheets("請求書")Range("B4").Value, Worksheets("商品").Range("A:A"), 0)
          'データ存在チェックない時のみ転記する

            '該当の列を ListBox2 に表示

            ' ListBox2 の表示内容はB列商品NO C列商品名 AP列空欄以外の値

              '空白以外のセル, 範囲はまだわからないので、省いてあります。
                ActiveSheet.AutoFilter Field:=Ap, Criteria1:="<>"

*前回の質問*************************************

 Q1.ユーザーフォームであいまい検索
  TextBox1に「ひ」と入力後、ListBox1に「ひ」が入っているすべてのの会社名を表示する
  ・検索値(英数大文字小文字、ひらがな、漢字、カタカナ)
 Q2.ListBox1の値をクリック後ListBox2に売上の値を表示
  ・売上表示条件(同じ商品NO・同じ金額の場合=一行にする
          同じ商品NO・違う金額の場合=そのまま表示する)
 Q3.ListBox1の値をクリック後ListBox3に顧客シート13列目の値を表示
 ▼フォーム 顧客
   CommandButton1 '入力 エクセルへ
   CommandButton2 ’終了
   TextBox1 'あいまい検索 ⇒ 顧客情報を引っ張ってくる
   ListBox2 ’購入履歴 ⇒ 売上から購入商品を引っ張ってくる
   ListBox3 ’注意 ⇒ 顧客から注意ランのデータを引っ張ってくる(データーは空欄のもある)
 ◆相談結果(ひなのメモ)		
Dim posCt1 As Range 
 Dim posList1 As Range
 Dim posCt2 As Range
 Dim posList2 As Range
 Dim posList4 As Range
 Const COLS売上 As Long = 11
 Const COLS顧客 As Long = 14
 Dim orgBack As Long
 Private Sub UserForm_Initialize()
    'リストボックス1
    With ListBox1
    'リストBOXの中の列数と↓ここの列数が異なると実行後エラーになる
        .ColumnCount = COLS顧客
        .ColumnWidths = "30;90;0;0;150;80;200;0;0;0;0;0;0;0"
        .BoundColumn = 5
        orgBack = .BackColor
    End With
    'リストボックス2
    With ListBox2
    '作業シートの列NOを数える、売上の列番号と異なる
        .ColumnCount = COLS売上
        .ColumnWidths = "0;0;0;0;0;0;50;150;0;50;30"
    End With
    With Sheets("作業")
        Set posCt1 = .Range("A1")                       'ListBox1用抽出条件領域
        Set posList1 = posCt1.Offset(, 2)               'ListBox1用リスト領域
        Set posCt2 = posList1.Offset(, COLS顧客 + 1)    'ListBox2用抽出条件領域
        Set posList2 = posCt2.Offset(, 2)               'ListBox2用リスト領域
    End With
    TextBox1_Change
 End Sub
 Private Sub TextBox1_Change()
    Dim r As Range
    Dim s1 As String
    Dim s2 As String
    With ListBox1
        .RowSource = ""
        .ColumnHeads = False
        .BackColor = orgBack
    End With
    ResetList
    With Sheets("顧客")    '範囲
        Set r = .Range("A1", .Range("A" & Rows.Count).End(xlUp)).Resize(, 14)
    End With
    s1 = StrConv(TextBox1.Value, vbUpperCase)    '文字列を大文字に変換
    s2 = StrConv(TextBox1.Value, vbLowerCase)    '文字列を小文字に変換
    'フィルターオプションの条件、縦に並べると OR 条件 ANDはできない
    With Sheets("作業")    'フィルター結果を作業シートにコピーする
        .UsedRange.ClearContents
        posCt1.Value = Sheets("顧客").Range("E1").Value    '条件タイトル
        '大文字小文字等で検索したい場合は設定
        posCt1.Cells(2).Value = "*" & StrConv(s1, vbWide) & "*"    '半角文字を全角文字に変換
        posCt1.Cells(3).Value = "*" & StrConv(s1, vbNarrow) & "*"    '全角文字を半角文字に変換
        posCt1.Cells(4).Value = "*" & StrConv(s2, vbWide) & "*"
        posCt1.Cells(5).Value = "*" & StrConv(s2, vbNarrow) & "*"
        r.AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=posCt1.CurrentRegion, CopyToRange:=posList1, Unique:=False
        If Not IsEmpty(posList1.Cells(2, 1)) Then
            With posList1.CurrentRegion
                ListBox1.RowSource = .Offset(1).Resize(.Rows.Count - 1).Address(External:=True)
                ListBox1.ColumnHeads = True
            End With
        Else
            ListBox1.BackColor = vbRed
        End If
    End With
 End Sub
 Private Sub ListBox1_Click()
    Dim r As Range
    ResetList
    With Sheets("売上")
        Set r = .Range("A1", .Range("A" & Rows.Count).End(xlUp)).Resize(, 11)
    End With
    posList2.CurrentRegion.ClearContents
    posCt2.Cells(1).Value = Sheets("売上").Range("D1").Value   '抽出タイトル
    posCt2.Cells(2).Value = ListBox1.Value                     '抽出条件(ListBox1で選ばれた1列目位の値)
    posCt2.Cells(1, 2).Value = Sheets("売上").Range("E1").Value  '抽出タイトル
    posCt2.Cells(2, 2).Value = "<>0*"                           '抽出条件 0 ではじまらないもの
    r.AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=posCt2.CurrentRegion, CopyToRange:=posList2, Unique:=False
    If Not IsEmpty(posList2.Cells(2, 1)) Then
        posList2.CurrentRegion.Sort Order1:=xlAscending, Key1:=posList2.Columns(5), Order2:=xlDescending, Key2:=posList2.Columns(2), Header:=xlYes
        posList2.CurrentRegion.RemoveDuplicates Columns:=Array(5, 8), Header:=xlYes
        With posList2.CurrentRegion
            ListBox2.RowSource = .Offset(1).Resize(.Rows.Count - 1).Address(External:=True)
            ListBox2.ColumnHeads = True
            ListBox3.List = Array(ListBox1.List(ListBox1.ListIndex, 12))
        End With
    Else
        ListBox2.BackColor = vbRed
        ListBox3.BackColor = vbRed
    End If
 End Sub
 Private Sub ResetList()
    With ListBox2
        .RowSource = ""
        .ColumnHeads = False
        .BackColor = orgBack
    End With
    With ListBox3
        .Clear
        .BackColor = orgBack
    End With
 End Sub

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


 すっかり忘却の彼方で、テストデータ等も、消してしまっていますので、キャッチアップに、少し時間がかかりそうです。
 今日は、終日、外出することもあって、ちょっと時間ください。

 その前に他の回答者さんから回答があればうれしいのですが。

(β) 2016/09/20(火) 06:32


ホントにすみません 。・゚・(pゝД;`q)・゚・

データーお渡しします。
声をかけてください

(ひなの) 2016/09/20(火) 11:56


慣れないスマホから質問を。
請求書シートや商品シートが登場しています。
これらの説明をお願いします。
レイアウトや用途など。

(β) 2016/09/20(火) 14:53


画面にもUPしますが、とりあえず渡しておきます。
DL後は削除下さいm(_ _;)m

(ひなの) 2016/09/20(火) 19:16


 ■請求書シート

 	[A]	[B]	[C]	[D]	[E]	[F]	[G]	[H]
 [12]	NO	品名	1cs数量	数量cs	数量pc	単価	金額	備考
 [13							0	
 [14]								
 :								
 [32]								

 ■商品シート

 	[B]	[C]	    [D]	[E]	[F]	[G]	[H]	[I]	    [J]	[K]	[L]	 [M]	[N]	…最終列
 [2]	NO	商品名前	容量	g	x	数	pc	数量	    重量	価格	001	020	035	
 [3]	A01	マンゴ酒	400 	g	×	30 	pc	400g×30pc	13 kg	\100 	90			
 [4]	A02	なし酒	    400 	g	×	30 	pc	400g×30pc	13 kg	\110 		80		
 [5]	A03	梅酒	    400 	g	×	30 	pc	400g×30pc	13 kg	\120 				
 [6]	A04	杏酒	    400 	g	×	30 	pc	400g×30pc	13 kg	\130 	120			
 [7]	A05	リンゴ酒	300 	g	×	20 	pc	300g×20pc	7 kg	\140 		100		
 [8]	A06	ぶどう酒	350 	g	×	20 	pc	350g×20pc	8 kg	\150 			130	
 :
 最終行

 ■フォーム名
  商品_顧客

 ■変更箇所

 現在の仕様 右側の顧客名をクリックすると 売上シート該当のデーターを表示する

 それを 右側の顧客名をクリックすると 商品シートの該当する列を表示するこ  とです。

 データーを比較するのは全部NOであればうれしいです
(ひなの) 2016/09/20(火) 19:31

 DLし、削除しておきました。
 じっくりと拝見し思い出してみます。

(β) 2016/09/20(火) 19:35


お手数をおかけしますがよろしくお願いします。

私もあきらめずに、修正のチャレンジしてます。

思い通りの結果得られないですが( ┰_┰)
(ひなの) 2016/09/20(火) 20:09


 少し時間が取れたので、以前のことを思い出しながら、DLしたブックのシートをチェックしました。
 以下質問です。

 1.TextBox1からListBox1への展開は従来通りですね。
 2.ListBox1 で選択された客先に対して、これと、請求書シートのB4を比較??
   B4 は請求書番号のようですが? 客先は B5 だと思いますが、とにかく、これを比較?
 3.で、同じものなら、【客NOある時は該当する客NOの列をlistbox2 に表示】
   この場合の該当する客NOの列って、どのシートのどの列ですか?
 4.同じではない場合は【客NOない時は商品K列をlistbox2 に表示】
   商品シートのK列という意味ですか? (ここは価格?)
 5.上記 3 または 4、ListBox2 には1列のみ表示ですか?(従来は複数列表示でしたけど)

(β) 2016/09/21(水) 21:41


1.はい従来通りです。

2.請求書の B4は顧客NO B5は会社名 になってます。

 現在は
 比較対象は 請求書 B5会社名 ⇒ 比較先は 売上シート D列名前 になっています。
 
 会社名で比較すると
 途中で社名変更があると、直すのがすごく大変でした。

 なので 今回は 顧客NOに変更できればと
 比較対象は 請求書 B4 顧客NO ⇒ 比較先は 顧客シートの A列 になります。 商品シートは 1 行目になります。

 請求書NO は G1 になります。

 請求書の A4 を NO ⇒ 顧客NO に変更ください。 紛らわしいので(ー_ー)

 3.4. Listbox2 の表示は 商品シートの内容↓こんな感じです。

 該当の 客NOがない場合(この表示はフィルタクリアにも使いたいです。)

 	[B]	[C]   	[I]	    [K]
 [2]	NO	商品名前	数量	    価格
 [3]	A01	マンゴ酒	400g×30pc	\100 
 [4]	A02	なし酒 	400g×30pc	\110 
 [5]	A03	梅酒	   400g×30pc	\120 
 [6]	A04	杏酒	   400g×30pc	\130 
 [7]	A05	リンゴ酒	300g×20pc	\140 
 [8]	A06	ぶどう酒	350g×20pc	\150 

 Listbox1 客NO 001 ?潟Aワビン クリック あるばあい(空欄は表示しない)

 	[B]	[C]   	[I]	    [L]
 [2]	NO	商品名前	数量	    001
 [3]	A01	マンゴ酒	400g×30pc	90
 [6]	A04	杏酒	    400g×30pc	120

 可能ならフィルタではなく、今後編集にわかるよう
 列とかわかるとすごくうれしいです ( ┰_┰) 
 こんなふうに。 .Range("A2").Value = ComboBox1.Value

 私でも直せるといいな〜(灬╹ω╹灬)┣¨キ┣¨キ

すみません。よろしくお願いします。
(ひなの) 2016/09/22(木) 23:52


 今回は、なかなか、ピピピっときません。
 何度も説明を読み、シートを見比べているのですが・・・・・

 >>1.はい従来通りです。 

 従来、TextBox1 に あいまい検索用文字列を入れ、これを元に 顧客シートから ListBox1 に 顧客名を表示 ですね。
 で、次には、この ListBox1 から 何か選び、選ばれた客先の売上データをListBox2 に表示。

 こうでしたよね?

 この選ばれたデータの顧客名ではなく、顧客NOで関連情報をマッチングしたいというのはわかったんですが
 わからないのは 選んだデータの顧客番号 と 請求書シートの B4 との関係です。もしListBox1から選んだ顧客の番号が 111 だったとします。
 で、請求書シートのB4 が 111 だったら、請求書シートの内容(商品の情報)を表示 ですかね?
 請求書シートの B4 が 111 じゃなかった場合は? どこのシートの何を表示するのですか? 商品シートにある情報すべてを表示?

(β) 2016/09/23(金) 19:34


順番に説明させていただきます m(_ _;)m

その前に先ず 商品シート の 値をないしてください。 その方がわかり易いと思います。

 	[L]	[M]	[N]
 [2]	001	003	004

(ひなの) 2016/09/23(金) 22:10


 1.エクセルシートの概要

 請求料シート へ入力 顧客情報は     ⇒ 顧客シートへ登録
            顧客NOと価格は ⇒ 商品シートの2列の最終列に登録
            売上の詳細は  ⇒ 売上シートに登録

 ▲という仕様になってます(未来の完成図です。)

 ◇顧客シートに顧客NO 有 で 商品シートも顧客NO 有 の場合。
  商品を一回でも購入する履歴ある時のみ

 ◇顧客シートに顧客NO 有 で 商品シートに 顧客NO 無 の場合。
  顧客情報のみ登録 購入履歴なし。

 ◇顧客シートに顧客NO 無 で 商品シートに 顧客NO 無 の場合。
   新規客(この場合はフォーム使わないので特に問題ありません。)
 
 2.フォームの使用

 フォーム名 「商品_顧客」オレンジ色です。(顧客のフォームと商品のフォームを合体させた感じです。)

 ■やりたいこと
 TextBox1  英数字大文字小文字 ひらがな カタカナ であいまい検索    
       値入力して、ENTER 押すと検索結果があるときListBox1に表示
       検索結果の値がないとき「赤」色にする
      
 ListBox1 表示データーの元は 顧客シートの値 
     
      ListBox1の顧客NOをクリックすると ListBox2 に該当する商品シートのデーターを表示

           IF ListBox1 0列目(エクセルシートの顧客NOは1列目) = 商品シート 該当する列の顧客NO Then
        
              ListBox2 に 商品シートの B列 c列 I列  該当の顧客列

      ないとき
             ListBox2 に 商品シートの B列 c列 I列  K列(価格)

 ListBox2 表示データーの元は 商品シートの値

ざっくりこんな説明ですが、伝わりますでしょうか (pゝД;`q)
いつも説明下手で申し訳ないです。
(ひなの) 2016/09/23(金) 23:12


 すっかり勘違いをしていたようです。

 まず、今まで作ってきたものの仕様を変更するんだと思っていましたが、そうではなく、全く新しいユーザーフォームをつくる。
 その際に、今までの仕掛けのなかの部品を利用する という感じなんですね。

 それと、なぜ 【請求書シート】のB4 とマッチングしなければいけないのか、それが、どうしてもわからなかったのですが
 (というか、操作として、あいまい検索したものから顧客を決定した後に、1枚しかない請求書シートの顧客番号と比較するという流れというか必要性が理解できなかった)
 実際には請求書シートとの比較は不要なんですね?
 でも、もし、顧客番号が同じなら、売上シートから該当顧客分を抽出しなくても、請求書シートに存在するので
 それを、そのまま表示すればいいと、そういうことでしたか?

 商品シートとのマッチングも、顧客番号と商品シートを、なぜ、どのように比較するんだろうと思っていましたが
 商品シートのL列から右に顧客の実績列があったんですね。
 で、この顧客列に値があるものを表示ということだったんでしょうか? 

 ところで商品シートの顧客列の数字は、売価ですか?

 追加で。

 >>該当の 客NOがない場合(この表示はフィルタクリアにも使いたいです。)

 フィルタクリアにも使いたい というところの意味が、まだ理解できていません。

 >>可能ならフィルタではなく、今後編集にわかるよう 列とかわかるとすごくうれしいです 

 この意味は、従来、フィルターオプションを使ったコードを提示してきましたが
 そうではない方法でコード記述したい(フィルターオプションは使いたくない)ということですか?
 もちろん、フィルター関連処理ではなく、Dictionaryなどを使ったメモリー内処理を書くことはできますが。
 (この場合、従来 ListBoxの先頭に表示していたタイトル行はなくなるかも。)

(β) 2016/09/24(土) 06:28


 >実際には請求書シートとの比較は不要なんですね?
  はい。

 >顧客番号が同じなら、売上シートから該当顧客分を抽出しなくても、請求書シートに存在するのでそのまま表示すればいいと、そういうことでしたか?
  請求料シート へ入力 顧客情報は     ⇒ 顧客シートへ登録
             顧客NOと価格は ⇒ 商品シートの2列の最終列に登録
             売上の詳細は  ⇒ 売上シートに登録

 ▲これは、あくまでエクセルのマクロの作動です「売上へ登録」のやつ
 (ホントはフォームにボタン設定して操作したかったですが、やり方わからなかったので、そのままにしました ( ┰_┰))

 3.請求料へ入力する流れ
 
 「商品_顧客」クリック 該当の顧客探す ⇒ 請求料へ転記
  ListBox1の該当顧客 クリック → ListBox2 購入履歴調べる ある場合 ⇒ 請求書 へ転記
                                ない場合 ⇒ 全商品のリストで該当商品クリック ⇒ 請求書 へ転記 

          

 >顧客番号が同じなら、売上シートから該当顧客分を抽出しなくても、請求書シートに存在するので それを、そのまま表示すればいいと、そういうことでしたか?
 ????何を表示るんでしょうか??

 > 商品シートのL列から右に顧客の実績列で、この顧客列に値があるものを表示ということだったんでしょうか? 
  はい、そうです。

 >ところで商品シートの顧客列の数字は、売価ですか?
  はい、そうです。

 > >>該当の 客NOがない場合(この表示はフィルタクリアにも使いたいです。)
 すみません。商品リスト全商品とK列の価格が見れるならOKです。フィルターは忘れてください。

 Private Sub ComboBox1_Change()。に入れようと思ってます。

 商品がA〜F,Z,Oの分類あるので、フォーム「商品」のように、分類別に見れるようにできればなと思ってます。

 >Dictionaryなどを使ったメモリー内処理を書くことはできますが。
  はい。よろしくお願いします。

 >(この場合、従来 ListBoxの先頭に表示していたタイトル行はなくなるかも。)
  はい、タイトルは問題ないです。あればいいな〜といった程度です。内容で大体わかります。

 すみません。こんな感じです。1っ箇所だけわからなかったですが、
 もう一度説明していただけると嬉しいです (灬╹ω╹灬)
 よろしくお願いします。

(ひなの) 2016/09/24(土) 09:07


 だいぶ、理解が進みました。でも、あらたに ?? となったところもあります。

 新たに ?? となったところ 3点。

 本トピは DL したブックの中の 商品_顧客 フォーム を完成させることだと、そう理解しました。
 (コメントしたように、それまでは、ずっと 従来の 顧客情報 フォームの手直しかと思っていました。)
 ですけど、『商品がA〜F,Z,Oの分類あるので、フォーム「商品」のように、分類別に見れるようにできればなと思ってます。』
 という説明がでてきて、フォーム『商品』って、いままで、対応してこなかったもので、中身がどんなものなのか
 わかっていないのですが、【分類別】というのが、どんな表示なのか、それが 新たに ??? となっています。

 次に、【Private Sub ComboBox1_Change()。に入れようと思ってます。】
 何をどこにいれるのか、理解できていませんが、それ以前に、ComboBox1 は 商品_顧客 フォームには存在しませんよね?
 TextBox1 は 顧客を絞り込むためのあいまい検索用文字列入力で、絞り込んだ結果をListBox1に表示。
 ListBox1 で選んだ顧客は、ListBox2 表示用のキーとして使いますよね。
 ComboBox1 とは ??

 最後に、【請求料へ入力する流れ】。別途登場する請求料シートというのも、どんなシートはわからないのですが
 今回対応する 顧客_商品 フォームのロジックで、この流れって、コード化必要ですか?
 それとも、単に 参考情報として説明していただいているということですか?

 で、そちらが、わからなかったという1か所。これも、私が誤解しているのかもしれないんですが。

 ListBox1 で選択した顧客の顧客番号で、何をどんな優先順位で検索して、何を ListBox2 に表示するのかという根本的なところですけど

 ・もし、この顧客NO が 請求書シートの B4 と同じであれば請求書シートに記載されている商品情報を表示
 ・そうでなかったら、商品シートの顧客列を検索し、あれば、その列に値のある行を表示
 ・いずれもなかったら・・・どうするかなぁ・・・?

 こんな理解なんです。間違っていますか?

(β) 2016/09/24(土) 09:46


 すみません。説明は細くも入っています。
 あと説明が下手ですみません。
 今回はフォームのみでお願いします。
 \(・_\)請求書のB4は (/_・)/コッチニオイトイテください。

 ◆やりたいことのまとめ

 TextBox1  英数字大文字小文字 ひらがな カタカナ であいまい検索    
        値入力して、ENTER 押すと検索結果があるときListBox1に表示
        検索結果の値がないとき「赤」色にする
      
 ListBox1 表示データーの元は 顧客シートの値 
     
       ListBox1の顧客NOをクリックすると ListBox2 に該当する商品シートのデーターを表示
            IF ListBox1 0列目(エクセルシートの顧客NOは1列目) = 商品シート 該当する列の顧客NO Then
        
               ListBox2 に 商品シートの B列 c列 I列  該当の顧客列
       ないとき
              ListBox2 に 商品シートの B列 c列 I列  K列(価格)
  ListBox2 表示データーの元は 商品シートの値

 ▼下記の各シートデーターと ListBox1とListBox2 と同じデーターと思ってください。説明がわかり易いかなと

 ■顧客シート = ListBox1

	[A]	[B]	[C]	[D]	[E]
 [1]	顧客NO	電話	携帯	FAX	社名
 [2]	001				(株)アワビン   ← ★クリックB
 [3]	002				アマエビン(株)   ← ★クリックA
 [4]	003				(株)イソガエン
 [5]	004				マグロン(株)  
 [6]	005				(株)カニン

 ■商品シート = ListBox2 L列 以降が各顧客の価格になります。

 	[B]	[C]	    [D]	[E]	[F]	[G]	[H]	[I]	    [J]	[K]	[L]	 [M]	[N]	…最終列
 [2]	NO	商品名前	容量	g	x	数	pc	数量	    重量	価格	001	003	004	
 [3]	A01	マンゴ酒	400 	g	×	30 	pc	400g×30pc	13 kg	\100 	90			
 [4]	A02	なし酒	    400 	g	×	30 	pc	400g×30pc	13 kg	\110 		80		
 [5]	A03	梅酒	    400 	g	×	30 	pc	400g×30pc	13 kg	\120 				
 [6]	A04	杏酒	    400 	g	×	30 	pc	400g×30pc	13 kg	\130 	120			
 [7]	A05	リンゴ酒	300 	g	×	20 	pc	300g×20pc	7 kg	\140 		100		
 [8]	A06	ぶどう酒	350 	g	×	20 	pc	350g×20pc	8 kg	\150 			130	
 :
 最終行

 ■フォーム
 【商品_顧客】 TextBox1 ListBox1 ListBox2

 **************************************************************************************************************

 >ListBox1 で選択した顧客の顧客番号で、何をどんな優先順位で検索して、何を ListBox2 に表示するのかという根本的なところですけど

 下記は例を使ってみました。

 TextBox1に (株)と入力すると
 上記の ■顧客シート = ListBox1 のデーターが ListBox1に表示される(多分)

  ▼ListBox1のとこの★マークをクリックすると
  ★クリックA の行をクリックする場合 顧客NO.002 → 商品シート = ListBox2 2行目 どこ見ても「002」なし  ⇒ ListBox2に表示A
  ★クリックB の行をクリックする場合 顧客NO.001 → 商品シート = ListBox2 2行目 の「L列」に同じ顧客NO有 ⇒ ListBox2に表示B 

 ■ListBox2 表示A (商品シートのデーター)

	[B]	[C]   	[I]	    [K]
 [2]	NO	商品名前	数量	    価格
 [3]	A01	マンゴ酒	400g×30pc	\100 
 [4]	A02	なし酒 	400g×30pc	\110 
 [5]	A03	梅酒	   400g×30pc	\120 
 [6]	A04	杏酒	   400g×30pc	\130 
 [7]	A05	リンゴ酒	300g×20pc	\140 
 [8]	A06	ぶどう酒	350g×20pc	\150

 ■ListBox2 表示B (商品シートのデーター)空欄以外
 	[B]	[C]   	[I]	    [L]
 [2]	NO	商品名前	数量	    001
 [3]	A01	マンゴ酒	400g×30pc	90
 [6]	A04	杏酒	    400g×30pc	120

長くなってすみません。こんな感じ大丈夫でしょうか?

(ひなの) 2016/09/25(日) 00:13


 なんとなくわかってきました。
 で、悩んでいても進まないので、とにかく 理解したベースで書いてみます。
 しばらく時間ください。

 で、1点質問をアップしておきます。コードを書き上げるのは、まだしばらく先ですが、それまでに返事いただければありがたいです。

 >>可能ならフィルタではなく、今後編集にわかるよう 列とかわかるとすごくうれしいです 

 この文の意図をもう一度確認。

 フィルタ機能を使いたくない? 作業シートを使いたくない? あるいは両方使いたくない?
 本件、メモリー内で抽出されたものを展開し、それを直接 ListBox2 の List に格納することで
 フィルターオプションなしで、かつ作業シートなしでコードを書くことはできます。
 できますが、現在、ListBox2 に表示している先頭のタイトル行、これが表示できなくなります。
 先頭のタイトル行は、シート上にタイトル行があるリストイメージをつくり、その領域を RowSourceで与えることで表示されます。

 今のところフィルターじゃない方式でメモリー内でリストを生成し、それをいったん 作業シートに転記して
 RowSourceとして指定することを考えています。

(β) 2016/09/25(日) 18:15


 ちょっと眠い状態で書きましたので、すっきりしない部分もありますがとりあえず。

 商品_顧客 フォームの

 ●Initialize 内の 'リストボックス2 の中の

    'リストボックス2
    With ListBox2
    '作業シートの列NOを数える、売上の列番号と異なる
        .ColumnCount = COLS売上
        .ColumnWidths = "0;0;0;0;0;0;50;200;0;35;35;35"
    End With

 これを

    'リストボックス2
    With ListBox2
        .ColumnCount = 4
        .ColumnWidths = "25;50;100;35"
    End With

 に変更。(列幅は、調整してください)

 ●ListBox1_Click を以下で置き換え

 Private Sub ListBox1_Click()
    Dim shC As Worksheet
    Dim r As Range
    Dim c As Range
    Dim w As Variant
    Dim x As Long
    Dim s As String

    ResetList

    Set shC = Sheets("商品")
    Set r = shC.Range("L2", shC.Range("K2").End(xlToRight)).Find(What:=ListBox1.List(ListBox1.ListIndex, 0), LookAt:=xlWhole)
    posList2.CurrentRegion.ClearContents

    With shC.Range("B2").CurrentRegion.EntireRow
        If r Is Nothing Then
            posList2.Resize(.Rows.Count).Value = .Columns("B").Value
            posList2.Offset(, 1).Resize(.Rows.Count).Value = .Columns("C").Value
            posList2.Offset(, 2).Resize(.Rows.Count).Value = .Columns("I").Value
            posList2.Offset(, 3).Resize(.Rows.Count).Value = .Columns("K").Value
        Else
            ReDim w(1 To .Rows.Count)
            For Each c In Intersect(.Cells, r.EntireColumn)
                If Not IsEmpty(c) Then
                    x = x + 1
                    s = IIf(x = 1, c.EntireRow.Columns("K").Value, c.Value)
                    w(x) = Array(c.EntireRow.Columns("B").Value, c.EntireRow.Columns("C").Value, c.EntireRow.Columns("I").Value, s)
                End If
            Next
            ReDim Preserve w(1 To x)
            posList2.Resize(UBound(w), 4).Value = WorksheetFunction.Transpose(WorksheetFunction.Transpose(w))
        End If
    End With

    If Not IsEmpty(posList2.Cells(2, 1)) Then
        With posList2.CurrentRegion
            ListBox2.RowSource = .Offset(1).Resize(.Rows.Count - 1).Address(External:=True)
            ListBox2.ColumnHeads = True
        End With
    Else
        ListBox2.BackColor = vbRed
    End If

 End Sub

(β) 2016/09/25(日) 22:17


 >フィルタ機能を使いたくない? 

 使いたくないのではなく、使い方がわからないので。
 セルとか列がわかると、ちょいと直しや。
 なんとなく、ここがこんな使い方か〜みたなのわかるんですが。

 フィルタはシステムで自動なので、分からなかったです ( ┰_┰)
 ちょっと、行をずらしたくてもできませんでした。。・゚・(pゝД;`q)・゚・
 すみません。理解度が低くて。

 そんならまだDictionaryのほうが 直せてたな〜と

理由は単純です。行や列がずれた場合。直し方がわからないから。。。。。。。。。

 >作業シートを使いたくない?

 特に問題ありません。
 今も使ってますので(〃⌒ー⌒〃)

 すみません。変なとこで悩ませてしまいました。

 頂いたコードを試してみますね少しお時間下さい。
(ひなの) 2016/09/26(月) 18:24

 Q2. マクロでは Call マクロ1 とか 違うところのマクロを呼び出すことができますが
    ユーザーフォームは Sub ListBox1_Click() Call Sub TextBox1_Change() とかコードを呼び出すことはできますか?
(ひなの) 2016/09/26(月) 18:27

 はい。呼び出せますよ。
 引数付のものは、ちゃんとした引数も指定して呼び出すことが必要ですが。
 Sub ListBox1_Click() やl Sub TextBox1_Change() は引数がないので、何も考えず、そのまま
 呼び出せますね。

 というか、現在のコードの Initialize プロシジャの最後、 End Sub の上を見てください。
 すでに、TextBox1_Change を呼び出していますよ。

(β) 2016/09/26(月) 18:42


 以下は、雑談です。時間があった時に眺めてください。

 >>セルとか列がわかると、ちょいと直しや。
 >>なんとなく、ここがこんな使い方か〜みたなのわかるんですが。
 >>フィルタはシステムで自動なので、分からなかったです ( ┰_┰)
 >>ちょっと、行をずらしたくてもできませんでした。。・゚・(pゝД;`q)・゚・

 フィルターオプションの名誉のために弁護(?)しておきます。

 フィルターオプションは、既存リストから必要な列を必要な条件を与えて、場合によっては、重複も排除して取り出すという処理(作業であれVBAであれ)をするにあたって
 「非常に効率がよく」、かつ、VBAとしても「非常にシンプルでわかりやすい1行コード」で実行可能です。

 わかりにくいとおっしゃるのは、フィルターオプションの部分ではなく、既存リストの領域特定の部分や、それに与える条件欄、抽出リストの作業シート上の位置の規定が
 βが提示したコードではわかりにくい、つまり、βのコードが悪いのであって、フィルターオプションのせいではありません。

 ちなみに、(β) 2016/09/25(日) 22:17 でアップしたコードの中の ListBox1_Click をフィルターオプション版にすると
 以下になります。

 Private Sub ListBox1_Click()
    Dim shC As Worksheet
    Dim r As Range
    Dim c As Range
    Dim w As Variant
    Dim x As Long
    Dim s As String
    Dim t As String

    ResetList

    Set shC = Sheets("商品")
    Set r = shC.Range("L2", shC.Range("K2").End(xlToRight)).Find(What:=ListBox1.List(ListBox1.ListIndex, 0), LookAt:=xlWhole)
    posList2.CurrentRegion.ClearContents
    posCt2.ClearContents

    If r Is Nothing Then
        t = shC.Range("K2").Value
        posCt2.Cells(2).ClearContents
    Else
        t = r.Value
        posCt2.Cells(2) = "=" & r.EntireColumn.Cells(3).Address(False, False) & "<>"""""
    End If

    posList2.Resize(, 4).Value = Array(shC.Range("B2").Value, shC.Range("C2").Value, shC.Range("I2").Value, t)
    shC.Range("B2").CurrentRegion.AdvancedFilter xlFilterCopy, posCt2.Resize(2), posList2.CurrentRegion.Rows(1)
    If Not r Is Nothing Then posList2.Cells(1, 4).Value = shC.Range("K2").Value
    If Not IsEmpty(posList2.Cells(2, 1)) Then
        With posList2.CurrentRegion
            ListBox2.RowSource = .Offset(1).Resize(.Rows.Count - 1).Address(External:=True)
            ListBox2.ColumnHeads = True
        End With
    Else
        ListBox2.BackColor = vbRed
    End If

 End Sub

(β) 2016/09/27(火) 10:30


(β)様

ありがとうございます。

今ばたばたして、なかなか見る時間作れず
返信できなくてすみません。

金曜に時間できるので、ゆっくり見ますね。

ちなみ、だれも悪くないですよ(*˘︶˘*)
件かは得ていますから、どのコードの〜♪
(ひなの) 2016/09/27(火) 17:12


 (β)様

 ありがとうございます。いつもながら完璧です ( ✧Д✧)
 しかも、私のわがままは反映され。セルとかがいっぱいあります。
 すごくうれしいです。

 コードでいくつか質問させてください。
 お時間あるときで構いませんので教えていただけると嬉しいです。
 よろしくお願いしします。

 Q1. Set r = shC.Range("L2", shC.Range("K2").End(xlToRight)).Find(What:=ListBox1.List(ListBox1.ListIndex, 0), LookAt:=xlWhole)

   Set r = shC.Range(★?, K2から最終列).Find(と同じインデクスの名前が見つかったかどうかを判定する) 

   Application関数のような役割であってますか?
   意味は

 商品シートK2〜最終列とListBox1が同じIndexを探す 

 であってますか? 

 ただ、その前のL2は何の意味でしょうか?調べてもわからなかったです ( ?_?)    
(ひなの ) 2016/09/30(金) 19:54

 >>Application関数のような役割であってますか? 

 そうですね。Application.Match と同じようなことを Findメソッドでやっています。

 検索領域は L2 から 2行目のデータ最終列までということにしています。
 最初の "L2" は セルの L2 のことで、Range(開始セル,終了セル) という領域規定の 開始セルが "L2" ということです。

(β) 2016/09/30(金) 20:22


 ありがとうございます。

 なるほどそういうやり方もあるんですね。

  List1の値が 商品シート L2 から 2行目のデータ最終列 にあるかを探すと。

Q2.ザックリですが意味あってますか?

 '商品シートB2列からデータの入力されているセル領域の終端セルを参照
    With shC.Range("B2").CurrentRegion.EntireRow
        '顧客がない場合
        If r Is Nothing Then
            'List2の最終行に  = 商品シート 商品NO を格納
            posList2.Resize(.Rows.Count).Value = .Columns("B").Value
            'List2(左から1列飛ばして) 1列目 に = 商品シート 商品名 を格納
            posList2.Offset(, 1).Resize(.Rows.Count).Value = .Columns("C").Value
            'List2(左から2列飛ばして) 2列目 に = 商品シート 数量  を格納
            posList2.Offset(, 2).Resize(.Rows.Count).Value = .Columns("I").Value
            'List2(左から3列飛ばして) 3列目 に = 商品シート 価格  を格納
            posList2.Offset(, 3).Resize(.Rows.Count).Value = .Columns("K").Value
(ひなの ) 2016/09/30(金) 20:53

 まず、今まで特に確認はしていませんでしたが、商品シートの1行目とA列は空白であるという前提です。
 (DLしたシートがそうなっていましたので)

 なので、Range("B2").CurrentRegion で、B2から始まる表の領域を取得できています。
 もし、1行目やA列に何か値があるセルが存在すれば、1行目やA列も表の一部だとみなされます。

 CurrentRegion の定義はおわかりですよね。(必要なら補足説明します)

 '商品シートB2列からデータの入力されているセル領域の終端セルを参照
    With shC.Range("B2").CurrentRegion.EntireRow

 ●shC.Range("B2").CurrentRegion が表全体の領域です。Range("B2:N8") といった感じですね。
  で、その.Entirerow ですから、2行目から8行目までの行全体、つまり、$2:$8 という領域です。
  B列から始まる領域のままだと、実際のB列を B という表現で指定できず、たとえば .Columns(1) あるいは .Columns("A") などという ?? といった表現になり
  わかりにくくなるので、あえて領域を A列から始まるものにしています。それによって、.Columns("B") と記述すると本当の B列を参照できます。

 ●ということで、顧客がない場合に 

            'List2の最終行に  = 商品シート 商品NO を格納
            posList2.Resize(.Rows.Count).Value = .Columns("B").Value

  これは posList2(単一セルです)の .Rows.Count行、つまり With でくくった $2:$8 の行数である 7行の領域に .Columns("B") これは 商品シートの B2:B8 ですけど、
  この内容を書きこんでいます。

  同様に、たとえば

            'List2(左から3列飛ばして) 3列目 に = 商品シート 価格  を格納
            posList2.Offset(, 3).Resize(.Rows.Count).Value = .Columns("K").Value

  これは、posList2という単独セルの3列右(posList2も含めると4列目)に 商品シートの K2:K8 を書きこんでいます。

 う〜ん・・・・ちょっと 難しいですかね?

(β) 2016/09/30(金) 21:26


 時間があるときに以下のコードを実行してみてください。

 最初のコードでは C列、あとの3つのコードでは B列になっています。
 結果をみて、コードをじぃぃっと見つめなおすと、前のレスで述べたことがわかってもらえるかも。

 Sub Test()
    Dim r As Range

    Set r = Range("B2:N8")

    MsgBox r.Columns("B").Address

    MsgBox r.Columns(1).Address
    MsgBox r.Columns("A").Address
    MsgBox r.EntireRow.Columns("B").Address

 End Sub

(β) 2016/09/30(金) 21:32


 (β)様 ありがとうございます。

 すみません。 勘違いました。

 ListBox の始まりは 0列 1列 2列 なので、

 posList2 単独なので、 エクセルと同じ数え方になるんですね

 posList2 商品シートの K2:K8 を書きこんでるだけで
 Listbox2 に K2:K8 を書きこんでるわけではないですもんね。

 結構勘違いしてました( ┰_┰)

 posList2 は 値を一時的に保管する倉庫みたいなもんですね

 >CurrentRegion の定義はおわかりですよね。
  はデーターのある前範囲のセルの値を取得する。途中に空欄があるとそこで止まる。と書いていります。
   http://qiita.com/furico/items/e2155fdd8810dd79795a

 >時間があるときに以下のコードを実行してみてください。
 あれ〜 MsgBox r.Columns("B").Address 予想外の結果です。
 (;¬д¬)ジー―――と見てみます
(ひなの ) 2016/09/30(金) 21:59

 ジーッとみるときの参考として。

 たとえば Columns("B") とか Range("B5") というコードを見ると、我々は、とっさに
 あぁ、あの、エクセルシートの左のほうの B 列のことだとか、左上のほうにある、あの B列の5行目のセルだと
 そう思いますね。間違ってはいません。Columns("B") とか Range("B5") だけなら、その通りですから。

 でも、実は Columns("B") とか Range("B5") は、ある領域の.Columns("B") とか ある領域の.Range("B5") であり
 そこが省略されていると、シートのセル全体の領域の.Columns("B") あるいは シートのセル全体の領域の.Range("B5") になります。

 で、この "B" は、とっさにイメージする【あのB列】ではなく、ある領域の中の 「2番目の列」という意味の B なんです。
 5 も、シートの上から数えて5行目ではなく、ある領域の 5行目 という意味です。

 で、シートのセル全体の領域の ということなので B も 5 も 「たまたま、我々が、とっさにイメージするものと」同じになるということです。

 一方、Range("B2:N8").Columns("B") は B2:N8 という領域の 2列目の領域、つまり C2:C8 になりますし、Range("B2:N8").Range("B5") は
 B2:N8 という領域の 2列目の5行目 となって、C6 になります。

 なんで、こんな紛らわしい記述方法があるんだ! と思われるかもしれませんが、これはこれで、便利な利用方法もあります。
 でも、通常は、わかりづらくなりますよね。

 なので、B2:N8 の中の特定の列を取り出したいのですが、われわれがイメージする列記号で指定できるように

 Range(B2:N8").EntireRow これは エクセルシートの 2行目から8行目の領域ですので Range(B2:N8").EntireRow.Columns("B") と記述すると
 エクセルシートの2行目から8行目の2番目の列、つまり B2:B8 を参照できると、まぁ、そんなところですね。

(β) 2016/10/01(土) 09:01


 もう、おなか一杯だと思いますけど、1つだけ。

 私のコードでは With shC.Range("B2").CurrentRegion とくくって、この領域を参照する記述で書き始めましたので
 アップしたような領域表現にしましたが、領域の指定は、とにかく、いろんな方法で記述できます。
 バリエーションがありすぎて、かえって困る? というぐらい、様々な方法があります。

 たとえば 行変数 = shC.Range("B2").CurrentRegion.Rows.Count と記述して領域の行数を取得しておいて

 shC.Range("B2").ReSize(行変数)  これでも、CurrentRegion が B2:N8 なら B2:B8 を参照できます。
 このほうが、ひなのさんにとって わかりやすかったかもしれませんね。
(β) 2016/10/01(土) 09:17

 (β)様

 ありがとうございます (;¬д¬)ジー――――――――――――――と見つめて
 説明文と照らし合わせたところようやくわかりました。

 これで何とかやってみます。
 またわからないことありましたら、懲りずに教えていただけましたらうれしいです。
 ホントにありがとうございました。
(ひなの ) 2016/10/02(日) 22:10

コメント返信:

[ 一覧(最新更新順) ]


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