KeyUpイベントが効かないようにするには

解決


  2005-08-22 20:44:43  No: 91656

現在、KeyUpイベントを使用して、あるキーが押されたらインプットボックスに
入力させる処理を行っているんですが、入力後のリターンキーをKeyUpイベント
が拾ってしまってうまくいきません。
そこでKeyUpイベントルーチンの先頭でイベントを効かないようにして、抜け出す
ときに効くように戻そうかと思っていますが、そのような機能はあるのでしょか?
どなたか教えていただければたすかります。


Geo=TK3  2005-08-22 23:17:04  No: 91657

>そこでKeyUpイベントルーチンの先頭でイベントを効かないようにして、抜け出す
>ときに効くように戻そうかと思っていますが、そのような機能はあるのでしょか?

質問する時は VisualBasic のバージョンを明記してください。
ご使用の VisualBasic のバージョンによって回答が変わってくる事が
ありますので。

で、とりあえず VB6.0 の場合はそのような機能はなかったと思います。
代案としては
・KeyUp イベント処理中であるフラグを用意して回避する
・(支障がなければ) KeyUp イベントでは Enter キーの入力を無視する
  ようにする
あたりが考えられるでしょうか。


  2005-08-22 23:30:06  No: 91658

Geo=TK3さん 申し訳ありません。
OSはWindows2000、言語はVB.netを使用しております。
とりあえずフラグのオンオフで考えましたがまだ成功していません。
なにとぞ良い解決法が、あればご教授お願いします。


特攻隊長まるるう  2005-08-22 23:36:08  No: 91659

>とりあえずフラグのオンオフで考えましたがまだ成功していません。
普通に考えればそれはプログラムがマズいわけですが、
どんなプログラムを書いてどう上手くいかないのか?
の説明無しにこちらでできる助言はありません。


  2005-08-23 00:24:16  No: 91660

