none
スレッドからフォームのテキストボックスに文字を追加したい RRS feed

  • 質問

  • フォームを作りフォームロードの処理に

    Dim Timer = New System.Timers.Timer()

    で時間で動くようにしました。

    呼ばれる関数は別のクラスファイルに書いてあります。

     

    フォーム内に作ったタイマーで実行する関数

    Private Sub OnTimedEvent(source As Object, e As ElapsedEventArgs)

    の場合フォームのテキストボックスに文字を出力する関数は

    Dim dlg As New WriteLineDelegate(AddressOf WriteLine)

    Me.BeginInvoke(dlg, New Object() {"実行" & Now.ToString("mm:ss") & vbNewLine})

    と書くことでデリゲートした関数

        Public Function WriteLine(ByVal str As String) As Integer

            txtMessage.AppendText(str)

            Return txtMessage.Lines.Length

        End Function

    をよぶことで実現できました。

    OnTimedEventからコールされた別のクラスファイルからテキストボックスに文字を出力する方法がわかりません。

    クラスファイルの関数からBeginInvokeを実行しようとすると

    ウィンドウ ハンドルが作成される前、コントロールで invoke または begininvoke を呼び出せません。

    が発生します。

    クラスファイルの関数の引数にこのフォームを入れると実行できました。

    フォームを渡さないと実現できないのでしょうか。

     


    2011年7月27日 1:03

回答

  • 外池と申します。

    ご質問の肝心なところが、具体的に何をされたのかが、よくわかりません。「クラスファイルの関数からBeginInvokeを実行」の部分ですが、フォームの参照を渡した上で、BeginInvokeしているんですよね? BeginInvokeが単独で現われることは無いと思うのですが。

    まず、確認まで。

    なお、BeginInvokeの前に、Meがついていますよね? このMeは、テキストボックスが載っているFormですよね? (あるいは、TextBoxへの参照であるtxtMessageをつかって、txtMessage.BeginInvokeでも良いですが。) で、BeginInvokeが意味するところは、Formやその上に載っているTextBoxを動作させているスレッド(メッセージポンプが動いているスレッド)で、かくかくしかじかのメソッドを実行してください、とお願いしているわけです。なので、そのFormが動き始めた(メッセージポンプが動き始めた、ウィンドウハンドルが作成された)後じゃないと、BeginInvokeは使えません。

    ところで・・・、「System.Timers.Timer」をあえて使われる理由はなんでしょうか? この類のスレッドをまたいだ煩雑な操作を避けるために、「System.Windows.Forms.Timer」がわざわざ用意されているわけで・・・。後者を使えば悩まなくて良いかと。

    Formが動き始める前から、Timerを動かしたい理由があるんでしょうね・・・、たぶん。


    (ホームページを再開しました)
    • 回答としてマーク 山本春海 2011年9月2日 5:30
    2011年7月27日 2:15
  • クラスファイルの関数の引数にこのフォームを入れると実行できました。
    フォームを渡さないと実現できないのでしょうか。

     そうです。

     引数にフォームを渡さない場合は、どの様に実現しようとしていたのでしょうか。VB は、オブジェクト指向言語です。オブジェクト指向言語では、操作の対象となるオブジェクトを指定します。「フォームを渡す」というのは、そういうことです。ただ、VB の場合は、暗黙のインスタンスを使うことも出来ます。お勧めしませんが。


    外池さん:
     System.Timers.Timer が使われているのは、ここで私がそれを使ったためかも。


    Jitta@わんくま同盟
    • 回答としてマーク 山本春海 2011年9月2日 5:30
    2011年7月27日 12:08
  • SynchronizationContextとかAsyncOperationManagerとかそういうのを使えば別にできないことはないでしょう。

     

    • 回答としてマーク 山本春海 2011年9月2日 5:30
    2011年7月27日 17:30

すべての返信

  • 外池と申します。

    ご質問の肝心なところが、具体的に何をされたのかが、よくわかりません。「クラスファイルの関数からBeginInvokeを実行」の部分ですが、フォームの参照を渡した上で、BeginInvokeしているんですよね? BeginInvokeが単独で現われることは無いと思うのですが。

    まず、確認まで。

    なお、BeginInvokeの前に、Meがついていますよね? このMeは、テキストボックスが載っているFormですよね? (あるいは、TextBoxへの参照であるtxtMessageをつかって、txtMessage.BeginInvokeでも良いですが。) で、BeginInvokeが意味するところは、Formやその上に載っているTextBoxを動作させているスレッド(メッセージポンプが動いているスレッド)で、かくかくしかじかのメソッドを実行してください、とお願いしているわけです。なので、そのFormが動き始めた(メッセージポンプが動き始めた、ウィンドウハンドルが作成された)後じゃないと、BeginInvokeは使えません。

    ところで・・・、「System.Timers.Timer」をあえて使われる理由はなんでしょうか? この類のスレッドをまたいだ煩雑な操作を避けるために、「System.Windows.Forms.Timer」がわざわざ用意されているわけで・・・。後者を使えば悩まなくて良いかと。

    Formが動き始める前から、Timerを動かしたい理由があるんでしょうね・・・、たぶん。


    (ホームページを再開しました)
    • 回答としてマーク 山本春海 2011年9月2日 5:30
    2011年7月27日 2:15
  • クラスファイルの関数の引数にこのフォームを入れると実行できました。
    フォームを渡さないと実現できないのでしょうか。

     そうです。

     引数にフォームを渡さない場合は、どの様に実現しようとしていたのでしょうか。VB は、オブジェクト指向言語です。オブジェクト指向言語では、操作の対象となるオブジェクトを指定します。「フォームを渡す」というのは、そういうことです。ただ、VB の場合は、暗黙のインスタンスを使うことも出来ます。お勧めしませんが。


    外池さん:
     System.Timers.Timer が使われているのは、ここで私がそれを使ったためかも。


    Jitta@わんくま同盟
    • 回答としてマーク 山本春海 2011年9月2日 5:30
    2011年7月27日 12:08
  • SynchronizationContextとかAsyncOperationManagerとかそういうのを使えば別にできないことはないでしょう。

     

    • 回答としてマーク 山本春海 2011年9月2日 5:30
    2011年7月27日 17:30