Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 11 Pro : Excel 2016)
↓キーと↑キーでは動きが違う?
投稿日時: 23/02/13 16:04:29
投稿者: taichi

UserForm に Listbox1、TextBox1、CommandButton1 を配置して試しています。
 Listbox1は1〜6(学年)の数字,TextBox1には3桁の数字を入力し、例えば 234 と
入力すれば1年(ListIndex=0の状態で)で234番の児童を検索できるようにするつもりです。
 UserForm.Show vbModeless で使用します。
 
学年は結構ばらばらに並んでいるので、学年変更でマウスを使うのも面倒なので、
↓キーと↑キーで Listbox1のListIndexを変更するためのコードとして
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    Select Case KeyCode
        Case 38 'Up Arrow
            If ListBox1.ListIndex > 0 Then
        ListBox1.ListIndex = ListBox1.ListIndex - 1
      End If
        Case 40 'Down Arrow
            If ListBox1.ListIndex < ListBox1.ListCount - 1 Then
               ListBox1.ListIndex = ListBox1.ListIndex + 1
            End If
   End Select
End Sub
Private Sub ListBox1_Change()
   検索コード
End Sub
 
■ ↓キーでは1回ごとにTextBox1からフォーカスが CommandButton1に移動
してしまうので、TextBox1をクリックしてからでないと次のListIndex に変更
されず連続↓の効果がありません。
■ ↑キーではTextBox1からフォーカスが消失しないので、連続して↑キーで
ListIndexは変化し目的は達成できています。
■ ↓キーと↑キーでは動きが違うきがします。
 
宜しくお願いいたします。
 

回答
投稿日時: 23/02/13 17:01:59
投稿者: WinArrow
投稿者のウェブサイトに移動

ヒットした時に、ヒットしたデータが表示されればよいので
リストボックスの中を検索するのに、
ListIndexを使用する必要はありません。
ListIndexの値を変更すると、イベントが発生する(画面が変化する)ので、
画面が動くことで、レスポンスが落ちます。
 
例えば、変数:Lxを使用します。
サンプルコード
  

Private Sub CommandButton1_Click()
Dim Lx As Long
    With Me.ListBox1
        For Lx = 0 To .ListCount - 1
            If .List(Lx, 0) = Me.TextBox1.Text Then
                .ListIndex = Lx
                Exit For
            End If
        Next
    End With    
End Sub

 
※ヒットしたら、検索する必要はないので、ループから抜ければよいです。
 
※上から検索したほうが早いか/下から検索したほうが早いかは、
データの中身如何です。
 
 
 

投稿日時: 23/02/13 19:39:19
投稿者: taichi

WinArrow さん いつも有り難うございます。
 
B列に4桁の数値が入っています。千の位は学年を表しています。下3桁は登録されている番号です。
資料は受付順に並んでいるので学年ごとに纏まっていなくてバラバラな状態です。
Private Sub TextBox1_Change()の中で
FindNo=1000*Listbox1.Value+Val(TextBox1) 'TextBox1は3桁の数値
Set myFind=データSheet.Columns("B").Find(What:=Format(FindNo, LookIn:=xlValues, LookAt:=xlWhole)
で検索して、処理しています。
 
私の一番の疑問は、ListIndex=0 の状態で↓キーを押した場合TextBox1からフォーカスが 外れ
CommandButton1に移動してしまい、6年までListIndexを変化させられません。
ところが、ListIndex=5の状態で↑キーを連続ぢて押すと4,3,2,1を希望通り順次選択が
可能になります。何故↓キーではフォーカスがTextBox1から外れるのかが疑問です。
 
>.List(Lx, 0)は複数列のListですよね。学年と3桁番号にするのですか?

回答
投稿日時: 23/02/13 20:50:21
投稿者: WinArrow
投稿者のウェブサイトに移動

掲示したコードは、ヒントです。
解答ではありません。
 
↓最初の質問時には説明がなかった
シートのデータとリストボックスは連動しているんですよね?
 
どちらのデータを検索→取得したいんですか?
 
先頭の1桁が学年ということは、
下3桁が同一の人がいますよね?
でも、複数の人を同時に検索する必要はないですよね?
なぜ、時間が掛かる「↓」でリストボックスを操作するんですか?
 
 
 
 
 

回答
投稿日時: 23/02/13 20:55:50
投稿者: WinArrow
投稿者のウェブサイトに移動

>Private Sub TextBox1_Change()
の問題点
 
テキストボックスは手入力ですか?
1桁でしょうか?
1桁ならば、問題はないが、
2桁以上入力する場合は、1桁ごとにイベントが発生することを
認識した方がよいですよ!

回答
投稿日時: 23/02/13 23:36:03
投稿者: WinArrow
投稿者のウェブサイトに移動

最初の説明を、取り違えていました。

引用:

Listbox1は1〜6(学年)の数字,TextBox1には3桁の数字を入力し、例えば 234 と
入力すれば1年(ListIndex=0の状態で)で234番の児童を検索できるようにするつもりです。

 
ListBox1の「値」(1〜6)とTetbox1の「値」で
シートの表を検索するということですね?
 
 
疑問1
選択肢が6つしかにのだから
Listbox1を手操作で「↓」「↑」すれば、テキストボックスのKEYでそうさするより早いと
思います。
それとも「1」〜「6」まで、連続で検索したいということかな?
 
別案
オートフィルタを使った方が早いのではないでしょうか?
シート表内が、ランダムでもオートフィルタのドロプダウンリストは昇順になります。
または、数値フィルタ’ユーザ定義)で「1000〜1999」の範囲指定も可能です。
文字列ならば、テキストフィルタで、「?234」のような指定もできます。
 
 
 
 
 
 

