[[20140626124047]] 『テキストボックスで間違った入力をした時元のテキストボックスへ』(中途半端) ページの最後に飛ぶ

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

 

『テキストボックスで間違った入力をした時元のテキストボックスへ戻るには』(中途半端)

 フォーム上のテキストボックスで本来求める形式で入力されなかった場合、
 vbaで元へ戻るコードを書いても次のコントロールへ移動してしまいます。
 (例)If Not IsNumeric(Tx1) then
         Tx1=""
         Tx1.SetFocus
      End If
  しかし次のコントロールへ? 簡単な方法で何とかなりませんか!

 関連して、MsgBoxの結果次第で直接Formを閉じたり、Excelを終了させる事は可能でしょうか?
 (例)If MsgBox("PassWordが違います。終了しますか?",VbYesNo) = VbYes Then
         Unload Me
      End If
 この結果はエラーになります。コマンドボタンを追加して終了処理をしなければなりません。

 MsgBoxで意向確認した後、更に終了ボタンを押さなければならないなんて不自然!
 私としては結果次第で即終了したいのです。

 どうか力添えをお願いします。

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


 上記は TextBox1_Exit で書いているとして、内部で TextBox1 にフォーカスしても
 その後の処理で、次のフォーカスへ移動してしまいます。
 If 文の中でイベント処理後に継続処理をしないよう Cancel=True を追加してください。

 Unload Me に関しては提示のコードでエラーなく動作しましたが、どのようなケースで
 なんと言うエラーになるのでしょうか。
 Me がユーザフォームを指していれば問題ないと思いますが、
  UnLoad UserForm1
 のように明記してもエラーになるでしょうか。
(Mook) 2014/06/26(木) 13:46

Mookさん 有難うございます。
 私はイベント AfterUpdate を使っていた為に UnLoad Me とするとオートメーションエラー云々
 となっていたのです。☆ Exit イベントの意味が良く分かりません。使い分け方法が・・・

 早速、Tx_AfterUpdate → Tx_Exit へ書直して思い通りの動作となりました。

 Private Sub Tx_Exit(ByVal Cancel As MSForms.ReturnBoolean)
 Dim PW As String
 Const Msg = "パスワードが違います" & vbCr & "再入力しますか?"

    If UCase(Tx.Value) = "HAJIMEMASU" Then
       Unload Me
    Else
       If MsgBox(Msg, vbYesNo, "") = vbYes Then
          Tx = ""
          Cancel = True   '追加しました。
       Else
          Unload Me       '←この時も即終了したいのですがもう一度回って来ます。
       End If
    End If
 End Sub

 [VbNo]でも終わらせる事も可能でしょうか?
(中途半端) 2014/06/27(金) 04:52

 イベントはこういったところをいろいろと検索で探して読んでみると良いと思いますが、
http://home.att.ne.jp/zeta/gen/excel/c04p30.htm
 AfterUpdate は変更があった場合、Exit は変更の有無に関係なく、といった違いだと思います。

 Unload の挙動はこちらでは再現しないので、他の部分が関係していると思うのですが、
 UserForm はシンプルな1フォームの構成でしょうか。

 Unload フォーム名
 はダメだったということでしょうか?

(Mook) 2014/06/27(金) 09:44


 現象は、確認しました(Excel2010)。

 Excelユーザーフォームって、バグっぽいのが多いんです、本当に!!
 この回避方法はいくつか方法がありそうですが、一例です。

 Private Sub Textbox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    Static stopev As Boolean
    Dim PW As String
    Const Msg = "パスワードが違います" & vbCr & "再入力しますか?"
    If Not stopev Then
       With Txt
          If UCase(.Value) = "HAJIMEMASU" Then
             unload Me
          Else
             If MsgBox(Msg, vbYesNo, "") = vbYes Then
                .Value = ""
                Cancel = True   '追加しました。
             Else
                stopev = True
                unload Me
             End If
          End If
       End With
    Else
       stopev = False
    End If
 End Sub

 ところで・・・。

 拝見したコードを見た限りの推測ですが、提示されたコードは、

 パスワードをユーザーに入力させてその内容をチェックするという機能ですよね?

 これが掲示板用の例題仕様ならよいですが、

 Unloadしてしまったら、パスワード入力が正常になされたのか 失敗して終わったのかわかりませんよね?

