(WinXP、VB.NET2003)
いつも初心者衆(私も)がお世話になっております。
先日Label上で文字列が流れる(マーキー風?)処理を作ってみました。
# 仕事の合間ができたので多少の勉強を兼ねて
# Private WithEvents m_timer As New Timer と宣言したタイマーの
# TickイベントでGraphicsオブジェクトを操作(DrawString)する程度の
# ものなんですが・・・
そこで質問ですが、
例えば上記の処理で"しばらくお待ち下さい"のような文字を流しつつ
その裏でなんらかの処理(集計ループとか)ができないかと考えたのですが
単純にButton1_Clickで
m_timer.Start()
Call 処理メソッド
'm_timer.Stop()
ですと、思惑通りの動作にはなりませんでした。
# Call処理が終わるまで文字が流れない?感じです。
このような場合なにをキーワードにどういった事を
ヘルプ等で調べれば良いのかも思いつかず
どんな感じで質問すればよいかも悩みまして
タイトルも含めて文章がヒドイとは思いますが
なにかこう手法とゆうか助言頂ければ幸いです。
「vb.net マルチスレッド 処理の進行状況」などでググル。
返信ありがとうございます。
助言を参考に自分なりにWEB検索等で調査してみたところ
UpdateメソッドやApplication.DoEventsメソッドによる
コントロールの再描画では無理のようでした(たぶん)
そうなるとご指摘の通り別スレッドで処理ということに
なるんだとは思いましたが、例えばデリゲートとか今の
私にはまだ難しいキーワードも出てきてハードルが高そうです・・・
># 仕事の合間ができたので多少の勉強を兼ねて
では全然無理そうなので
きちんと時間が取れる時に勉強しようと思います。
> (WinXP、VB.NET2003)
う〜ん、残念。
VB2005 なら、別スレッドでの処理+デリゲートという複雑(?)な部分を、
単純なイベント処理による「BackgroundWorker クラス」として扱えるので、
比較的簡単に実装できるのですけれどね。
Private Sub Button1_Click(……
BackgroundWorker1.RunWorkerAsync() '時間のかかる処理を非同期で開始
End Sub
Private Sub BackgroundWorker1_DoWork(……
'---------
'時間のかかる処理をここに記述
'---------
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(……
MessageBox.Show("別スレッドの処理が完了しました。")
End Sub
# URL 貼り忘れた……。
VB2005 の BackgroundWorker クラスによる実装例と、
VB.NET 2003 の Thread クラスによる実装例です。
もっとも、すでにご覧になっているかも知れませんけれども。(^^;
http://www.microsoft.com/japan/msdn/vbasic/migration/tips/BackgroundWorker/
魔界の仮面弁士さん、回答ありがとうございます。
># URL 貼り忘れた……。
を参考に、まったくの見よう見まねですが
以下のコードでそれっぽく動いてくれてるみたいです。
Private WithEvents m_timer As New Timer
Private m_left As Integer
'
Private Delegate Sub TimerProcessDelegate()
Private m_thread As System.Threading.Thread
' 実行Button
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
m_left = Me.Label1.Width
m_timer.Interval = 5
' 別スレッド…?
m_thread = New System.Threading.Thread(AddressOf doWork)
m_thread.Start()
End Sub
' タイマー
Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles m_timer.Tick
' マーキー?処理
Dim g As Graphics = Me.Label1.CreateGraphics()
Dim siz As SizeF = g.MeasureString(Me.Label1.Text, Me.Label1.Font)
g.Clear(Me.Label1.BackColor)
g.DrawString(Me.Label1.Text, Me.Label1.Font, New SolidBrush(Me.Label1.ForeColor), m_left, 4)
m_left -= 1
If m_left < CInt(siz.Width) * -1 Then
m_left = Me.Label1.Width
End If
g.Dispose()
End Sub
' 別スレッド処理…?
Private Sub doWork()
Me.Invoke(New TimerProcessDelegate(AddressOf TimerStart))
'
For i As Integer = 0 To 50000
' テストループ(実際は処理を記述)
Me.Label2.Text = i.ToString
Next
'
Me.Invoke(New TimerProcessDelegate(AddressOf TimerStop))
End Sub
Private Sub TimerStart()
Me.Button1.Enabled = False
m_timer.Start()
End Sub
Private Sub TimerStop()
Me.Button1.Enabled = True
m_timer.Stop()
End Sub
結局、Delegate・Invoke・AddressOfなど
ほとんど打ったことのないキーワードに
ついては相変わらず意味不明ですが^^;
# 徐々に理解できればと・・
とりあえず解決チェック付けますが、まだまだ勉強不足ですので
お気づきの点などあれば、ご指摘お願いします。
>とりあえず解決チェック付けますが、
付けてないし・・すいませんでした。
>Me.Label2.Text = i.ToString
メインスレッドから操作していないのでこれはダメでしょう。
Private Delegate Sub SetTextDelegate(ByVal objText As Object, _
ByVal strText As String)
Private Sub SetText(ByVal objText As Object, _
ByVal strText As String)
DirectCast(objText, Label).Text = strText
End Sub
For i As Integer = 0 To 50000
' テストループ(実際は処理を記述)
Try
Me.Invoke(New SetTextDelegate(AddressOf SetLabelText), _
Me.Label2, i.ToString)
Application.DoEvents()
Catch
MsgBox("操作が取り消されました")
Return
End Try
Next
こんなことするのかな。
我龍院さん、再度返信ありがとうございます。
>メインスレッドから操作していないので
なるほど。かなりぼんやりとですが
今回自分がやろうとしてる事(マルチスレッド?)についての
意味や手法など徐々に理解していけそうな予感がしてきました。
>こんなことするのかな。
(現在の処理件数というか)こんな感じです^^
サンプルありがとうございます。とても参考になります。
タイマー部分は大丈夫そう(?)なので、テスト用ではなく
実際のソースにうまく組み込めるよう更に勉強致します。
ありがとうございました。
ツイート | ![]() |