投稿日時: 23/02/14 09:37:54
投稿者: taichi

 
>Listbox1を手操作で「↓」「↑」すれば、テキストボックスのKEYでそうさするより早いと
>思います。
はじめはそうしていました。
下3桁の数字を入れ、Hitすれば当日の出席欄に〇を付ける作業です。
 
日々、数百人分番号を次々と入力し記録していきます。
「↓」「↑」で学年を変更しようとしたのは、指が常に数字キーの付近にあります。
セル移動は検索Hit後に移動させているのこの間はあまりマウスをつかいません。
 
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  …
End Sub
で楽をしようと考えたのですが、「↓」の場合にうまくいかないのです。Eventが発生して少し時間が
かかっても我慢できます。
何故「↓」の場合にうまくいかないのかが疑問なのです。

回答
投稿日時: 23/02/14 10:25:31
投稿者: WinArrow
投稿者のウェブサイトに移動

>下3桁の数字を入れ、Hitすれば当日の出席欄に〇を付ける作業です。
  
説明不足があると思います。
下3桁でヒットする・・・・最大6人が考えられます。
氏名を確認する必要がありますね?
  
最大6人だから、スクロールさせずに、
6人分1回に表示したらどうでしょう?
 
どこに○を付けるのでしょうか?
この時、手はキーボードの上にはあるの尾ですか?
  
例 サンプルコード
  
↓のイベントを使うとよいでしょう。
Option Explicit
 

Private Sub TextBox1_AfterUpdate()
Dim 氏名 As String
Dim SKEY As Long, Lx As Long
Const ShtNM = "Sheet1"
    
    With Me.ListBox1
        .ColumnCount = 2
        .ColumnWidths = "30;80"
        .Clear
        For Lx = 0 To 5
            SKEY = Lx + 1 & Me.TextBox1.Text
            If WorksheetFunction.CountIf(Sheets(ShtNM).Columns("B"), SKEY) > 0 Then
                氏名 = WorksheetFunction.VLookup(SKEY, Sheets(ShtNM).Colimns("B:C"), 2, False)
            Else
                氏名 = ""
            End If
            .AddItem SKEY
            .List(.ListCount - 1, 1) = 氏名
        Next
    End With
End Sub

 
テキストボックスでEnterを押すと
リストボックスに6人の氏名が表示されます。

回答
投稿日時: 23/02/14 11:23:36
投稿者: simple

お邪魔します。
>何故「↓」の場合にうまくいかないのかが疑問なのです。
それは↓がコントロールを移動する命令で、それが単に機能しているからでは?
その移動ルールはTabとは異なるようですが、
↑のときに動かないのは、位置的に上が無いと判断しているからでしょう。
(ExitプロシージャでCancel=Trueとするとフォーカスを移動させないようにできますが、
   本当に移りたいときに、今度は逆にそれが制約となって外に出れなくなってしまいます。)
 
そもそもですけど、入力者は全学年の入力担当なんですか?
年度がバラバラな入力が求められるなら、
いっそ4桁(学年+番号)を直接入れたほうがキー操作だけで完結しませんか?
 
なお、同じ問題が発生するでしょうから問題解決には貢献しない話ですが、
学年選択はオプションボタンで選択させるほうが普通な気がします。

回答
投稿日時: 23/02/14 12:06:53
投稿者: Suzu

今回の、KeyDownを含めた、Key ○○のイベントは
 
キーを押した際(後・放す時)に、
1.イベントプロシージャが実行
2.その後に、コントロールで、そのキーを押した際(後・放す時)の本来の処理が行われる
 
の流れです。
 
 
今の状態で、各プロシージャをコメントアウトてください。
その上で、リストボックスにフォーカスがある状態で ↑ を押したら?
     リストボックスにフォーカスがある状態で ↓ を押したら?
 
それぞれ確認してみてください。
 
↑を押しても何もならないけど、↓を押したら、CommandButton1 へフォーカスが移動しませんか?
 
イベントプロシージャで割込み処理を行った後、本来のキーの動作が行われている事が判ると思います。
 
