tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルShowDialog時の処理について
記事No8046
投稿日: 2008/09/01(Mon) 15:52
投稿者皐月
こんにちは、いつもお世話になっております。
VB2005で開発を行っております。USB通信ケーブルから接続されたデバイスの信号を受け取り、状態のモニター、設定が行えるアプリケーションを作成しております。

通常の信号読み取りはメイン画面から、ループ処理を利用して行っています。読み取った値はメイン画面のそれぞれの項目のラベルへ入力されるようになっており、値が表示されているラベルをクリックすると値の設定が行えるようにしてあるのですが、値の設定画面(Form2)をForm2.ShowDialogで呼び出しユーザーが値を設定するまでメイン画面には戻れないような仕様にしたいと考えています。

そのため、ShowDialogをそのまま使用してForm2を呼び出していたのですが、このとき他のFormに干渉しなくなってしまうため、Mainで作成した信号読み取りの処理を通らなくなってしまいました。Form2にMainと同等のソースコードを記述してみました。(メイン画面同様、ループ処理でデバイスより送られてくる信号を読み続ける処理です)が、Form2の画面をShowDialogしてもForm2は表示されずループの処理まですすんでしまっているようです。

デバッグで確認してみますとForm2_Load後にループの処理を呼び出しているのですが、実際はなぜかForm2が表示されず、信号読み出しのループが行われている状態となっているようです。流れとしては

    Form2.ShowDialogでForm2を呼び出す
                   ↓

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load, DispSetdata.Enter

        DispSetdata.Select()

        信号読み取りのループ処理をコール

    End Sub

という風になっております。信号読み取りのループ処理には

System.Windows.Forms.Application.DoEvents()

の記述があります。Form2の画面を表示するためにはどうすればよいのでしょうか?

今回のソースはShowDialogを使用していますが、ShowDialogと同等の動作(他のFormにフォーカスが移動しない)をするのであれば、ShowDialogであるかどうかは、気に留めませんので別の方法がありましたら、ご教授ください。

また、上記のものとは別になりますが、印刷の呼び出し中に、PrintDialog1.ShowDialog()がありますのでこちらもループの処理を通るように修正したいのですが、どこを編集すればよいのかわからない状態です。

宜しくお願いいたします。

[ツリー表示へ]
タイトルRe: ShowDialog時の処理について
記事No8047
投稿日: 2008/09/01(Mon) 16:27
投稿者たくボン
> 通常の信号読み取りはメイン画面から、ループ処理を利用して行っています。読み取った

ループ処理の中身がわからないので、解答しにくいですがこんな感じですか?

-- 作成手順 ---------
新規プロジェクト作成
Form1, Form2を作成。
Form1にLabelとTimer, Buttonを追加。
Timer1のEnableをTrue。

Form1に以下のコードを追加。

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

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim dlg As New Form2
    If dlg.ShowDialog(Me) Then    MessageBox.Show("hoge")
End Sub

------------------

ループ処理がTimerで実装できるか検討してみてください。

[ツリー表示へ]
タイトルRe^2: ShowDialog時の処理について
記事No8048
投稿日: 2008/09/01(Mon) 17:03
投稿者皐月
たくボンさん、さっそくのお返事ありがとうございます。

> ループ処理の中身がわからないので、解答しにくいですがこんな感じですか?

失礼しました。わかりにくいとは思いますが、以下にForm2の内容の一部を記します。
Form2_Loadから、ループ処理のあるCommunicateを呼び出す処理となっています。
現在、以下のソースではForm2は表示されず、communicateのループ処理を行うため強制終了するしか終了方法がありません。
Form2には決定ボタンがありますので、それをクリックされるとForm2がクローズされメインの処理に戻るよう作成してあります。

Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load, DispSetdata.Enter
        DispSetdata.Select()
        communicate()
    End Sub


Private Sub communicate()
 Do
    If Devicechk(ReDevNo) = 1 And FirstData(ReDevNo) = -1 Then
        StartdataRead(ReDevNo)
    End If

    If Devicechk(ReDevNo) <> 0 Then
        ReadPara()
    End If

    If CommState <> DOREAD Then
        ReDevNo = ReDevNo + 1
        If ReDevNo > 100 Then
           ReDevNo = 0
           ReadNo = ReadNo + 1
           If ReadNo > 10 Then
               ReadNo = 0
               SelectDispItem()
           End If
        End If
     End If

     System.Windows.Forms.Application.DoEvents()
  Loop

End Sub

> ループ処理がTimerで実装できるか検討してみてください。

Timerを使用したときは問題なく動作したのですが、Timerで設定できる最小のIntervalが1となっており、アナライザで測定すると通信データの読み取りで、1データごとに約1.4秒ほど時間の隙間が生じるため、実装を断念しております。

[ツリー表示へ]
タイトルRe^3: ShowDialog時の処理について
記事No8054
投稿日: 2008/09/02(Tue) 10:05
投稿者たくボン
返信遅くなりすいません。開発環境は何でしょうか?

VS2005以降ならBackgroundWoker, それ以前なら別スレッドで処理するのが良いと思います。
以下は、VB2005でのサンプルの手順です。


-- 作成手順 ---------
新規プロジェクト作成。
Form1, Form2を作成。
Form1にLabel1とBackgroundWoker1, Button1, Button2を追加。
BackgroundWoker1のWokerReportsProgressをTrueに。

Form1に以下のコードを追加。

Private sec As Integer

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    Do
        If DateTime.Now.Second <> sec Then
            BackgroundWorker1.ReportProgress(1)
        End If
        Application.DoEvents()
    Loop
End Sub

Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    Me.Label1.Text = DateTime.Now.Second
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Me.BackgroundWorker1.RunWorkerAsync()
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    Dim dlg As New Form2
    If dlg.ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
        'TODO hoge
    End If
End Sub

------------------
2005からはスレッド間のコントロールアクセスで例外が発生するようになったので、BackgroudWokerを利用するのが簡単でいいです。

[ツリー表示へ]
タイトルRe^4: ShowDialog時の処理について
記事No8081
投稿日: 2008/09/03(Wed) 23:28
投稿者皐月
たくボンさん、お返事ありがとうございます。遅くなりましたが、自分なりに検証ができましたので報告させていただきます。

開発環境はVB20005です。
結果としてたくボンさんに教えていただいたBackgroudWokerを利用する方法で、思うように動作させることができました。ありがとうございます。

あと、BackgroudWokerの前に提案していただいたタイマーでの処理なのですが、よく自分が記述したソースを確認するとタイマー処理から飛んだ関数でDoLoopを使用している部分がありそこで時間がかかっていたようです。修正したら問題なく動作いたしました。
お騒がせしてすみません><

[ツリー表示へ]