説明不足ですいません。
キーイベントは下記のようなルーチンで、ESCキーが押されたら番号を入力させて、データ内をその番号で検索してあればその行を表示し、無ければその番号でデータを追加しようと思っております。
しかし、番号入力時のリターンを検知して再度このルーチンに入ってリターンキーの処理をしてしまい、番号入力後の処理が出来ないでいます。
従って、できればフラグではなくこのルーチンに処理が移ったら先頭でキーイベントの禁止を行い、このルーチンから抜けるときに許可を行うことができればよいのですが、そんな都合の良い命令はあるのでしょうか?

   Private Sub Form_KeyUp(ByVal sender As Object, _
                           ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp

        Dim i, a, F_tuika, F_wari As Integer
        Dim result As String

        If F_wari = 0 Then 
                     Select Case e.KeyCode
                        Case vbKeyRET             'RETキー
                            K_code = vbKeyRET
                        Case vbKeyTab             'TABキー
                            K_code = vbKeyTab
                        Case vbKeyESC             'ESCキー
                            F_wari = 1
                            result = InputBox("№を入力してください" _
                            , "№入力", No        '№の入力

№入力後にここからの処理をさせたいが、№入力時のリターンキーで上記の
K_code = vbKeyRETに処理が移ってしまう。
 
                            For i = 0 To LinMax
                                    データを入寮した番号で検索
                            Next
                              検索で見つからなかったのでデータ追加
                              F_wari = 0
                       Case vbKeyF2               'F2キー(終了)
                            K_code = vbKeyF2
                    End Select

        End If

    End Sub


ねろ  2005-08-23 00:41:31  No: 91661

Geo=TK3さん言われる通り、フラグ処理で、
Private Sub Form_KeyUp(・・・・
      Static Flg As Boolean
      If Flg Then Exit Sub
      Flg = True

      処理・・・
      処理・・・

      Flg = False
End Sub
とやれば良いでしょう。


  2005-08-23 01:10:56  No: 91662

回答ありがとうございます。
早速フラグの処理で試してみましたが、リターンキーの処理に移ることはなくなったのですが、ESCキーの処理の残りの処理をやってくれません。

   Private Sub Form_KeyUp(ByVal sender As Object, _
                           ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp

        Dim i, a, F_tuika, F_wari As Integer
        Dim result As String
        
        Static Flg As Boolean
        If Flg Then Exit Sub                      '禁止フラグオン?
        Flg = True

       Select Case e.KeyCode
              Case vbKeyRET             'RETキー
                   K_code = vbKeyRET
              Case vbKeyTab             'TABキー
                   K_code = vbKeyTab
              Case vbKeyESC             'ESCキー
                   result = InputBox("№を入力してください" _
                   , "№入力", No        '№の入力

ここからの処理に移ってくれない

                   For i = 0 To LinMax
                        データを入寮した番号で検索
                   Next
                    検索で見つからなかったのでデータ追加
                    Flg = False
              Case vbKeyF2               'F2キー(終了)
                   K_code = vbKeyF2
      End Select

    End Sub


特攻隊長まるるう  2005-08-23 01:20:15  No: 91663

なんで e.KeyCode の Select 文で Keys 列挙体を使わないのだろう(疲)

…あと、こちらでは再現しません。デバッグした限りでは
>しかし、番号入力時のリターンを検知して再度このルーチンに入って
>リターンキーの処理をしてしまい、番号入力後の処理が出来ないでいます。
番号入力後の処理はちゃんと処理されてて、その後リターンでイベントが
走ってるようですが???ちゃんと動きを把握してますか???そっちの
問題を言っているなら質問文が間違ってますよ?。質問どおり
>番号入力後の処理が出来ないでいます。
なら先の御二方と同じくフラグで解決できると思います。

後者の問題なら
InputBox 使わずに別フォームで入力させれば解決しそうな気がしますが。

>早速フラグの処理で試してみましたが、リターンキーの処理に移ることは
>なくなったのですが、ESCキーの処理の残りの処理をやってくれません。
フラグの場所が悪いのでは?

出力結果を教えて下さい。
[VB.NET]
    Private Const LinMax As Integer = 1
    Private K_code As Keys
    Private mEventMusi As Boolean

    Private Sub Form_KeyUp(ByVal sender As Object, _
                            ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp
        Dim i, a, F_tuika, F_wari As Integer
        Dim result As String
        If Me.mEventMusi = True Then
            Debug.WriteLine("無視")
            Exit Sub
        End If
        If F_wari = 0 Then
            Select Case e.KeyCode
                Case Keys.Enter     'RETキー
                    K_code = Keys.Enter
                    Debug.WriteLine("RET")
                Case Keys.Tab       'TABキー
                    K_code = Keys.Tab
                    Debug.WriteLine("TAB")
                Case Keys.Escape    'ESCキー
                    Debug.WriteLine("ESC")
                    Me.mEventMusi = True
                    F_wari = 1
                    result = InputBox("№を入力してください" _
                    , "№入力", "No") '№の入力
                    For i = 0 To LinMax
                        'データを入力した番号で検索
                        Debug.WriteLine("検索" & i.ToString)
                    Next
                    '検索で見つからなかったのでデータ追加
                    F_wari = 0
                    Me.mEventMusi = False
                Case Keys.F2        'F2キー(終了)
                    K_code = Keys.F2
            End Select
        End If
    End Sub


  2005-08-23 03:07:06  No: 91664

特攻隊長まるるうさん、回答ありがとうございます。
初心者なのでとんちんかんな質問をしているかもしれませんが申し訳ありません。
早速回答のコードを書き込んで実行しましたが、番号入力後はLinemaxを1にして
いるので表示は2行でしたがその2行がコピーされて4行になりました。そして
Debug.WriteLine("検索" & i.ToString)は実行されず"検索"も表示されませんでした。RET、TAB、ESCはきちんと表示できています。
ご指摘のようにうまくいくはずなんですが・・
もう少しがんばってみます。


Geo=TK3  2005-08-23 14:20:08  No: 91665

>早速回答のコードを書き込んで実行しましたが、番号入力後はLinemaxを1にして
>いるので表示は2行でしたがその2行がコピーされて4行になりました。そして
>Debug.WriteLine("検索" & i.ToString)は実行されず"検索"も表示されませんでした。

んー...
これは特攻隊長まるるうさんが提示してくれたコードをそのまま使った時の
実行結果ですよね?
それとも InputBox と For 〜 の間に何か自前の処理いれてます??

>RET、TAB、ESCはきちんと表示できています。

“無視”というのは表示されていますか?


  2005-08-23 17:46:33  No: 91666

Geo=TK3さん、ありがとうございます。
InputBox と For 〜 の間には何も入れていません。報告漏れでしたが昨日はESCが表示された後に番号入力をすると“無視”が表示されてその後は何のキーを押しても“無視”の表示のみでしたが、タイミングの問題なのかもしれませんが、先ほどの結果は番号入力後に2行コピーまでは同じですが"検索"が2回表示されました。その後数回試したら“無視”の表示になってしまいました。
とりあえず中間報告をしておきます。引き続きがんばってみます。


特攻隊長まるるう  2005-08-23 18:36:15  No: 91667

うーん。不安定ですねぇ。…そんなに順番変わるものかなぁ…。
KeyUp イベントの先頭で
    Debug.WriteLine(e.KeyCode)
して何のキーイベントが起こってどう処理されてるのか確かめる
必要があるかなぁ?

[VB.NET]のバージョンは 2003 ?
OSは?サービスパックは?

それとキーイベント系の処理は他に利用してないよね?
DoEvents も使ってないですよね?
フォームでキーイベントを拾ってるという事は
    KeyPreview = True
してると思ったんだけど間違ってる?
新規プロジェクトのフォームにテキストボックスを1つ貼り付けて、
フォームの KeyPreview = True して、ボクの提示したコードだけ
コピペして実行しても同じ結果ですか?

>昨日はESCが表示された後に番号入力をすると“無視”が表示されて
>その後は何のキーを押しても“無視”の表示のみでしたが
変数を Static にしてない?わざわざ変数名まで変えてサンプル示した
んだからコードの意味も理解してからテストしてね?(^^;)


特攻隊長まるるう  2005-08-23 18:47:02  No: 91668

エラー処理も削除してね?質問であげた以外でやってることを
全て削除してテストして下さいね?


  2005-08-23 19:04:09  No: 91669

特攻隊長まるるうさん、回答ありがとうございます。
[VB.NET]のバージョンは 2003、OSはWindows2000、サービスパック=4です。
キーイベント系の処理は他に利用してません。
DoEventsを使っています。当初これを使用しないとリストビューのデータが
表示できなかったのでヘルプを見て使用しました。
KeyPreview = Trueにしています。
変数を Static に変更していません。

下記にメインルーチンを書きました。
DoEventsが間違っているのでしょうか。

    Private Sub Form1_Activated(ByVal sender As Object, _
                                ByVal e As System.EventArgs) Handles MyBase.Activated

        '********************************
        '*      データ読込            *
        '********************************

        Mode = 0                                                    'モードを選択中

        Call Yoteireed()                                            '予定データ読み込み

 
        Call disp()                                                 'データ表示

        '********************************
        '*      オーダー選択            *
        '********************************

        P_line = 0                                                  '対象行№を先頭
        ListView1.Items(P_line).Selected = True
        ListView1.Select()                                          '先頭行をアクティブにする
        T_start = TimeString                                        '開始時刻取得
        Me.start.Text = T_start
        Me.M_Mode.Text = Msg(Mode)                                  'モードの表示

        Do While K_code <> vbKeyRET
            For Each si As ListViewItem In ListView1.SelectedItems
                P_line = si.Index                                   'ポインター取得
            Next
            Me.J_number.Text = JutyuN(P_line)                       '受注№表示
            Me.Now.Text = TimeString                                '現在時刻取得

            If K_code = vbKeyF2 Then GoTo OWARI '終了か?

            Application.DoEvents()

        Loop


ねろ  2005-08-23 19:09:09  No: 91670

良く考えると、Form_KeyUpイベントでやると上手くいきませんね。
>result = InputBox("№を入力してください" _
>         , "№入力", "No") '№の入力
この時『OK』ではなく『Return』を押すと、処理はキーの押下時に
すぐ続行されますので、キーを離した時には既にこのForm_KeyUpイベントは抜け
フラグがリセットされされるので、再び Form_KeyUpイベントが起こり、
Keys.Enterの処理をします。
ブレークをかけたり、キーを叩くようにするとタイミングが変わります。
result = InputBox(...  の時Returnキーを押しっぱなしにすると良く判ります。
Form_KeyDownイベントで処理すれば問題ないと思われるのですが、何か別の
問題が有るのでしょうか。


Geo=TK3  2005-08-23 19:39:07  No: 91671

あと気になった事1点。
メインルーチンとして公開したソース、どうやら Form_Activated 
イベントハンドラのようですが、これだと InputBox で表示した
ダイアログボックスが消去された時に再度呼び出されたりしませ
んかね??
VB.NET が手元にないので確認出来ないんですけど、VB6.0 の
Form_Activate イベントと同じような動作をするのなら何かヤバい
気が...


特攻隊長まるるう  2005-08-23 20:37:39  No: 91672

色々と(ボク的に)気持ち悪いコードが出てきたのはとりあえずスルーしてw
ねろさんの書き込み見て InputBox のキーイベントが何で Form に流れて
来てるのか疑問に思ってたけどオイラの勘違い?
・InputBox Enter
・Enter KeyDown
・InputBox 消え
・Enter KeyUp → Form が受け取る
…かもしかして?

2つ疑問。
1つ目。ある関数(Form_KeyUp)の処理中に起こったキーボードからの
イベント(Enter KeyUp)ってキューされて溜まるんじゃないのかと思って
たんだけど違った?。(ボクのサンプルでは InputBox の後に Doevents
を入れてないから Debug.WriteLine("検索" & i.ToString) が先に実行
されると思ってた)
2つ目、仮にキーボードからのイベント(Enter KeyUp)が先に処理されたと
して、ボクの示したコードではフラグの変更が組みになってる部分の処理は
必ず通るはず…間に色んなイベント処理が入ったとしても
   result = InputBox("…
の後の
    Debug.WriteLine("検索" & i.ToString)
が永遠に実行されない理由がボクの知識内では見当付きません。
エラー処理か Goto 文や Exit 系の処理で抜けないと不可能だと
思うんですが…あるんでしょうか?そんな事。

>Form_Activate
>これだと InputBox で表示したダイアログボックスが
>消去された時に再度呼び出されたりしませんかね??
…色んな予期せぬ処理が盛りだくさんな予感。


特攻隊長まるるう  2005-08-23 20:54:25  No: 91673

[VB.NET]ボクのサンプルの修正点のみ
                    result = InputBox("№を入力してください" _
                    , "№入力", "No") '№の入力
                    System.Threading.Thread.Sleep(1000)
                    For i = 0 To LinMax
                        System.Threading.Thread.Sleep(1000)
                        'データを入力した番号で検索
                        Debug.WriteLine("検索" & i.ToString)
                    Next

    Private Sub Form1_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Activated
        Debug.WriteLine("Form1_Activated")
    End Sub

[出力結果]
>ESC
>Form1_Activated
>検索0
>検索1
>RET
Activated ヤバいね。


ねろ  2005-08-23 21:52:40  No: 91674

>[出力結果]
の最後の>RETは?


特攻隊長まるるう  2005-08-23 22:03:20  No: 91675

>の最後の>RETは?

>検索1
までが Escape KeyUp による InputBox の処理。
正常にループを処理して Form_KeyUp 関数を抜けた後、
溜まってた Enter KeyUp が2回目の Form_KeyUp 関数で
>RET
出力

ボクの中の結論としては
Form1_Activated の処理で DoEvents が溜まってた
Enter KeyUp を実行しちゃって誤動作…と思うんだけど、
それでもループの出力が無くなるのは理解できなかったです。
再現もできてません。


  2005-08-23 22:09:07  No: 91676

DoEventsを外してActivatedをLoadに戻して、メインルーチンのループを止めて
解決しました。うまくいかなくて泥沼にはまっていたみたいです。皆さんの意見
を読みながらプログラムを整理しなおして目からうろこでした。
特攻隊長まるるうさん、Geo=TK3さん、ねろさん本当にありがとうございました。


特攻隊長まるるう  2005-08-23 22:25:31  No: 91677

リストビューが更新されないだけなら
    Me.ListView1.Refresh()
てのもあります。


Geo=TK3  2005-08-23 23:19:52  No: 91678

遅くなりましたが特攻隊長まるるうさん、Form_Activated に
関する検証どうもありがとうございました。

>それでもループの出力が無くなるのは理解できなかったです。
>再現もできてません。

これは Form_Activated イベントハンドラの中にあるループが
終わらなくなったんじゃないかなぁ、って気がします。
元の Form_Activated イベントハンドラでは K_code という変数が
vbKeyRET にならないと Do 〜 Loop ループが終わらないけど、単
純に Form_KeyUP を特攻隊長まるるうさんのものに差し替えただけ
でループの終了条件を満たさなくなった、とか (^^;; 。


特攻隊長まるるう  2005-08-24 00:08:02  No: 91679

あーΣ(‾□‾)Form1_Activated のループかー
抜けられないねー(汗)
オイラ頭硬くなってるなー(  _)_へたり
InputBox → Activated → ループの虜
の繰り返し?…Sleep もしてないし、内部的に CPU は
すごい頑張ってたのかもー。実行したら重くなかった?
…よく動いてたね、このコード。
ちょっと感心しました、CPU に対してw。

すっきりしましたm(__)m
>Geo=TK3 さん


ねろ  2005-08-24 01:12:55  No: 91680

解決したようですが、
FormにTextBoxを一つ置き、FormのKeyPreviewをTrueにしますよね。
そこで
Private Sub Form_KeyUp(ByVal sender As Object, _
     ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp
     Select Case e.KeyCode
            Case Keys.Return
                Debug.WriteLine("Return")
            Case Keys.Escape
                Dim result As String = InputBox("")
     End Select
End Sub 
これだけのコードを書き、Escapeを押して、InputBoxにReturnを押します、
すると Debug.WriteLineにReturnが書かれます、これは明らかにInputBoxの
ReturnのKyeUpイベントですよね、これを回避するにはどうするかと言う
質問ではないのでしょうか、これはフラグでもSleepでも解決しないと
思うのですが、それともその質問は途中で終わったのか。。。
解決したと言うならそれでもいいのですが・・・


Geo=TK3  2005-08-24 21:51:00  No: 91681

>すると Debug.WriteLineにReturnが書かれます、これは明らかにInputBoxの
>ReturnのKyeUpイベントですよね、これを回避するにはどうするかと言う
>質問ではないのでしょうか、これはフラグでもSleepでも解決しないと
>思うのですが、それともその質問は途中で終わったのか。。。
>解決したと言うならそれでもいいのですが・・・

大元の質問は途中で終わってますね、確かに。

話をそちらに戻すと。
特攻隊長まるるうさんがやったくださった Form_Activated の検証結果から
みても、ねろさんのご推察通り、単純なフラグや Sleep では InputBox の 
Return の KeyUp イベントは回避できないと私も思います。
# 公開されているテストコードを使っていて、それで一番最後に RET が出力
# されているのが...

対策として一番簡単なのは、やはりねろさんがおっしゃっていたように 
KeyDown イベントで処理するように変える事ですが、あえて KeyUp イベントの
ままでいく方法を考えてみました...が結局

・処理中フラグをクリアするタイミングを KeyUp イベントハンドラの
  Return キー処理時のみにする

というかなりトリッキーなものしか思いつきませんでした (^^;; 。
# いっそ Return キーを無視してしまうというのも考えなくもないですが。


特攻隊長まるるう  2005-08-24 22:11:52  No: 91682

んー。オイラは最初から (InputBox の誤動作と勘違いしてたのでw)
InputBox 使わずに自分で動作を制御できる Form で入力させて
そっちのフォームで Enter KeyUp が処理されるまで待ってやれば
いいだけでは?…と思ってましたが。


Geo=TK3  2005-08-24 22:59:12  No: 91683

あ、その手がありましたね (^^;; 。
別にわざわざ InputBox にこだわる必要はないのですし (^^;; 。
何か発想ヨワ〜。>自分


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加