関数からイベントを動かす

タグの編集
投稿者 かつ  (社会人) 投稿日時 2018/7/9 17:49:08
下記
①関数の※AのCall txtGPIBSend_KeyPress(sender, e) で    
②テキストボックスのイベントを動かしたいです。
 ※Aの(sender, e)の引数をどう記述すればいいのかよくわかりません。

②テキストボックスイベントは e As KeyPressEventArgs となっていますが、
このeの引数をきちんと指示すれべ動きそうで、いろいろ調べましたが、
KeyPressEventArgsの意味がよくわかりません。
.NETはまだまだわからない所が多くすみませんが、どなた様かご教授頂けませんでしょうか。


①関数
    Public Function GPIBSEND(PORTNO As String, Command As String) As Boolean
        GPIBSEND = False
        Dim sender As Object = Command
        Dim e As KeyPressEventArgs()
        Select Case PORTNO
            Case "SLAVE1" : cmbGPIB.SelectedIndex() = 0
            Case "SLAVE2" : cmbGPIB.SelectedIndex() = 1
            Case "SLAVE3" : cmbGPIB.SelectedIndex() = 2
            Case "SLAVE4" : cmbGPIB.SelectedIndex() = 3
        End Select
        Me.txtGPIBSend.Text = Command
        Call txtGPIBSend_KeyPress(sender, e) ・・・※A
        If Items(Sq, ceWait1) <> "" Then Call WaitTime(CLng(Items(Sq, ceWait1)))
        Call WaitTime(CLng(Items(Sq, ceWait2)))
        GPIBSEND = True
    End Function

②テキストボックスイベント
    Private Sub txtGPIBSend_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtGPIBSend.KeyPress
        'Enterキーが押された事を取得()
        If e.KeyChar = Chr(Keys.Enter) Then
            sender0706 = sender
            e0706 = e
            e.Handled = True    'KeyPress イベントをキャンセル(Beep音を消音に)
            f.txtSend.Text = txtGPIBSend.Text
            Call f.cmdSend_Click(txtGPIBSend, e)
            txtGPIBSend.Focus()
        End If
    End Sub

投稿者 魔界の仮面弁士  (社会人) 投稿日時 2018/7/9 23:40:08
> ①関数の※AのCall txtGPIBSend_KeyPress(sender, e) で    
> ②テキストボックスのイベントを動かしたいです。
>  ※Aの(sender, e)の引数をどう記述すればいいのかよくわかりません。

そういう書き方をするべきではありません。
イベントの使い方がいろいろと間違っていますよ。


イベントハンドラである Sub txtGPIBSend_KeyPress は、原則として
「Handles txtGPIBSend.KeyPress」によって呼び出されるためのものです。

すなわち、txtGPIBSend と名付けられた TextBox の KeyPress イベントによって、
『呼び出される』ものであって、本来は『呼び出す』ものではないということです。
※ この点は VB6 であっても同様。




同様の理由で、「Call f.cmdSend_Click(txtGPIBSend, e)」のような呼び出しも NG です。
cmdSend_Click などといった「イベントハンドラ」は、本来、
何かの操作に基づいて発生する「イベント」を通じて呼び出されるものであり、
プログラムから意図的に呼び出すのは、あまり行儀の良いコードではありません。

Button がクリックされたり、Button の PerformClick メソッドが呼ばれると
その Button の Click イベントが呼ばれます。でも、自分で Call Button1_Click(…) などとはしない。

TextBox の Text が変化すると、その TextBox の TextChanged イベントが呼ばれます。
でも、自分で Call TextBox1_TextChanged(…) などとはしない。

Form が右上の × ボタンなどで閉じられると、その Form の FormClosing イベントが呼ばれます。
でも、自分で Call Form1_FormClosing(…) などとはしない。


ではどうするとかと言えば、たとえば、「txtGPIBSend 上で Enter が押されたときの処理」を
GPIBSEND の中から呼び出したいのであれば、こんな感じで処理します。

Private Sub txtGPIBSend_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtGPIBSend.KeyPress
    'Enterキーが押された事を取得 
    If e.KeyChar = ChrW(Keys.Enter) Then
        e.Handled = True

        '別途用意したプロシージャーを呼び出します 
        YourProcedure()
    End If
End Sub

Private Sub YourProcedure()
    '★ここに「Enter が押されたときに行いたい処理」を記述します★ 
End Sub

