- PR -

ループ処理で中断・再開するには

投稿者投稿内容
れい
ぬし
会議室デビュー日: 2005/11/01
投稿数: 346
投稿日時: 2008-04-11 22:39
引用:

nakaPさんの書き込み (2008-04-11 18:04) より:
コルーチンという言葉を初めて聞いたので、少し惹かれて作ってみました。



せっかく作ってくれたので、ちょっと直してみました。

コード:

Private Sub StartButton_Click
StartButton.Enabled = False
StopButton.Enabled = True
AddHandler Application.Idle, Application_Idle
idx = 0
End Sub

Private Sub EndButton_Click
StartButton.Enabled = True
StopButton.Enabled = False
RemoveHandler Application.Idle, Application_Idle
End Sub

Private idx As Integer
Private Sub LoopMethod()
CountLabel.Text = idx.ToString()
idx += 1
End Sub

Private Sub Application_Idle
LoopMethod()
End Sub



シングルスレッドですし、
キューイングなどは全部Frameworkとシステムがやってくれますから、
細かいことは気にしなくてOKです。

引用:

こういうことなのかな?
確かに、Application.DoEvents()を使うよりも安定しているかも。



「利用できるものは何でも利用する」というスタンスでプログラムをしてますし、
他人にもそう評価されることが多いですが(いい意味でも悪い意味でも。)、
DoEventsは例外です。

私の中ではDoEvents()はとっくにObsoleteです。
VB6の時代からゴミ扱いでした。




[ メッセージ編集済み 編集者: れい 編集日時 2008-04-11 22:43 ]
飛行船
会議室デビュー日: 2008/04/11
投稿数: 7
投稿日時: 2008-04-11 23:18
れいさん、nakaPさん

コルーチンを使った方法のご提案やサンプルコードのご呈示ありがとうございました。

未だコルーチンなるものがよく理解できていませんが、お二人のコードを単体でテストしたところ、どちらも上手く動きました。

ただ、AddHandler Application.Idle, AddressOf Application_Idle
のように、AddressOfを入れないとエラーになりました。


さて、私が行いたい以下の処理

Private Sub Main()

Dim j As Integer
For j = 1 To 100
  フォームの入力項目の自動入力
  ★wait処理
Next

End Sub


この★wait処理のところで、ボタンを押さなくてもwaitに入り、手作業による入力項目の修正処理を行いたいと思います。

そして、その処理が終わったら、「再開ボタン」を押して、次のfor nextから再開処理
をしたいと思います。

そこで、ご呈示いただいたコードを参考に試行錯誤しているのですが、うまくいきません。

例えば、★wait処理のところに、

AddHandler Application.Idle, AddressOf Application_Idle

を記述してみると、waitすることなく、for nextが回ってしまいます。


理解不足で申し訳ございませんが、具体的な方法をご呈示いただければ幸いです。




Azulean
大ベテラン
会議室デビュー日: 2008/01/04
投稿数: 123
お住まい・勤務地: 大阪府
投稿日時: 2008-04-11 23:30
引用:

この★wait処理のところで、ボタンを押さなくてもwaitに入り、手作業による入力項目の修正処理を行いたいと思います。


考え方を変えて下さい。
Windowsのメッセージの処理自体がループなので、その内側でループしている限り、解決できませんよ。

イメージ(あくまでイメージで正確なものではありません!!)
コード:

While True
' メッセージ(イベントの元となるもの)の受信
' メッセージが何かで処理を分岐する
If msg = MsgType.Paint Then
' 画面を更新する
ElseIf msg = MsgType.ButtonClick Then
' ボタンが押された
Button1_Click()
End If
End While



飛行船さんが求めているコードはButton1_Clickの部分でループに入り、そのまま中から出てこない状態です。
これでは次のイベントを起こすためのメッセージを受け取るループに戻れません。
#画面が再描画されず、ボタンが押せる状態にもなりません。


今回の場合、ループするのではなく、ボタンが押されたときに続きの処理をする、結果を表示してイベントを抜ける、ボタンが押されたときに続きの処理をするの繰り返しであるべきです。
-------
追記

ところで、入力処理というのはどんなものなんでしょうか。
Text1.Text = "aaa"みたいにプロパティで設定しているのか、SendKeyみたいに文字入力をシミュレートしているのか。
SendKeyみたいなものなら、Button1をクリックした時点でフォーカスが移動するので、正しく処理されないかもしれませんし。

[ メッセージ編集済み 編集者: Azulean 編集日時 2008-04-11 23:35 ]
nakaP
大ベテラン
会議室デビュー日: 2005/09/27
投稿数: 138
お住まい・勤務地: 高知
投稿日時: 2008-04-12 01:40
引用:

れいさんの書き込み (2008-04-11 22:39) より:

私の中ではDoEvents()はとっくにObsoleteです。
VB6の時代からゴミ扱いでした。



むー、そうなのか。
VB6ではループ処理が長いと画面が固まったように見えるので、多用してました。
まあそんなに複雑なことしてたわけじゃなかったので、たまたま問題なかったのかもしれません。

引用:

飛行船さんの書き込み (2008-04-11 23:18) より:

ただ、AddHandler Application.Idle, AddressOf Application_Idle
のように、AddressOfを入れないとエラーになりました。


ごめんなさい、実際に書いたコードでは付けてたんですが、転写した時にぬかってたようです。