( ichinose) 2014/06/27(金) 12:48


 Mookさん ichinoseさん

 このフォームはファイルを開いた時に動作しています。つまり単独フォームです。
 Unload フォーム名・・・も試しましたが同じでした。

 パスワードが合致した時の Unload Me はフォームを即終了します。
 [VbNo]  の時の Unload Me → Application.Quit と変更した所、即座にエクセルを終了します。
         ↑の場合はこのラインへ来た時に再度 Tx_Exit のイベント処理となっています。

 ★只、テキストボックス1個だけでは、Tx_Exitイベントでフォームを閉じるのは
 出来ないのですね。×ボタンでの終了も出来ませんでした。
 何かフォーカスを得る事の出来るコントロールが必要のようです。

 特に支障が無いのですが疑問だけが残りました。 つまらない事に拘ってすみません・・・

 ichinoseさんのご指摘とStopEvの追加は良くわかりました。
 実際に成功した時はファイルを開くし、間違った時のメッセージも出していますが・・・

 有難うございました。

( 中途半端) 2014/06/27(金) 13:24


 >実際に成功した時はファイルを開くし、間違った時のメッセージも出していますが
 とうことは、

 >Private Sub Textbox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
 >   Static stopev As Boolean
 >   Dim PW As String
 >   Const Msg = "パスワードが違います" & vbCr & "再入力しますか?"
 >   If Not stopev Then
 >      With Txt
 >         If UCase(.Value) = "HAJIMEMASU" Then
             'ここでそのファイルを開くという処理を行っているのですよね?
 >            unload Me
 >         Else
 >            If MsgBox(Msg, vbYesNo, "") = vbYes Then
 >               .Value = ""
 >               Cancel = True   '追加しました。
 >            Else
 >               stopev = True
 >               unload Me
 >            End If
 >         End If
 >      End With
 >   Else
 >      stopev = False
 >   End If
 >End Sub

 パスワードを入力させるという機能って よく使いそうな機能ですよね?

 この機能を汎用的に作っておけば、次回に同じような事がしたい場合は、そのプログラムを
 呼び出せばよいだけにしておきたいと 思いませんか?
 汎用的に使えるようにするためには、ユーザーフォームの中でパスワードが正しく入力された
 時の後の処理(ここでは、ファイルを開くという処理)をしてしまうと次回に同じことをするときに
 又、その処理用にユーザーフォームを書き換えなければなりません。
 私たちがExcel/VBAで使用しているオブジェクトと呼ばれるプログラムを作るための部品は、
 処理に応じて、中のプログラムを作り直さなければならない なんてことはないですよね。

 そのオブジェクトの持つプロパティやメソッドを使うことで、汎用的に活用できますよね!!
 ユーザーフォームもオブジェクトです。プロパティやメソッドをうまく使えば、汎用性を高めることが出来ます。

 新規ブックにて、ユーザーフォームを作成してください(UserForm1)。

 コントロールは、テキストボックスを一つだけ配置してください(TextBox1)。

 UserForm1及び、TextBox1の大きさや位置は、コードで調整しますから、初期配置は、適当でよいです。

 このUserForm1は、パスワードの入力を促し、これを予め設定されているパスワードと比較し、
 正しいか否かを判断します。

 プロパティ

    InitMes    テキストボックスに初期表示するメッセージを登録します。
    PassWord   比較するパスワードを登録します。
    Result   設定されたパスワードと入力された文字列を比較し、結果を返します。
               True パスワードと一致した 
               False パスワードと一致しない又は、閉じるボタンが押された

 メソッド
    show       パスワードチェックダイアログを表示し、パスワードチェックを行います。

 このUserForm1は、上記のインターフェースで操作します。

 ではコードです。

 UserForm1のモジュール

 '====================================================================
 Option Explicit
 Private imes As String
 Private psw As String
 Private Judgment As Boolean
 Private stopev As Boolean
 '==================================================================== 
 Property Let InitMes(mes As Variant)
    imes = mes
 End Property
 '====================================================================
 Property Let PassWord(mes As Variant)
    psw = mes
 End Property
 '====================================================================
 Property Get Result() As Boolean
    Result = Judgment
 End Property
 '====================================================================
 Private Sub TextBox1_Change()
    If Not stopev Then
       With TextBox1
          If .Value = "" Then
             stopev = True
             .PasswordChar = ""
             .Value = imes
             .SelStart = 0
             .SelLength = Len(.Value)
             stopev = False
             .setfocus
          Else
             .PasswordChar = "*"
          End If
       End With
    End If
 End Sub
 '==================================================================== 
 Private Sub UserForm_Activate()
    With TextBox1
       stopev = True
       .Value = imes
       stopev = False
       .SelStart = 0
       .SelLength = Len(.Value)
       .setfocus
    End With
 End Sub
 '====================================================================
 Private Sub UserForm_Initialize()
    With Me
       .Width = 280
       .Height = 108
       With .TextBox1
          .Left = 54
          .Top = 30
          .Width = 156
          .Height = 24
          .PasswordChar = ""
          .Font.Size = 14
       End With
    End With
    Judgment = False
 End Sub
 '====================================================================
 Private Sub textbox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    Dim PW As String
    Const Msg = "パスワードが違います" & vbCr & "再入力しますか?"
    If KeyCode = vbKeyReturn Then
       With TextBox1
          If UCase(.Value) = UCase(psw) Then
             Judgment = True
             Me.Hide
          Else
             If MsgBox(Msg, vbYesNo, "") = vbYes Then
                .Value = ""
                KeyCode = 0
             Else
                Judgment = False
                Me.Hide
             End If
          End If
       End With
    Else
       TextBox1.PasswordChar = "*"
    End If
 End Sub
 '====================================================================
 Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = 0 Then
       Judgment = False
       Cancel = True
       Me.Hide
    End If
 End Sub

 標準モジュールに

 '===========================================================================
 Sub test()
    With UserForm1
       .InitMes = "パスワード"  '初期表示文字列の登録
       .PassWord = "ichinose"   'パスワードの登録
       .Show                    'UserForm1の表示
       If .Result Then          '入力文字列がパスワードと一致
          MsgBox "ok"           'ここでファイルを開く処理
       Else                     '閉じるボタンが押されたか パスワードと不一致
          MsgBox "パスワードは、認識できません"
       End If
    End With
    unload UserForm1
 End Sub
 

 testを実行してみてください、ダイアログが表示されますから、パスワード ichinose を入力したり
 間違った文字列を入力して試してください。入力確定は、Enterキーです。

 入力文字列は、*でマスクされます。

 このように作成しておくと、UserForm1は、入力文字列チェック用に他の場面でも使えますよね!!
 バグがない限りは・・・。

 又、UserForm1は、文字列をチェックするという機能だけを考慮して、機能拡張を考えることも
 この機能として独立しているのですから、考えがまとまりやすいと思いますよ!!