'これって Function ではなく Sub で良いのでは? 
Public Function GPIBSEND(PORTNO As String, Command As StringAs Boolean
    'こういう時は Case 分岐よりも、Dictionary を使った方がスマートかも 
    Select Case PORTNO
        Case "SLAVE1" : cmbGPIB.SelectedIndex = 0
        Case "SLAVE2" : cmbGPIB.SelectedIndex = 1
        Case "SLAVE3" : cmbGPIB.SelectedIndex = 2
        Case "SLAVE4" : cmbGPIB.SelectedIndex = 3
    End Select
    Me.txtGPIBSend.Text = Command

    '★これが今回の主題★ 
    '下記のように呼べなくも無いですが、そのようにはせず 
    'Call txtGPIBSend_KeyPress(txtGPIBSend, New KeyPressEventArgs(ChrW(Keys.Enter))) 
    
    'このように、別途用意したプロシージャーを呼び出すようにします。 
    YourProcedure()

    If Items(Sq, ceWait1) <> "" Then
        WaitTime(CLng(Items(Sq, ceWait1)))
    End If
    WaitTime(CLng(Items(Sq, ceWait2)))
    Return True
End Function



> KeyPressEventArgsの意味がよくわかりません。

イベントは基本的に、引数として「sender As Object」と「e As EventArgs」の 2 つを取ります。
イベントによっては、後者が「e As [EventArgsを継承したクラス]」になります。


イベント引数 sender は、「そのイベントの発生元となるオブジェクト」を指します。
たとえばこういう使い方をします。

'TextBox1~3の TextChanged イベントに、下記のイベントハンドラが割り当てられている 
Private Sub TextBoxes_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged, TextBox2.TextChanged, TextBox3.TextChanged
    '引数 sender は、TextBox1/TextBox2/TextBox3 のいずれかが渡される 
    If sender.Text = "" Then
        'テキストが空になったら、背景を黄色にする 
        sender.Backcolor = Color.Yellow
    Else
        'テキストが空でなくなれば、背景色をリセットする 
        sender.ResetBackColor()
    End If
End Sub



イベント引数 e は、「そのイベントにとって必要な情報」を指します。
KeyPress イベントなら「入力された文字」を表す KeyPressEventArgs が渡され
MouseDown イベントなら「マウスの座標や押されたボタン」を表す MouseEventArgs が
渡されます。特に特筆すべき情報が無い場合には、EventArgs.Empty が渡されます。

たとえば Button1 の Click イベントなどでは、フォーカス遷移後に
キーボードのスペースキーで押されたときは、e は EventArgs.Empty ですが、
マウス操作で押されたときは、e に MouseEventArgs が渡されていたりします。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    If TypeOf e Is MouseEventArgs Then
        Dim e2 As MouseEventArgs = DirectCast(e, MouseEventArgs)
        MsgBox("マウス操作で呼ばれた:座標=" & e2.Location.ToString())
    ElseIf e Is EventArgs.Empty Then
        MsgBox("マウス操作以外で呼ばれた")
    End If
End Sub
投稿者 かつ  (社会人) 投稿日時 2018/7/11 15:27:52
魔界の仮面弁士様


イベントハンドラは、本来、 何かの操作に基づいて発生する「イベント」を通じて呼び出されるものであり、プログラムから意図的に呼び出すのものではないという事で認識しました。

イベントからイベントを呼び出す事ができたので、
関数からイベントを呼び出したかったのですがYourProcedure()を別につくる事で動作する事ができました。

VB中学校様の初級講座の第10回 イベントプロシージャの6.自分で呼び出す
でできましたので、可能かと思い質問しました。

前回同様に回答頂きありがとうございました。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2018/7/12 16:14:33
> VB中学校様の初級講座の第10回 イベントプロシージャの6.自分で呼び出す
> でできましたので、可能かと思い質問しました。

はい。もちろんそれも可能です。
先ほどのコードでいうと、下記の部分にあたりますね。
'Call txtGPIBSend_KeyPress(txtGPIBSend, New KeyPressEventArgs(ChrW(Keys.Enter)))  


ただしこういう方法は、あまり行儀の良い書き方ではない、というだけのことです。
イベントハンドラーは、「呼び出すものではなく、呼び出されるもの」なので。


> Call f.cmdSend_Click(txtGPIBSend, e)
これも先の YourProcedure 法と同様ですね。
変数 f が示すフォームに Public Sub (あるいは Friend Sub)な
公開メソッドを用意して、それを cmdSend_Click から呼ぶように設計してみてください。

そうすれば、GPIBSEND / txtGPIBSend_KeyPress からも、
その公開メソッドを通じて処理が呼び出せるようになるはずです。


なお、初級講座第10回の『6.自分で呼び出す』のところでは、
Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click
    Call Button2_Click(Button1, e)
End Sub
と言うサンプルが掲載されていますが、このような場合は、下記のようにした方が良いでしょう。
Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click
    Button2.PerfomeClick()   'これにより、Button2 の Click イベントが発生します 
End Sub


後者の方法であれば、Buton2 の Click イベントが割り当てられている先が、
通常の Sub Button2_Click ではなく、リスト8で示された Sub MyClick に
変更されていたとしても、正しく呼び出すことができます。


また、『6.自分で呼び出す』の例では、Button2_Click の sender に
Button1 や Nothing が渡されているのですが、本来の sender の役目から言えば
ここは通常、Button2 が渡されることが期待されるものですから、
やはり適切な呼び出し方とは言えません。

PerfomeClick メソッド経由で Click イベントを呼び出すようにすれば、
sender や e も適切な値が渡されるようになります。


もちろん直接呼出しであれば、sender に対して意図的に、
別のコントロールを渡したり、Nothing を渡したりといったことも行えてしまうわけですが、
そういう実装にしてしまうと、何故、あえて本来とは異なる値を引数に渡すのか、
処理の「意図」が分かりにくくなってしまいます。

どうしても直接呼び出したいのであれば、上記を十分に理解したうえで行うようにしましょう。