- ベストアンサー
VB6(SP5) 無限ループ
VB6(SP5)で、プログラミングをしております。 コマンドボタンをクリックすると、別のフォームを開く仕様にしております。 下記のプログラミングです。 ブレイクポイントで、テキストボックスにフォーカスが戻る事は、確認しております。 が、再び、同じフォームが開きます。要するに無限ループになってしまって いるのです。しかも、開発マシン(Win2000)では、再現しません。 実際のあるマシン(Win98SE)のみ再現します。(全てではありません) 助言の程、よろしくお願い致します。 Private Sub CB_Code_Click() Form1.iDoF = True Form1.Show Do While Form1.iDoF = True DoEvents Loop Set Form1 = Nothing Form_Activate DoEvents Text1.SetFocus End Sub
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
なるほど、わかりました。 「子画面からの復帰を親画面の特定の位置で待っていて、 でその処理を継続させたい」 ということですね? その場合、考え方をまったく変える必要があります。 つまり「コマンドボタンの処理は子画面を呼び出す関連処理のみ」にするんです。 Private Sub CB_Code_Click() iDoF = True ←これは自画面(親)のoption Explicitで宣言しましょう Form1.Show vbmodal End Sub で、テキストボックスへの処理はアクティベートに条件句をつけて書く、と。 Private Sub Form_Activate If iDoF = True then Text1.SetFocus end if iDoF = False End Sub こんな感じかな。 フォーム2重起動の理由はまた後述します。 これから会議なので(笑)
その他の回答 (5)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
#2です。 >Private Sub CB_Code_Click() >Form1.Show 1 >Text1.SetFocus >End Sub これが動かないということですが、CB_Code_Click()がCB_Codeを押したこと以外で呼ばれているなんてありませんか? Form1で特別なことを何もしていなければこれでOKなはずなんですが。なにか特別な処理を記述していますか? あと、テキストボックスにフォーカスが戻るかの確認方法なのですが、ブレイクポイントをはると、ブレイクしたときにフォーカスがVBに移動してしまうので好ましくありません。 Debug.Printで確認してみてください。 Text1.SetFocusを削除すれば特に問題なく動くのであれば、#4の方の方法でとりあえずは回避できると思われます。 #4、5の方へ Option Explicitは変数の宣言を強制するためのステートメントです。 "Globalセクションで変数を宣言してください"と言いたいのですよね。 暗黙のLoadはメンバ変数を参照するだけでは発生しません。フォームに貼り付けられたコントロールのプロパティ等を参照したりメソッドをコールしたときにフォームの暗黙のLoadが発生します。
お礼
>これが動かないということですが、CB_Code_Click()がCB_Codeを押したこと以外>で呼ばれているなんてありませんか? 確認しましたが、ありませんでした。(^^; ありがとうございました。
- kagep
- ベストアンサー率23% (171/721)
#4に補足です。 iDoFはフォームロード時に必ずfalseにしてください。 これで、コマンドボタン押下で子画面をオープンし、 子画面を閉じたら親画面のtext1テキストボックスにフォーカスがあたるはずです。 で、質問にあるソースでなぜ子フォームが2重起動するかというと、 子画面(Form1)のiDoFにFalseを設定してから、 Form1.showしていますよね。 実は、Form1.iDoF = True を行った時点で Form1は暗黙的にLoadされているのです。 確か暗黙でフォーム呼び出しのデフォルトはVbmodalだったと思うので、 とりあえず子フォーム終了まで親フォームは待機しているのでしょう。 で、親画面復帰後さらにshowを発効しているのでまた新たにForm1のLoadがくる。 これで、Form1が再度開きます。 DoEventsを使用しているので、内部がぐちゃぐちゃになってしまっている、 というオチなんでしょう。 間違えてたらごめんなさい。 あくまでも限られた情報下での推測ということで(^^; とりあえず#4のソース構造で試してみてください。
お礼
何度も、ありがとうございました。
- kagep
- ベストアンサー率23% (171/721)
正解は「“DoEvents”が悪さをしているから」と、 「“Form1”をmodalで開いていないから」ということです。 理由はですね、VBの場合、処理は順番に行われていきます。 ソースを記述した順番に、です。 ソース内で何らかのイベントが発生すればその処理に行き、 そのイベントが終了すれば、またもとのソースの続きの処理が進む、 というのが一般的な流れです。 ところが「DoEvents」はこの流れを破綻させます。 つまり、処理の秩序だった流れが破綻してしまい、 今回で言えば「Form1.iDoF」がFalseにならないために、 無限ループになってしまうわけです。 で、処理速度などの違いにより「この環境では出ないのに・・・」 という話になってしまうわけですね。 あと、modal(VBではVBmodalという定数&予約語になっています)の件ですが、 新規に子フォームをオープンする際に、Modalにしておかないと、 親フォームが処理を受け付けている状態になり、子フォームを呼んだ状態を 内部的に維持できないのです。 結果、子フォームは作り捨てになります。 これを防ぐために、vbmodalを指定して子フォームをオープンするのです。 こうすれば、子画面は排他になり、親画面は子画面がクローズするまで 新たな処理を受け付けなくなるのです。 これで、処理の順番の整合性を保つことができるのです。 DoEventsを意図的に使うことももちろんありますが、 とても限られていることです。 (検索処理中のキャンセルボタンなど) またmodal指定しない画面のオープンを意図的にすることもありますが、 これも限られている条件です。 「処理がどのように進んでいるのか」をもっと丁寧に考えないといけません。
補足
最初は、下記の通り単純なプログラミングでしたが、同様の現象が 出て、苦肉の策でした。Form1は、一度閉じますが、すぐに また、開いてしまうのです。(;_;) お助けを・・・ Private Sub CB_Code_Click() Form1.Show 1 Text1.SetFocus End Sub
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>Form1.Show >Do While Form1.iDoF = True >DoEvents >Loop なぜモーダルで開かないんですか? DoEventsがなんだかわかってますか? Windowsアプリのプログラミング自体に問題があると思われるのですが・・・
補足
正直言って、DoEventsは、はっきり解かっていません。 でも、結果は同じなのです。(;_;) お助けを・・・
- utatane
- ベストアンサー率33% (86/254)
Form1.iDoF = True とあり、 Do While Form1.iDoF = True とあるので、新しく開いたForm1に Form1.iDoF=Falseとなる記述はあるんですよね? 後気になるのが、iDoFというのは独自の関数のものなのでしょうか?標準のイベントにもメッソドにもなかったような気がしたので・・・・
補足
Private Sub Form_Unload(Cancel As Integer) iDoF = False End Sub と、あります。
お礼
大変参考になりました。ただ、開発マシンでは再現しないので、 結果が出るまで時間がかかると思います。 ありがとうございました。