- PR -

スレッドからタイマーを起動したんですが・・・

投稿者投稿内容
FX
常連さん
会議室デビュー日: 2004/12/06
投稿数: 49
投稿日時: 2005-10-26 09:44
フォームに貼り付けてあるタイマーイベントを0秒時に1分間隔ちょうどに取りたいので、タイマーを起動するスレッドを作り時間調整を行ってからタイマーのEnableをTrueにしているんですが、イベントが発生しません。
デバッグで以下の行が実行されている事は確認しています。
Timer1.Enabled = True
また、プロパティであらかじめEnabledをTrueにするとイベントは発生します。
スレッドから起動するには何か問題があるのでしょうか?
また、別方法でタイマーイベントを0秒ちょうど(0.1秒程度の誤差はOK)に
発生させる何か良い方法はありますでしょうか?
よろしくおねがいします。

Private Sub StartTimer()
While Now.Second = 0

End While

Timer1.Enabled = True

End Sub

環境 VisualStudio.net2003
言語 VB.NET
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2005-10-26 10:25
これかなぁ
http://www.atmarkit.co.jp/fdotnet/dotnettips/312ctrlinvoke/ctrlinvoke.html

Invoke()メソッドを使うんですね。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-10-26 10:35
ついでに、「スレッド セーフ」とは何であるかも調べておくと良いでしょう。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
FX
常連さん
会議室デビュー日: 2004/12/06
投稿数: 49
投稿日時: 2005-10-26 11:21
一郎さん、じゃんぬねっとさん
レスありがとうございます。
一郎さんに教えていただいた記事を参考にして実行する事ができました。
しかし、ループしている間処理が戻って来ないようです。フォーム上にカーソルを
乗せると砂時計になったままです。タイトルバーにマウスを乗せてウインドウは移動
出来たりするので完全に戻って来ないわけではないようなのですが・・・
ロジックを少し変えて、現在秒を取得して0秒以外の時は60から取得した秒数をマイナスした数をSystem.Threading.Thread.Sleep()で待たせてから、タイマーを起動する
方法を取ってみましたが、やはりスリープしている間はメイン処理も止まってしまって
いるようです。
これではスレッドにした意味がありません。
何かやり方が悪いのでしょうか?

Private Delegate Sub StartTimerDelegate()
Private StartTimerThread As Threading.Thread

'タイマーの起動
StartTimerThread = New Threading.Thread(AddressOf StartTimerWorker)
StartTimerThread.Start()

Private Sub StartTimerWorker()
Invoke(New StartTimerDelegate(AddressOf StartTimer))
End Sub

Private Sub StartTimer()

Do Until Now.Second = 0
Loop

Timer1.Enabled = True
End Sub

Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2005-10-26 12:59
こんにちは。

次の2つの方法はどうですか?

【コード1】
コード:

Private Sub StartTimer()

Do Until Now.Second = 0
Application.DoEvents() ' (*1)
Loop

Timer1.Enabled = True
End Sub



ループ中にApplication.DoEvents()を呼んで、UIスレッドのメッセージポンプを行う。
ただし、この方法だとワーカースレッドを作った意味がないように思います。

【コード2】
コード:

Private Sub StartTimerWorker()

Do Until Now.Second = 0
Loop

Invoke(New StartTimerDelegate(AddressOf StartTimer))
End Sub

Private Sub StartTimer()

Timer1.Enabled = True
End Sub



メインスレッド(UIスレッド)で0秒時を待つのではなく、
ワーカースレッドで0秒時を待ち、それからタイマーを起動させます。

※どのメソッドがどのスレッドで実行されているか、正しく把握しておくことが大事です。

どうでしょうか?

[ メッセージ編集済み 編集者: Tdnr_Sym 編集日時 2005-10-26 13:08 ]
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2005-10-26 14:32
Sleepさせておいてもメインのスレッドの方は動いているみたいですけど。
テキストボックスとか触れましたよ。
カーソルを砂時計にしているのは、自分でしているんですよね?
勝手に砂時計にはならないと思いますけど。

ちなみにこんなコードです。
コード:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    th = New Thread(AddressOf f)
    th.Start()
End Sub

Private Sub f()
    Dim now As DateTime = DateTime.Now
    Dim mSec As Integer
    mSec = 60000 - (now.Second * 1000 + now.Millisecond)
    Thread.Sleep(mSec)
    Me.Invoke(New Del(AddressOf g))
End Sub

Private Sub g()
    Timer1.Start()
End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    Label1.Text = DateTime.Now.ToString()
End Sub

FX
常連さん
会議室デビュー日: 2004/12/06
投稿数: 49
投稿日時: 2005-10-26 14:41
Tdnr_Symさん、レスありがとうございます。
コード1、コード2ともためさせていただきました。
コード2の方で思い通りの動きになりました、ループ処理がどのスレッドで実行されているのかが、ごっちゃになっていました。
大変助かりました。ありがとうございました。
FX
常連さん
会議室デビュー日: 2004/12/06
投稿数: 49
投稿日時: 2005-10-26 14:43
一郎さん、レスありあがとうございます。

>カーソルを砂時計にしているのは、自分でしているんですよね?
いいえ、これはシステムでしているようです。私が設定しているのではありません。

先ほどのコードではメインスレッドでループしていたようでしたので、秒が0になるまでメインスレッドがループしていたようです。

スキルアップ/キャリアアップ(JOB@IT)