• ベストアンサー

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

質問者が選んだベストアンサー

  • ベストアンサー
  • kagep
  • ベストアンサー率23% (171/721)
回答No.4

なるほど、わかりました。 「子画面からの復帰を親画面の特定の位置で待っていて、  でその処理を継続させたい」 ということですね? その場合、考え方をまったく変える必要があります。 つまり「コマンドボタンの処理は子画面を呼び出す関連処理のみ」にするんです。 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重起動の理由はまた後述します。 これから会議なので(笑)

m-toshi
質問者

お礼

大変参考になりました。ただ、開発マシンでは再現しないので、 結果が出るまで時間がかかると思います。 ありがとうございました。

その他の回答 (5)

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.6

#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が発生します。

参考URL:
http://www.microsoft.com/JAPAN/developer/library/Vb98/vbmthshow.htm
m-toshi
質問者

お礼

>これが動かないということですが、CB_Code_Click()がCB_Codeを押したこと以外>で呼ばれているなんてありませんか? 確認しましたが、ありませんでした。(^^; ありがとうございました。

  • kagep
  • ベストアンサー率23% (171/721)
回答No.5

#4に補足です。 iDoFはフォームロード時に必ずfalseにしてください。 これで、コマンドボタン押下で子画面をオープンし、 子画面を閉じたら親画面のtext1テキストボックスにフォーカスがあたるはずです。 で、質問にあるソースでなぜ子フォームが2重起動するかというと、 子画面(Form1)のiDoFにFalseを設定してから、 Form1.showしていますよね。 実は、Form1.iDoF = True を行った時点で Form1は暗黙的にLoadされているのです。 確か暗黙でフォーム呼び出しのデフォルトはVbmodalだったと思うので、 とりあえず子フォーム終了まで親フォームは待機しているのでしょう。 で、親画面復帰後さらにshowを発効しているのでまた新たにForm1のLoadがくる。 これで、Form1が再度開きます。 DoEventsを使用しているので、内部がぐちゃぐちゃになってしまっている、 というオチなんでしょう。 間違えてたらごめんなさい。 あくまでも限られた情報下での推測ということで(^^; とりあえず#4のソース構造で試してみてください。

m-toshi
質問者

お礼

何度も、ありがとうございました。

  • kagep
  • ベストアンサー率23% (171/721)
回答No.3

正解は「“DoEvents”が悪さをしているから」と、 「“Form1”をmodalで開いていないから」ということです。 理由はですね、VBの場合、処理は順番に行われていきます。 ソースを記述した順番に、です。 ソース内で何らかのイベントが発生すればその処理に行き、 そのイベントが終了すれば、またもとのソースの続きの処理が進む、 というのが一般的な流れです。 ところが「DoEvents」はこの流れを破綻させます。 つまり、処理の秩序だった流れが破綻してしまい、 今回で言えば「Form1.iDoF」がFalseにならないために、 無限ループになってしまうわけです。 で、処理速度などの違いにより「この環境では出ないのに・・・」 という話になってしまうわけですね。 あと、modal(VBではVBmodalという定数&予約語になっています)の件ですが、 新規に子フォームをオープンする際に、Modalにしておかないと、 親フォームが処理を受け付けている状態になり、子フォームを呼んだ状態を 内部的に維持できないのです。 結果、子フォームは作り捨てになります。 これを防ぐために、vbmodalを指定して子フォームをオープンするのです。 こうすれば、子画面は排他になり、親画面は子画面がクローズするまで 新たな処理を受け付けなくなるのです。 これで、処理の順番の整合性を保つことができるのです。 DoEventsを意図的に使うことももちろんありますが、 とても限られていることです。 (検索処理中のキャンセルボタンなど) またmodal指定しない画面のオープンを意図的にすることもありますが、 これも限られている条件です。 「処理がどのように進んでいるのか」をもっと丁寧に考えないといけません。

m-toshi
質問者

補足

最初は、下記の通り単純なプログラミングでしたが、同様の現象が 出て、苦肉の策でした。Form1は、一度閉じますが、すぐに また、開いてしまうのです。(;_;) お助けを・・・ Private Sub CB_Code_Click() Form1.Show 1 Text1.SetFocus End Sub

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.2

>Form1.Show >Do While Form1.iDoF = True >DoEvents >Loop なぜモーダルで開かないんですか? DoEventsがなんだかわかってますか? Windowsアプリのプログラミング自体に問題があると思われるのですが・・・

m-toshi
質問者

補足

正直言って、DoEventsは、はっきり解かっていません。 でも、結果は同じなのです。(;_;) お助けを・・・

  • utatane
  • ベストアンサー率33% (86/254)
回答No.1

Form1.iDoF = True とあり、 Do While Form1.iDoF = True とあるので、新しく開いたForm1に Form1.iDoF=Falseとなる記述はあるんですよね? 後気になるのが、iDoFというのは独自の関数のものなのでしょうか?標準のイベントにもメッソドにもなかったような気がしたので・・・・

m-toshi
質問者

補足

Private Sub Form_Unload(Cancel As Integer) iDoF = False End Sub と、あります。

関連するQ&A

  • Access2010 SetFocusが当たらない

    Access2010です。 VBAにて、あるフォームの、デザイン上、「詳細」の中に存在しているテキストボックスにSetFocusでフォーカスを当てようと思ってます。 1 フォームロード時、フォームの「詳細」は非表示(当然、テキストボックスも非表示) 2 ボタンクリック時、フォームの「詳細」を表示し、テキストボックスにフォーカスを当てる という動作をしているのですが、2でテキストボックスにフォーカスがフォーカスが当たりません。どうしたらフォーカスが当たるのでしょうか? 以下、コードです。 Private Sub Form_Open(Cancel As Integer) Me.詳細.Visible = False End Sub Private Sub cmdボタン_Click() Me.詳細.Visible = True 'テキストボックスにフォーカスを当てる Me.txtテキスト.SetFocus End Sub よろしくお願いいたします。

  • 無限ループ objIE.Navigate

    win8.1でvbaでブラウザを操作しています。 XPからWIN7までは、 Sub Sample() Dim objIE As InternetExplorer Set objIE = CreateObject("InternetExplorer.application") objIE.Visible = True objIE.Navigate "http://www.yahoo.co.jp/" Do While objIE.Busy = True DoEvents Loop objIE.Navigate "http://shopping.yahoo.co.jp/" ・・・ このように、 objIE.Navigate に、URLを入れ替えても、問題なく表示できたのですが win8からは objIE.Navigateで、1つ目のURLを表示させ、2つ目のURLを表示させると、 見た目は、 二つ目の"http://shopping.yahoo.co.jp/"が表示されるのですが、 objIEの中身は、1つ目の "http://www.yahoo.co.jp/"のままです。 なので、 objIE.Navigate "http://shopping.yahoo.co.jp/" のあとに、 Do While objIE.Busy = True DoEvents Loop をしても、 objIEに格納されている値は、 "http://www.yahoo.co.jp/"だから 無限ループしてしまいます。 この現象を回避するにはどうすればいいでしょうか? エクセル2010です。 よろしくお願いします。

  • どこにもフォーカスを当てたくない

    フォームを開いたとき、どこにもフォーカスを当てたくないです。 アクセス2003です。 フォームにテキストボックスを1つ設置して、そのフォームを開くと フォーカスがテキストボックス上で、点滅しますが どこにもフォーカスを当てない方法あるのでしょうか? Private Sub Form_Open(Cancel As Integer) Me.詳細.SetFocus End Sub とするとコンパイルエラーになってしまいます。 不可能でしょうか?よろしくお願い致します。

  • Access+VBです

    メインフォーム側からサブフォームの並び替えや、検索するにはどう書けば良いのでしょうか? また、 [サブフォーム].Form![氏名].SetFocus と書いても、サブフォームの[氏名]にフォーカスされないのは、なぜですか? メイン側からサブ側へのアクセスの仕方がいまいち理解できません。

  • 無限ループ VBA IE操作

    VBAです。 とあるサイトで Sub IE_wait() Const READYSTATE_COMPLETE As Long = 4 Do Until objIE.readyState = READYSTATE_COMPLETE Loop Do While objIE.Busy = True DoEvents Loop End Sub が無限ループに陥ります。 中断して Exit Sub を入れてみましたが、抜けれません。 ページは既に表示済みです。 なぜ無限ループが抜けられないのか、 なぜページが表示されているのにこのコードが繰り返されるのか 何かわかる方よろしくお願いします。

  • テキストボックスの桁数をカウントして、フォーカス移動

    Win2000、VB6.0です。 テキストボックスとADOコントロールを使用して、レコードを編集・更新するフォームを作っています。 ただ、簡単に書く為に下の説明文ではDBについては書きません。 Form1に、Text1とText2があるとします。 Tab移動だけではなく、Text1に4桁目まで入力された時点で、Text2へフォーカスが移動するようにしたいと考えています。 Text1のChangeイベントで、 ------------------------------------ Private Sub Text1_Change()   If Len(Text1.Text) >= 4 Then     Text2.SetFocus   End If End Sub ------------------------------------ 以上のように記述しています。 ただ、Form1のロード時に、 ------------------------------------ Private Sub Form_Load()   Text1.Text = "1111" End Sub ------------------------------------ 以上のように記述すると、 「実行時エラー"5";」 「プロシージャの呼び出し、または引数が不正です。」 とエラーが発生してしまいます。 ロード時にテキストボックスに表示しつつ、入力された現在の桁数をカウントして、フォーカス移動する方法は無いのでしょうか? よろしくお願いします。

  • フォームを開く時のイベント処理

    Visual Basic 6.0 あるフォーム読込時イベント[Private Sub Form_Load()]で コマンドボタンにフォーカスを移動しようとしたら、エラーしてしましました。 Private Sub Form_Load() CommandButton.SetFocus ’プロシージャの呼び出し、または引数が不正です End Sub Form_Open や BeforeUpdate ? 開いた後にフォーカスをセット出来る イベント処理は無いでしょうか? ご教授願います。

  • フリーズしてしまいます。

    アクセスでWebBrowserコントロールを使ってIE操作をしているのですが フリーズしてしまいます。 フォームに、WebBrowser0を配置して、 ---------------------------------- Private Sub Form_Load() Me.WebBrowser0.Navigate "http://login.yahoo.co.jp/config/login?logout=1" Call wait 省略・・・ End Sub ---------------------------------- Sub wait() Const READYSTATE_COMPLETE As Long = 4 Do Until Me.WebBrowser0.ReadyState = READYSTATE_COMPLETE Loop Do While Me.WebBrowser0.Busy = True DoEvents Loop End Sub ---------------------------------- を実行すると必ずフリーズします。 ---------------------------------- Sub wait() Do While Me.WebBrowser0.Busy = True DoEvents Loop End Sub ---------------------------------- にしたら問題なく表示されます。 でもこれだけだと、表示し終わりません。 表示されてないのに次のコードへ進んでしまいます。 そもそもなぜフリーズするのでしょうか? アクセス2007です。ご回答よろしくお願いします。

  • VB Loopを一時停止し再開あるいはキャンセル

    Loopで処理を回しています。処理件数が多く、処理の途中で一時停止させ、DataGridViewに表示されている処理結果を目で確認ないしマウスでコピーしてから、処理を再開ないしキャンセルして終了させる仕様を作成中です。 MessageBoxを使用すれば、Loopは一時停止出来たのですが、MessageBoxだとDataGridView上の処理結果をマウスでコピーなど出来ません。 そこで、MessageBoxを使用せずに、以下のコマンドを書いてみたのですが、最初のStopFlag=Trueが効くだけで次のコマンドは一瞬で処理されLoopが続いてしまいます。いかにすればLoopを一時停止できるか教えてください。 <変数宣言> Public StopFlag As Boolean Public CancelFlag As Boolean <前処理> TextBox1.Text = "処理待ち" 'テキストボックスに処理ステータスを表しています。 TextBox1.Refresh() <処理> Do Me.Cursor = Cursors.WaitCursor '砂時計開始 TextBox1.Text = "処理中" ’ステータスを処理中として表示 TextBox1.Refresh() ~ Application.DoEvents() 'ストップボタンを押下したらここでDoEventsさせます。 If StopFlag = True Then ’ここでLoopを一時停止させておきたいのです。 Me.Cursor = Cursors.Default '一旦砂時計を止めます TextBox1.Text = "処理一時停止" TextBox1.Refresh() If StopFlag = False Then ’再開ボタンが押下されたらここで再開させたい。 TextBox1.Text = "処理中" ’処理中と表示させます TextBox1.Refresh() Me.Cursor = Cursors.WaitCursor '砂時計再開です ElseIf CancelFlag = True Then ’キャンセルボタンが押下されれば、処理はLoopを抜けます。 TextBox1.Text = "キャンセル" TextBox1.Refresh() Exit Do End If Loop '----------ストップボタン---------- Private Sub Button2_Click~ StopFlag = True End Sub '----------再開ボタン---------- Private Sub Button3_Click~ StopFlag = False End Sub '----------キャンセルボタン---------- Private Sub Button4_Click~ CancelFlag = True End Sub この質問に補足する

  • クリップボードにアクティブウィンドウが貼り付けられません。

    Public Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long) Private Sub Command1_Click() Clipboard.Clear Form2.Picture1.AutoRedraw = True Form1.SetFocus keybd_event vbKeySnapshot, 0, 0, 0 Do While Clipboard.GetFormat(vbCFBitmap) = False DoEvents Loop Form2.Picture1.Picture = Clipboard.GetData() End Sub keybd_eventを使って、こんな感じでForm2のピクチャーにForm1を貼付けしたいのですが、画面全体がコピーされてしまいます。 アクティブウィンドウのみコピーするにはどうしたら良いですか?

専門家に質問してみよう