引用:

Private Sub Main()

Dim j As Integer
For j = 1 To 100
  フォームの入力項目の自動入力
  ★wait処理
Next

End Sub


この★wait処理のところで、ボタンを押さなくてもwaitに入り、手作業による入力項目の修正処理を行いたいと思います。

そして、その処理が終わったら、「再開ボタン」を押して、次のfor nextから再開処理
をしたいと思います。

そこで、ご呈示いただいたコードを参考に試行錯誤しているのですが、うまくいきません。

例えば、★wait処理のところに、

AddHandler Application.Idle, AddressOf Application_Idle

を記述してみると、waitすることなく、for nextが回ってしまいます。



少し、コルーチンを勘違いされてるかもしれません。
【Wikipedia】 より
引用:

サブルーチンがエントリーからリターンまでを一つの処理単位とするのに対し、コルーチンはいったん処理を中断した後、続きから処理を再開できる


重要なのは以下の部分です。
引用:

コード:
Private idx As Integer
Private Sub LoopMethod()
    CountLabel.Text = idx.ToString()
    idx += 1
End Sub





なんか、無理にFor〜Nextを使おうとしてません?
飛行船
会議室デビュー日: 2008/04/11
投稿数: 7
投稿日時: 2008-04-12 10:07
Azuleanさん

ご回答ありがとうございます。

>ところで、入力処理というのはどんなものなんでしょうか。
Text1.Text = "aaa"みたいにプロパティで設定しているのか、SendKeyみたいに文字入力をシミュレートしているのか。

Textbox1.textのように、プロパティで設定しています。

今回のご指摘で、メイン部分でfor nextを使わないwaitのやり方がようやくわかってきました。

ありがとうございました。


nakaPさん

ご回答ありがとうございます。

>なんか、無理にFor〜Nextを使おうとしてません?

その通りでした。
クリック処理を上手く使えば、中断〜再開はわりと簡単にできることがわかりました。

また、コプロセスをどういう場合に使えばよいのかもよくわかりました。とても勉強になりました。

ありがとうございました。

れい
ぬし
会議室デビュー日: 2005/11/01
投稿数: 346
投稿日時: 2008-04-12 16:39
引用:

nakaPさんの書き込み (2008-04-12 01:40) より:
引用:

れいさんの書き込み (2008-04-11 22:39) より:

私の中ではDoEvents()はとっくにObsoleteです。
VB6の時代からゴミ扱いでした。



むー、そうなのか。
VB6ではループ処理が長いと画面が固まったように見えるので、多用してました。
まあそんなに複雑なことしてたわけじゃなかったので、たまたま問題なかったのかもしれません。



http://forums.microsoft.com/msdn-ja/showpost.aspx?postid=2381944&siteid=7&sb=0&d=1&at=7&ft=11&tf=0&pageid=0

この辺で暑苦しく語ってしまっていますので、参照ください。


引用:

引用:

飛行船さんの書き込み (2008-04-11 23:18) より:

ただ、AddHandler Application.Idle, AddressOf Application_Idle
のように、AddressOfを入れないとエラーになりました。


ごめんなさい、実際に書いたコードでは付けてたんですが、転写した時にぬかってたようです。



ごめんなさい。実際にはコードを書いていません…。
とりあえず、うまく動いたようでなによりです。

こういったイベントドリブンの作法をきちんと覚えておけば、
信頼性が高く、レスポンスのいいアプリケーションを作れます。

たとえば、こちらも
[イベントハンドラーの中でさらにイベントを起こすと、再帰的に呼び出されてしまう]
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=44288&forum=7&start=16&16
同じような問題です。

与えられたフレームワークをhackして使い倒すのも楽しいですが、
そのまえに作法を覚えたほうが、効率がよいでしょう。
飛行船
会議室デビュー日: 2008/04/11
投稿数: 7
投稿日時: 2008-04-12 18:34
れいさん

>こういったイベントドリブンの作法をきちんと覚えておけば、
信頼性が高く、レスポンスのいいアプリケーションを作れます

本当によくわかりました。

また、DoEventsを使うときの危険性もよくわかりました。他にもDoEventsを使ったプログラムがあり、どうも動作が不安定なところがあったので、見直していこうと思います。

貴重なアドバイスありがとうございました。


テッテさん

マルチスレッドの手法のご紹介ありがとうございます。

これから、ご紹介いただいたURLなどを参考にして、マルチスレッドも勉強していこうと思います。

ありがとうございました。


nakaP
大ベテラン
会議室デビュー日: 2005/09/27
投稿数: 138
お住まい・勤務地: 高知
投稿日時: 2008-04-13 02:41
引用:

れいさんの書き込み (2008-04-12 16:39) より:
http://forums.microsoft.com/msdn-ja/showpost.aspx?postid=2381944&siteid=7&sb=0&d=1&at=7&ft=11&tf=0&pageid=0

この辺で暑苦しく語ってしまっていますので、参照ください。



拝見させていただきました。
少し、自分なりにテストしてみたくなりました。

ただ、私としては完全には捨てきれないでしょうね、特にVB6では。
(未だVB6システムの保守をしてますので・・・)
もちろん危険性は認識させていただきました。

れいさんのおかげで、自分のレベルが少し上がったのをはっきりと確認できました。ありがとうございます。

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