特定のキーだけイベントプロシージャ内で特別な処理をし、
その後、本来の処理をさせたくないなら、
 イベントプロシージャ内 の処理の最後に、KeyCode=0 を入れれば良いです。

回答
投稿日時: 23/02/14 16:54:46
投稿者: はぶ

失礼します。試しに、TextBox1 と CommandButton1 の間に
ダミーの Label コントロールを配置してみてはどうでしょう。

投稿日時: 23/02/15 22:28:17
投稿者: taichi

■ WinArrow さん
>テキストボックスは手入力ですか? → テンキーからの入力です。
>複数の人を同時に検索する必要はないですよね? → ありません
>シートのデータとリストボックスは連動しているんですよね?
 データシートのがActiveSheeノ状態で番号列を4桁の数字で検索し、同じ行に出席記号〇
 をいれています。
>なぜ、時間が掛かる「↓」でリストボックスを操作するんですか?
  ※ の説明をごらんください。
 
TextBox1は長さを3桁に制限し、長さが3になった時点で、検索するように
しています。エラー処理もしています。今回の質問では、コントロールは
 ListBox1、CommandButton1、TextBox1 で
コードは 3つだけで動きを試しています。
Private Sub UserForm_Initialize()
    Dim n As Integer
    For n = 1 To 6
        ListBox1.AddItem n
    Next
    ListBox1.ListIndex = 0
End Sub
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    Select Case KeyCode
        Case 38 'Up Arrow
            If ListBox1.ListIndex > 0 Then
        ListBox1.ListIndex = ListBox1.ListIndex - 1
      End If
        Case 40 'Down Arrow
            If ListBox1.ListIndex < ListBox1.ListCount - 1 Then
               ListBox1.ListIndex = ListBox1.ListIndex + 1
            End If
   End Select
End Sub
Private Sub CommandButton1_Click()
    End
End Sub
 
■ はぶ さん
>試しに、TextBox1 と CommandButton1 の間に
>ダミーの Label コントロールを配置してみてはどうでしょう。
 
不思議なことに、TextBox1にフォーカスがある状態で、問題のある↓でも
TextBox1からフォーカスがなくなることはありませんでした。
もちろん↑でもOKです(これはダミーの LabelをいれなくてもOK)
 
↓ならフォーカスはTextBox1のまま、↓は↓を押すたびに
フォーカスがCommandButton1に移動する。
何故なんでしようね。 理屈がわかりません。
 
 
■ simple さん
>リストボックスにフォーカスがある状態で ↑ を押したら?
>リストボックスにフォーカスがある状態で ↓ を押したら?
↑ ↓どちらもListIndexは問題なく移動します。
ただその後TextBox1で3桁数字を入力しなければなりません。
 
※ なぜ、ListBox1(1〜6)とTextBox1(3桁の数字)に分けて
4桁の番号を検索するようにした理由を書きます。
全くランダムに4桁番号が並んでいるのなら初めから
4桁を入力した時点で検索し、出席欄に〇を記入するようにしますが、
実は、毎日 1年生が10数人続いた後で2年生がまた10数人……と続いて記録する
ような状態なので、全員4桁入力するのも面倒なので、せめて学年が同じ間だけは
下3桁でけの入力で、記録したかったのです。ほとんどテンキーばかりですので、
マウスを使って学年の数字を変更するのが面倒だったので、TextBox1にフォーカスを
保ったまま↑ ↓で楽したかったのです。

回答
投稿日時: 23/02/16 07:57:04
投稿者: WinArrow
投稿者のウェブサイトに移動

taichiさん
 
オペレーションが、ようやく、理解で今した。
テキストボックスを入力ご、リストボックスを操作すると
思っていたので、「なぜ?」といつ疑問がわいてきました。
 
先に、リストボックスを選択しておいて、
10数人分の入力
という操作をする
その間、マウス←→キーボードの切替もしたくない
ということが理解できました。
 
察しが悪くてすみませんでした。
 

投稿日時: 23/02/16 14:37:37
投稿者: taichi

一応目的は達成できました。
 
結局 はぶ さんの提案
 
TextBox1 と CommandButton1 の間にダミーの Label コントロールを
配置しました。勿論 Caption=Empty です。
 
ダミーの LabelのTabOrderは最後に挿入したので一番したです。
レイアウトはダミーの Labelを入れた分だけ間がぬけますが、
商品でないので我慢できます。因みにダミーの Label.Height=0では効果なしです。
ダミーの Label の配置位置は最後に追加したにも拘わらず、中間に配置しなければ
効果ありませんでした。
 
理屈が分からないまま使うのもすっきりしませんが、こちらの方が作業効率が
上がります。
 
一応解決とさせていただきます。
もし理屈がわかりましたら、もう一つ新たに質問(TextBoxにフォーカスを戻す)を
しますのでよろしくお願いいたします。
 
WinArrow さん Suzu さん はぶ さん ありがとうございました。