( ichinose) 2014/06/27(金) 21:09


ichinoseさん、大変遅くなってすみません。
 先月27日の自分の投稿が最後と思っていたのと、病気で入院していた事でこちらを見ていませんでした。

 ichinoseさんのコードを見て感激しました。スラスラと書かれていて私にはとっても出来無い事です。
 私の質問でテキストボックスの入力間違いが有った場合、同じテキストボックスに戻る方法について
 (1)[AfterUpdate]では[Cancel]の引数がないので再度のフォーカス取得は出来ないのでしょうか?
    可能であるならばご指導ください。

 (2)このサンプルの様に[textbox1_Change][textbox1_KeyDown] の2つイベント処理をすれば出来るのでは? 
    これから試したいと思います。

( 中途半端) 2014/07/18(金) 12:33


 >[AfterUpdate]では[Cancel]の引数がないので再度のフォーカス取得は出来ないのでしょうか?

 既投稿のTextbox1_Exitイベントと同じような動作なら・・・、

 ユーザーフォームのモジュールに

 Option Explicit
 Private Sub TextBox1_AfterUpdate()
    Const Msg = "パスワードが違います" & vbCr & "再入力しますか?"
    With TextBox1
       If UCase(.Value) = "HAJIMEMASU" Then
          Me.Hide
       Else
          If MsgBox(Msg, vbYesNo, "") = vbYes Then
             .Value = ""
             Application.OnTime Now(), "'ctrl_SetFocus """ & Me.Name & """,""TextBox1""'"
          Else
             Me.Hide
          End If
       End If
    End With
 End Sub

 標準モジュールに

 Sub test()
    UserForm1.Show
    Unload UserForm1
 End Sub
 '=============================================================================
 Sub ctrl_SetFocus(ByVal frmnm As String, ByVal ctrlnm As String)
    Dim frm As Object
    For Each frm In UserForms
       If UCase(frm.Name) = UCase(frmnm) Then
          frm.Controls(ctrlnm).SetFocus
          Exit For
       End If
    Next
 End Sub

 

 これでtestを実行してみてください。

 >このサンプルの様に[textbox1_Change][textbox1_KeyDown] の2つイベント処理をすれば出来る
 ExitイベントやAfterUpdateイベントでは、中途半端さんが記述されたように

 >★只、テキストボックス1個だけでは、Tx_Exitイベントでフォームを閉じるのは
 >出来ないのですね。×ボタンでの終了も出来ませんでした。
 >何かフォーカスを得る事の出来るコントロールが必要のようです。

 という事になってしまいます。よって、テキストボックスの他にフォーカスを持つコントロールが
 ない場合の事例として、投稿したのがKeydownイベントを使ったコードです。

 この場合、データのチェックやテキストボックスに再入力を促すコードは、すべてKeydownイベントが行っています。Changeイベントは、テキストボックスの初期表示文字列の始末をしているだけです。

 確認してみてください

(ichinose) 2014/07/23(水) 00:29


 KeyDownイベントの事例が難しすぎたかもしれません。
 もうちょっと、仕様を簡単にしました。

 >新規ブックにて、ユーザーフォームを作成してください(UserForm1)。
 >コントロールは、テキストボックスを一つだけ配置してください(TextBox1)。
 >UserForm1及び、TextBox1の大きさや位置は、コードで調整しますから、初期配置は、適当でよいです。
 >このUserForm1は、パスワードの入力を促し、これを予め設定されているパスワードと比較し、
 >正しいか否かを判断します。
 >プロパティ
    InitMes    UserForm1の左上に表示するメッセージを登録します。
    >PassWord   比較するパスワードを登録します。
    >Result   設定されたパスワードと入力された文字列を比較し、結果を返します。
               True パスワードと一致した 
               False パスワードと一致しない又は、閉じるボタンが押された
 >メソッド
    >show       パスワードチェックダイアログを表示し、パスワードチェックを行います。
 >このUserForm1は、上記のインターフェースで操作します。

 というようにInitMesというプロパティの機能をちょっとかえるだけで少し簡単になり、
 KeyDownイベントの役割が見えてきます。

 UserForm1のモジュールに

 Private psw As String
 Private Judgment As Boolean
 Private stopev As Boolean
 '====================================================================
 Property Let InitMes(mes As Variant)
    Me.Caption = mes
 End Property
 '====================================================================
 Property Let PassWord(mes As Variant)
    psw = mes
 End Property
 '====================================================================
 Property Get Result() As Boolean
    Result = Judgment
 End Property
 '====================================================================
 Private Sub UserForm_Initialize()
    With Me
       .Width = 280
       .Height = 108
       With .TextBox1
          .Left = 54
          .Top = 30
          .Width = 156
          .Height = 24
          .PasswordChar = "*"
          .Font.Size = 14
       End With
    End With
    Judgment = False
 End Sub
 '====================================================================
 Private Sub textbox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    Dim PW As String
    Const Msg = "パスワードが違います" & vbCr & "再入力しますか?"
    If KeyCode = vbKeyReturn Then
       With TextBox1
          If UCase(.Value) = UCase(psw) Then
             Judgment = True
             Me.Hide
          Else
             If MsgBox(Msg, vbYesNo, "") = vbYes Then
                .Value = ""
                KeyCode = 0
             Else
                Judgment = False
                Me.Hide
             End If
          End If
       End With
    End If
 End Sub
 '====================================================================
 Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = 0 Then
       Judgment = False
       Cancel = True
       Me.Hide
    End If
 End Sub

 標準モジュールに
 '===========================================================================
 Sub test()
    With UserForm1
       .InitMes = "パスワード"  '初期表示文字列の登録
       .PassWord = "ichinose"   'パスワードの登録
       .Show                    'UserForm1の表示
       If .Result Then          '入力文字列がパスワードと一致
          MsgBox "ok"           'ここでファイルを開く処理
       Else                     '閉じるボタンが押されたか パスワードと不一致
          MsgBox "パスワードは、認識できません"
       End If
    End With
    unload UserForm1
 End Sub

 以上です。testを実行してみてください。
(ichinose) 2014/07/23(水) 06:21

コメント返信:

[ 一覧(最新更新順) ]


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