『ユーザーフォームのテキストボックスにオートフィルターを掛けた際のデーター修正について』(まき) エクセル:2003、OS:XP いつも色々本webを参考にさせて頂いております。 さて、現在ユーザーフォームのテキストボックスにオートフィルターを掛けた他の bookのシートを読み込んでいます。(下表は例です。ユーザーフォームには、Row表 示は有りません。) Row A B C D E F 1 開始  完了    品名   型番   user   area  8 2008/09/10 2009/01/30 car jzx100  sato tokyo 10 2008/11/20 2008/12/31 car jzx90   tanaka yokohama  13 2008/12/01 2008/12/31 car w203   sasaki saitama 15 2008/10/01 2008/11/05 car rx-7   saito chiba 16 2008/10/20 2008/12/05 car w211   itou tokyo 27 2008/12/20 2009/03/20 car w212   kimura tochigi 38 2008/10/15 2009/02/20 car w204   hara tokyo この中から1点だけ修正したい場合は、他のユーザーフォームに引き渡しております。 修正後、元の読み込み先シートのデーターも修正を行いたいと考えております。しかし、 修正を掛けるとRowアドレスの違う所が修正されてしまいます。 ブレークポイントを入れてListIndexを読んだ所、Row・8のデーターがListIndex・1と帰 って来てしまいます。 現状のListIndexの取得は次の通りです。(一部割愛) Dim g0 As Long: Dim g1 As Long With UserForm2 g0 = ListBox1.ListIndex 'このg0が1となってしまう。 本来は(例題時には)8となれば正しく修正出来るのだと思うのですが、どの様にすれば 本来のRowデーターを取得出来るのでしょうか?ちなみに、オートフィルターを掛けなけ れば、正しくシートも修正する事が出来ます。 以上よろしくお願い致します。 ---- With UserForm2 Msgbox .ListBox1.Parent.Name Msgbox ListBox1.Parent.Name End With   それぞれどのようにメッセージ表示されるか、確認してください。 ピリオド一つですが、この違いが理解されていないのでは、と推測します。 (みやほりん)(-_∂)b ---- みやほりん 様 おはようございます、まきです。 ご指摘頂きました内容を記述した所、次の通りでした。 Msgbox .ListBox1.Parent.Name → コンパイルエラーメソッドまたはデータメンバがみつかりません。 となり「.ListBox1」部が青になっていました。 上記部をコメント行として Msgbox ListBox1.Parent.Name → メッセージboxで予約確認(フォーム名)が出て来ました。 みやほりん様が言われる通り、ピリオドの違いが全然分かりません。(偉そうに言えないのですが。。。) 以上よろしくお願い致します。 ---- >ピリオドの違いが全然分かりません。 すでに現在お使いのコードが(大袈裟な言い方ですが)「オーバーテクノロジー」の 状態ですね。 「コンパイルエラーメソッドまたはデータメンバがみつかりません。」 は、UserForm2.ListBox1というオブジェクトがないからです。   > With UserForm2 > g0 = ListBox1.ListIndex 'このg0が1となってしまう。   相談文章とサンプルをよく読んでみて、これの原因は大体わかりました。 ListBox1で選択しているのがListBox1の2行目であるなら、g0=1 は不自然ではありません。 SheetのRowとListBox1.ListIndexは連動していません。ListBox1.ListIndexはあくまで ListBox1の中でのアイテム番号であり、しかも、0から始まります。 Sheetの一行目はColumnHeadsに指定してあるようですから、ColumnHeadsの行がListIndex=0です。   だから、書き戻すときにListBox1.ListIndexをSheetの行番号に単純に当てはめることが 出来ません。ということは、 「書き戻そうとしているデータがもともとSheetのどの行だったのか」ということを 何らかの方法で確定する仕組みが必要です。 私なら、もともとのデータに一意なIDを付すか、ListBox1のアイテムとして、行番号も 加えるでしょう。 「他は編集しても、この列のデータだけは絶対編集せず、かつ、重複しない、行を 特定できるデータ」があると、変更するときにはそれを目印にできますから、 そのようなデータを付け加えるのがコーディングとしては簡単になるでしょう。   (みやほりん)(-_∂)b ---- みやほりん様、まきです。 ご指摘有り難うございました。ListIndexのHELPを読んでいて、 g0 = ListBox1.ListIndex 'このg0が1となってしまう。 g0が1となってしまう事は分かりました。 本ご指摘を頂く前にデバッグしており、確認の為次の様なメッセージboxを立ち上げオートフィルター後 のシートのrowデーターを表示する様に致しました。(追記部のみ明記) Private Sub UserForm_Initialize() Dim FilterRow As Range Set Sh1 = Workbooks("レンタル予約.xls").Worksheets("全体予約") For Each FilterRow In _ Sh1.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible) If FilterRow.Row <> 1 Then MsgBox FilterRow.Row End If Next FilterRow すると、オートフィルターが効いた状態で本来のシートのrowアドレスを表示しました。以上の事から ListIndexへのデーターの引き渡しが上手に出来ていないんだろうと予測しました。ご参考までに現行の VBAを明記させて頂きます。 Private Sub UserForm_Initialize() Dim rng_myRange As Range Dim lng_RowCnt As Long, i As Long Dim C As Range Dim Sh1 As Worksheet Dim FilterRow As Range Set Sh1 = Workbooks("レンタル予約.xls").Worksheets("全体予約") With Sh1 Set rng_myRange = Range(.Range("D1"), .Range("D65536").End(xlUp)).SpecialCells(xlCellTypeVisible) End With 予約確認.ListBox1.ColumnCount = 4 予約確認.ListBox1.ColumnHeads = True lng_RowCnt = rng_myRange.Count ReDim MyArray(1 To lng_RowCnt, 1 To 4) For Each C In rng_myRange i = i + 1 MyArray(i, 1) = C.Offset(, 0).Value MyArray(i, 2) = C.Offset(, 1).Value MyArray(i, 3) = C.Offset(, 2).Value MyArray(i, 4) = C.Offset(, 3).Value Next C 予約確認.ListBox1.List = MyArray Set Sh1 = Nothing Set rng_myRange = Nothing End Sub 上記の記述でシートのrowアドレスを引き渡せればいいのですが。オートフィルターを掛けなければ、同 ListBoxで修正しても指定行が直るんですが。。。 みやほりん様が言われる通り、シートのrowアドレスを追加して見直しも平行して進めて見ます。 以上よろしくお願い致します。 ---- > With Sh1 > Set rng_myRange = Range(.Range("D1"),.Range("D65536").End(xlUp)).SpecialCells(xlCellTypeVisible) ↑              ??? With を使うのをやめた方がいいのかもしれない。 > End With BJ ---- >ListIndexへのデーターの引き渡しが上手に出来ていないんだろう   シートのオートフィルターの状態がListBoxに反映されているわけではないのです。 ListBoxに転記された時点で、元のデータが何行目にあったのかは、ListBoxには 「あっしにゃ関りのないことでござんす」になります。   現在のListBoxのListの作成の仕方では「元のデータが何行目だったか」は 単純に示すものがありません。   1行1行に変更の許可されない「一意(ユニーク)」データがあれば、 それをキーとして行を特定する。(検索のメソッドなどで)   そういう一意のデータがない場合は一意なIDなり、行番号をListBoxの Listに含めるようにする。   たとえば、次のようなコードでListBoxの隠しデータとして、「元のデータの行位置」 を与えることが出来るんじゃないでしょうか。   Private Sub UserForm_Initialize() Dim rng_myRange As Range Dim lng_RowCnt As Long, i As Long Dim C As Range Dim Sh1 As Worksheet Dim FilterRow As Range Set Sh1 = Workbooks("レンタル予約.xls").Worksheets("全体予約") With Sh1 Set rng_myRange = Range(.Range("D1"), .Range("D65536").End(xlUp)).SpecialCells(xlCellTypeVisible) End With 予約確認.ListBox1.ColumnCount = 4 予約確認.ListBox1.ColumnHeads = True lng_RowCnt = rng_myRange.Count ReDim MyArray(1 To lng_RowCnt, 1 To 5) :Rem 配列スペースを追加 For Each C In rng_myRange i = i + 1 MyArray(i, 1) = C.Offset(, 0).Value MyArray(i, 2) = C.Offset(, 1).Value MyArray(i, 3) = C.Offset(, 2).Value MyArray(i, 4) = C.Offset(, 3).Value MyArray(i, 5) = C.Row :Rem 元データの行位置をListBoxに追加 Next C 予約確認.ListBox1.List = MyArray Set Sh1 = Nothing Set rng_myRange = Nothing End Sub   で、ListBoxに埋め込んだ行位置を取り出すのは例えば、次のように。 g0 = Me.ListBox1.List(Me.ListBox1.ListIndex, 4)                 (みやほりん)(-_∂)b ---- BJ様、みやほりん様、こんばんはまきです。 BJ様からご指摘頂いた通り、withを除き2行追加しました Workbooks("レンタル予約.xls").Activate'追加 Worksheets("全体予約").Slect'追加 Set rng_myRange = Range(.Range("D1"), .Range("D65536").End(xlUp)).SpecialCells(xlCellTypeVisible) すると Set rng_myRange = Range(.Range("D1"), .Range("D65536").End(xlUp)).SpecialCells ~~~~~~ ここでコンパイルエラーとなりました。 みやほりん様から教えて頂きました通り明記した所、 g0 = ListBox1.ListIndex(Me.ListBox1.ListIndex, 4) で型が一致しませんとエラーになりました。そこで、 予約確認.ListBox1.ColumnCount = 4 → 5 を変えてみましたが、上記と同じ場所でエラーになりました。 現在行番号をシートに記入して、同番号をユーザーフォームに上げる様変更しております。 MyArray(i, 5) = C.Offset(, 4).Value '行番号を追加 .t_no.Value = ListBox1.List(g0, 4) 以上よろしくお願い致します。 ---- >みやほりん様から教えて頂きました通り明記した所、   比べてください。 g0 = Me.ListBox1.List(Me.ListBox1.ListIndex, 4)  g0 = ListBox1.ListIndex(Me.ListBox1.ListIndex, 4)   >型が一致しませんとエラーになりました。そこで、 > 予約確認.ListBox1.ColumnCount = 4 → 5 >を変えてみましたが、上記と同じ場所でエラーになりました。   ヘルプには以下のように書かれています。 「ListBoxコントロールまたはComboBoxコントロールに表示する列の数を設定します。」                         ^^^^^^^^^^^^^^^^ 表示される列数を設定するものなので、リストアイテムの列数を増やすものではありません。   Withの使い方や、「.」がどういうことなのかは、次の例(Excel2000Helpより)が 分りやすいでしょう。   /////////////////////////////////////////////////////////////////////////////// With MyObject .Height = 100 ' MyObject.Height = 100 と同じです。 .Caption = "Hello World" ' MyObject.Caption = "Hello World" と同じです。 With .Font .Color = Red ' MyObject.Font.Color = Red と同じです。 .Bold = True ' MyObject.Font.Bold = True と同じです。 End With End With ///////////////////////////////////////////////////////////////////////////////   Withステートメントを使わないと、次のような書き方になります。 MyObject.Height = 100 MyObject.Caption = "Hello World" MyObject.Font.Color = Red MyObject.Font.Bold = True   さて、それから、 With Sh1 Set rng_myRange = Range(.Range("D1"), .Range("D65536").End(xlUp)).SpecialCells(xlCellTypeVisible) End With   これは、次のように書くのが正解でしょう。 With Sh1 Set rng_myRange = .Range(.Range("D1"), .Range("D65536").End(xlUp)).SpecialCells(xlCellTypeVisible) End With   正解ではないのに動くのは、たまたまSh1がアクティブだからではないでしょうか。 (みやほりん)(-_∂)b ---- Withステートメントについて が話題になっているので・・・。 http://www.vbalab.net/vbaqa/c-board.cgi?cmd=one;no=45368;id=excel 以前、こんな投稿をしたことがありました。 記述が簡便になるだけではないことも理解してみてください。 ichinose ---- みやほりん様、ichinose様、おはようございます。 昨日は本業(営業職)で1日外出しておりましたので、何も出来ませんでした。今日は電話も無いので 朝から試してみました。 g0 = Me.ListBox1.List(Me.ListBox1.ListIndex, 4) に直した所、この行のエラーは無くなりました。しかし、この予約確認フォームで選択した1件の物件 を、UserForm2に引き渡す次の行のルーチンで”「実行時エラー'381' Listプロパティの値を取得できません。” と出て来ました。デバッグモードでg0の値を見た所、シートの行番号が正しく表示されております。 エラーが出ている行のg0は本来のシートの行番号です。 そこで、g0を修正時のデーターとする様にして、他は従来のまま使用する様に致しました。 将来誰か私と同じ様な人が本LOGを見て参考になる様に、修正したVBAを表記致します。 ちなみに、 Private Sub UserForm_Initialize()はみやほりん様から指導頂いた通りです。 Private Sub 変更_Click() Dim g0 As Long: Dim g1 As Long Dim sht As Worksheet Dim 開始日 As Date: Dim 完了日 As Date '変更前予約日のセット Dim 開始日af As Date: Dim 完了日af As Date '変更後予約日のセット Dim 装置 As String: Dim 号機 As String '変数を宣言。 Dim FilterRow As Range 装置 = TextBox1 号機 = TextBox2 Set sht = Workbooks("レンタル予約.xls").Worksheets("全体予約") '何も無い時の為の判定を追加 If ListBox1.ListIndex > -1 Then 'テキストボックスで選択された行の本当のシートの行番号の取得 g0 = Me.ListBox1.List(Me.ListBox1.ListIndex, 4) '予約確認フォームの選択した1件の物件を、UserForm2に引き渡す With UserForm2 g1 = ListBox1.ListIndex .t_yoyaku.Value = Format(ListBox1.List(g1, 0), "yy-m-d") 開始日 = ListBox1.List(g1, 0) .t_kanryo.Value = Format(ListBox1.List(g1, 1), "yy-m-d") 完了日 = ListBox1.List(g1, 1) .t_user.Value = ListBox1.List(g1, 2) .t_genba.Value = ListBox1.List(g1, 3) .Show If .update Then '内容変更時 開始日af = CDate(.t_yoyaku.Value) 完了日af = CDate(.t_kanryo.Value) If 完了日af > 開始日af Then If MsgBox("指定されたユーザーの予約変更致します!", 4, "レンタル管理") = vbYes Then sht.Cells(g0, 4).Value = CDate(.t_yoyaku.Value) sht.Cells(g0, 5).Value = CDate(.t_kanryo.Value) sht.Cells(g0, 6).Value = .t_user.Value sht.Cells(g0, 7).Value = .t_genba.Value Call set_listbox -----以下省略−−−−−−−− *最後の行の"Call set_listbox"が効かなくなってしまいました。多分g1でUserForm2に上げて、修正がg0で行っているから?? 今まで色んな過去ログを見ていると、Withステートメントが使用されておりますが、正直何なのか全然 分かっておりませんでした。以前に2003のVBA HELPでWithと入れても何も出てこなかったので、まあい いかと思っておりました。みやほりん様、ichinose様の回答で少し分かった様な気がします。有り難う ございました。 話は変わりますが、予約確認フォームのテキストボックスにヘッダーが表示されません。 枠は出てくるのですが、表題が枠に入りません。また、表題はrowの1に有るのですが? Private Sub UserForm_Initialize() Dim rng_myRange As Range Dim lng_RowCnt As Long, i As Long Dim C As Range Dim Sh1 As Worksheet Dim FilterRow As Range Set Sh1 = Workbooks("レンタル予約.xls").Worksheets("全体予約") With Sh1 Set rng_myRange = Range(.Range("D1"), .Range("D65536").End(xlUp)).SpecialCells(xlCellTypeVisible) End With 予約確認.ListBox1.ColumnCount = 4 予約確認.ListBox1.ColumnHeads = True'※この表記で良いと思うのですが? lng_RowCnt = rng_myRange.Count ReDim MyArray(1 To lng_RowCnt, 1 To 5) :Rem 配列スペースを追加 For Each C In rng_myRange i = i + 1 MyArray(i, 1) = C.Offset(, 0).Value MyArray(i, 2) = C.Offset(, 1).Value MyArray(i, 3) = C.Offset(, 2).Value MyArray(i, 4) = C.Offset(, 3).Value MyArray(i, 5) = C.Row :Rem 元データの行位置をListBoxに追加 Next C 予約確認.ListBox1.List = MyArray Set Sh1 = Nothing Set rng_myRange = Nothing End Sub 以上よろしくお願い致します。 ---- ColumnHeads はRowSourceプロパティにワークシート範囲を指定したときに 有効になります。ワークシートのデータ範囲のすぐ上の行が見出しとして セットされる仕様だからです。配列MyArrayを直接Listに投入するやり方では 有効にならないのでは、と推測します。   ListBox1.RowSource = "Sheet1!A2:B10" ListBox1.ColumnHeads = True ListBox1.ColumnCount = 2   このようなコードなら、Sheet1!A1:B1 が見出しとしてセットされます。 ColumnHeads を生かしたいなら、「.List = MyArray」の部分を上記のような コードに改変していく必要に迫られます。 複数の人が作った「部分的に動作するコード」を組み合わせても 希望通りにはならない、という好例かもしれません。   さらに、他人の作ったコードは読みにくいものです。 ましてやそれが複数の人になれば、なおさら。 掲示板の回答者はある意味無責任ですから、全体とは矛盾する提案をしてしまうこともあります。 往々にして、問題提起されている部分だけを検証します。例えば、リストを作る部分では、 「フィルタで表示されている部分をリストに表示する」っていうことだけに集中しますから。   「まあいいか」の姿勢で、コードをつないでいくだけでは、 完成図のないパッチワークをしているようなもので、最終的には全体を放棄せざるを得ない 可能性もあるということです。 >"Call set_listbox"が効かなくなってしまいました。 は、その兆候かもしれません。 完成ばかり急がないで、VBAの基礎部分を深める時間を持つことをお勧めします。   以下余談: <仕様を考える> オートフィルタのかかったシートをリストボックスに転記する。 そのときのリストボックスには見出しをつけたい。 リストで選択した項目を修正して、元のリストに修正する機能もほしい。   <仕様を実現する機能の検討> リストボックスにデータを転記するにはどんな方法があるか、 リストボックスの見出し機能を有効にする為にはどんな転記の仕方がよいのか、 リストボックスで選択した項目を修正する為にはどんな方法があるか、 また、元のリストへ修正した内容で書き戻すためにはどうすればよいのか。 (いくつか選択肢のあるものについては)それぞれの長所・短所はなにか。   <シナリオの作成> 検討に基づいて、いろいろコードの筋道を描いてみる。 なかには、ある仕様を実現する為にはどうしても使わなくてはならない機能がある。 ColumnHeads は、RowSource でシートから取得しないと難しいみたいだ。 表示部分だけRowSource で取得することは出来ないから、フィルタした結果を シート上に転記する必要がありそうだ、さてどうしよう・・・。   ・・・とここで決断に迫られます。 「フィルタした結果をシート上に転記してColumnHeadsを生かす」か、 「ColumnHeadsは諦めて、RowSource以外の方法でリスト取得する」か。 どちらを選択するかで、その後のコーディングが収束して(選択の幅が狭まって)いきます。 選択の幅が狭まってしまうということは、例えば、他の部分がほとんど全部出来上がって しまっている場合には、一部を実現する為にほとんど全体を手直ししなければならない 可能性も出てきます。   だから、「この部分はわからないけど、とりあえず動いているから『まあいいか』」だと、 少し厳しいところが出てくるかも。 プロシージャ一つの「ツール」ならいいんですよ。 でも、作ろうとしているのは「システム」ですから、全体のフローは最初に作っておく べきですし、フローを作る為には、「こうすれば必ずこうなる」っていう、ある程度 自信を伴ったスキルが必要になってきます。 「ColumnHeads は、RowSource でシートから取得しないと難しい」というポイントは ここまで出来あがっちゃう前に検討すべき問題なのかもしれません。   ・・・とここで決断。 「フィルタした結果をシート上に転記してColumnHeadsを生かす」か、 「ColumnHeadsは諦めて、RowSource以外の方法でリスト取得する」か。   ColumnHeadsいかすのなら、 せっかく配列取得までしているコードがあるのだから、これを利用してみようか。 With Worksheets("sheet2") .Range(.Cells(1, 1), .Cells(UBound(myarray, 1) + 1, UBound(myarray, 2) + 1)) = myarray End With   と適当なシートに転記しちゃって、この範囲をRowSourceに指定する方法はあるでしょうか。 (※追記 myarrayをスパッとやめて、フィルタされたシートをそのままコピペしたほうが早いかも;;;) ただ、これをやって他の部分に影響がないかどうか、私にはわかりません。 ColumnHeads諦めちゃうなら、 予約確認.ListBox1.ColumnHeads = True を消すだけなんですが。   だらだらと書いてしまいました。スミマセン。 (みやほりん)(-_∂)b ---- みやほりん様、おはようございます、まきです。 さて、今回の質問は、過去に質問を出していたソフトのver upに伴う物でした。最初の検討不足がたた ったのでしょうが、いざ使ってみると検索等で不具合が有り、今回の質問に至りました。以前は装置単 位でシートを作り(VBAとは別のbookで)、このシートをVBAのシートにコピペして編集等を行い、作業 完了後また従来のシートに戻す様にしておりました。よって、上記の様な問題が有りませんでした。 しかし全体での検索を行う際に(例:11月に貸し出した一覧等)、別々のシートから読んでまとめる のも面倒の為に、1枚のシートに全ての装置を保存する様にして、オートフィルターを使って個々の装 置の情報を見る様に修正しました。それに伴い、VBAのシートにコピペするのを辞めて、VBAのbookから ではなく他のシートからのdataをフォームに取り込む様にしました。(言い訳ですが。。。) この度のみやほりん様が言われる事は正論です。(私の性格を含め)上記の理由からColumnHeadsを諦め (見栄えの問題だけなので)Call set_listbox相当の方法で、変更後の情報をユーザーフォームのテキスト ボックスに反映出来る様検討を進めてみます。私は営業職でソフト技術者には、ソフトの受注を受けた際に は、仕様やフロチャートをちゃんと検討する様に言っておきながら、自分では「まあいいかっ『どうせ社内 で使うソフトだから』」と言う所があり反省する次第です。(時間も本業の合間で行っているので) もし、他のシートからオートフィルターで読み込み修正後、同データーがテキストボックスで反映させ る良い方法が有りましたら、ヒントでも与えて下さい。この度は、遅い時間にお返事頂きありがとうご ざいました。 以上よろしくお願い致します。 ---- [まき]さんがやろうとしていることは、内容的には「データベースアプリケーション」の 領域になるものです。MSではAccessでしょうか。 元となるリスト(データベース)から抽出したり、転記したりという作業で別の場所に新た なリストを作成し、それに変更を加えたときに、変更点を元となるリストに反映する為には 「元となるリスト」と「新たなリスト」の関連付けをしておく必要があります。 データベースソフトではこれらを紐付け(Accessではリレーションと表現しています)の設 定をして、実現しているようです。   今回の件では、 「元となるリスト」は全体予約シート。 「新たなリスト」はリスとボックス。 ところが、この二つは「転記元」「転記先」という関係があるだけで、それらは連絡し合っ ていません。リレーションなどのデータ同士を紐付けしていく仕組みがありませんから。   だから、先に述べたように、 「もともとのデータに一意なIDを付すか、ListBox1のアイテムとして、行番号も加える」 が今回の場合の鍵になります。こういう鍵を元に、修正すべきデータを見つける仕組みを 作ればよいわけです。   >修正後、同データーがテキストボックスで反映させる良い方法 ということですが、 一つは、 修正したら、リストボックスをクリアして読み込む、という方法。 あるいは、 「適当なシートに転記しちゃって、この範囲をRowSourceに指定する方法」なら、 「元のシート」の修正と同時に「適当なシート」の修正を行えば、自動的にリストボック スも修正されます。転記のコードが不要な分、コード的に簡単には出来ます。 (みやほりん)(-_∂)b ---- みやほりん様、こんにちはまきです。 先ほどの私の返事以降、違うシート間でどの様に同期を取ったらいいのかと考えておりました。みやほ りん様が言われる通り、row番号専用行をもうけて修正する方法がベーターかなとみやほりん様の内容を 読んで思いました。既に予約時からrow番号を入れる様に修正はしてあります。但し、その際には予約した物 件をキャンセルした場合(行削除)、どの様に全データーの番号をソートしたらいいのか考えちゃいます。 (これもキャンセル時にはフラグを立てる事で処理出来ますが、読み込み時にmaskしたりするのも面倒かなぁ? →既に他のコマンドも動いているので。後データーが大きくなる。) 話は変わりますが、当初はアクセスでリレーショップを使い組む予定でしたが(その方が変更、削除や 他のフォームへのデーター受け渡しが簡単だったので)、配布先のPCに全てアクセスが無かった為、エ クセルで作る事になりました。売上伝票はアクセスで作ったので、貸し出した物件の売上上がったか否 かも見られたので、アクセスの方がよかったのですが。。。 変更後のテキストボックスの反映は辞めちゃおうかなぁ(所詮、自分達で使うソフトなので)と頭が傾 いています。(フォームを抜けて、直ぐにシートビューに切り替えちゃえば良いのだから)卑怯かもし れませんが、運用を早く行いたいので(現在黒板に書いてる状況)。。。だからいつになっても進歩が 無いのでしょうね。。。。 みやほりん様はどの様に思いますでしょうか? 以上よろしくお願い致します。 ---- レコードに一意のIDを割り振っていくのがデータベース的な考え方。ですが、 更新時に各シートやコントロールに矛盾が出なければ、行番号での管理も可能と思います。 問題は、メンテナンスを行う方がどちらが理解しながらコーディングできるか、じゃないでしょうか。   行番号は、修正行を特定するのは楽ですが、削除の場合は行番号の再割り付け、コントロール の内容の修正、という処理が増えます。 ID方式の場合は、削除の場合、IDの再割り付けは考えなくても良いのですが、 修正行を特定するのにIDを検索する、というメソッドが必要になります。   どちらが優れている、ということは私には断言できませんが、 どちらを理解しながらコーディングできるかという点は、[まき]さんが判断できます。   参考になるかどうか分かりませんが、私好みのフローは次のようになります。 (内容的な誤解もあるかもしれません) 0.前提   レコードには一意のIDを割り付ける。 1.オートフィルタのかかったシートを「適当なシート」にリンク貼り付け。 2.貼り付けたデータ範囲をリストボックスのRowSourceに指定。 3.リストボックスでレコードを選択。   さらに、選択したレコードのIDを元に元データをオートフィルタ。   この時点で、元データには1レコードしか表示されないので、見出しを除いた、   リスト範囲の可視セルを特定すれば、その行は容易に取得できる。      行番号 = 見出しを除いたリスト範囲.SpecialCells(xlCellTypeVisible).Row    行を割り出すだけならFindメソッドのほうがややこしくないけど。   取得した行番号から、修正用のテキストボックスのControlSourceプロパティに   リンクするセルを設定。何故かというと、コントロールのUpdateだけで転記でき   るから。(シートに書き込むというステートメントは不要になる)      TextBox??.ControlSource = "[ブック名]シート名!列番号" & 行番号      テキストボックスの修正と同時に、元リストは修正されます。   なおかつ、ListBoxのRowSourceに指定している範囲は元リストをセル参照してい   ますから、ListBoxのリスト再取得も不要になります。 4.問題の「削除」は行削除ではなくて、テキストボックスのクリアでデータクリア   (もしくは、見出しを除いたリスト範囲.SpecialCells(xlCellTypeVisible).ClearContents    で、フィルタデータをクリア)でクリアします。      上記の構造が良い点。   とにかく、「修正の為のコード」やそれを実行させる為のボタンが必要ない。   テキストボックスからシートへの転記やリストボックスの更新は考えなくても良い。   リストから選んで、テキストボックスで修正して、次のリストを選んで、を繰り   返せばよい、という作業のリズム感が良い(自己満足)。      上記の構造で不満が出る点。   クリアした場合、「適当なシート」のリンク式は「0」を返す。これをRowSourceに   指定  しているリストボックスには当然その0が表示されちゃう。   これをどう対処するか。   また、テキストボックスがフォーカスを失うと、即同期なので、「あっ、間違えた!」   という場合は、すでに書き換えられた後。Undoも出来ないので、慎重な人向け。   あくまで、このトピックの相談''だけ''を踏まえて、ということで。 (みやほりん)(-_∂)b ---- みやほりん様、おはようございます!まきです。 レコードに一意のIDを割り振っていくのがベターな考えだと私も思います。昨日までID=Row data と考えていたので、削除した場合ID=Row dataの秩序が崩れちゃうのをどうするのかと考えており ましたが、変更するIDを検索してRow addressを読み、dataを削除や修正すれば良いだけですね。 私のエクセルの知識が薄いのかもしれませんが、data用のエクセルシートからVBA用のエクセルシートに オートフィルターのリンク貼り付けをしても、リンク先を修正(VBAのコピーした方)してもリンク元の dataは変わらないと思うので(修正すると、リンクが切れて修正した値が入るだけ)、VBAシートにオー トフィルター後対象でない行を削除してコピー(するとColumnHeadsやユーザーフォームのCall set_listboxが効く) した物をユーザーフォームのテキストボックスに使用する様に考えてみます。 今回は色々アドバイス頂き有り難うございました。また何か有った際には、よろしくお願い申し上げます。 一人で考えていたら、きっと今頃頭の中が@@状態でした。  by まき