none
処理中に、スレッドタイマーを使用してラベルを点滅させたい RRS feed

  • 質問

  • お世話になっております。arubi_momoと申します。

    現在、Windows7 64bit、Visual Studio2010 VC# .net Framework4.0を使用してアプリケーションを作成しています。

    実行ボタンを押した時に、1:ファイル読込処理 2:ファイル作成処理、など、今行っている処理内容をラベルで点滅させる処理を作っています。

    点滅処理にはWindows.formのタイマーを使用しましたが、これだとビジー状態となり、実行処理中にラベルが点滅しませんでしたので、スレッドタイマーを使用して別スレッドでタイマーを動かせば実現できるだろうと思い、作成してみたのですが、やはり実行処理中はラベルが点滅しません。

    ※ファイル読込などの処理を実行せず、タイマーだけの処理であれば動作することは確認してあります。

    何か使い方が間違っているのだろうとは思うのですが、行き詰ってしまいました。原因のわかる方がいらっしゃいましたら、ご教示いただければ幸いです。

    何卒よろしくお願いいたします。

    private void button_Click(object sender, EventArgs e)
    {
        // スレッドタイマー作成
       TimerCallback timerDelegate = new TimerCallback(MyClock);
       System.Threading.Timer timer = new System.Threading.Timer(timerDelegate, null, 0, 500);
      //ファイル読込処理
        ・・・
      //ファイル作成処理
        ・・・
      // スレッドタイマーを停止
      timer.Change(Timeout.Infinite, Timeout.Infinite);
    }
    //Delegate呼出処理
    public void MyClock(object o)
    {
        this.BeginInvoke(new changeLabelTextDelegate(changeLabelText), new object[1]);
    }
    //Timer処理(ラベル点滅)
    private delegate void changeLabelTextDelegate(int val);
    private void changeLabelText(int val)
    {
         label1.Visible = !label1.Visible;
     }

    2014年3月19日 8:25

回答

  • カーソルが砂時計にならないのは、ファイル処理を別スレッドにしたことでハンドラから抜けてしまい、メッセージが適切に処理されるようになったからだと思います。

    なので、マウスカーソルが変わらないのではなく、一瞬だけ変わるけど、そのあとすぐに元に戻ってしまう状態なのだと思います。

    それと、砂時計にならなくなったということなので、マウス操作も含め、ユーザー操作を受け入れ可能な状態になっていると思います。ファイル処理を行うボタンを処理中にも押せていませんか?

    今までと段取りが変わったことで、待機状態を作り出せない状況になっていると思いますので、それを疑似的に作り出す状態(メッセージは適切に処理しつつ、不適切なユーザー操作をすべてブロックする仕組み)を考慮する必要があると思います。

    C++の話なので直接参考にはなりませんが、1月にこのネタでセッションやったので資料のリンクを張っておきます。

    [勉強会]東京87資料公開


    とっちゃん@わんくま同盟, Microsoft MVP for Visual C++ (Oct 2005-) http://blogs.wankuma.com/tocchann/

    • 回答としてマーク arubi_momo 2014年4月7日 3:01
    2014年4月2日 2:46
  • どのみちUIスレッドは単一です。タイマをスレッドタイマに変えたところで、UIの変更にはUIスレッドを使わざるを得ないので、UIスレッドで重い処理をやっているなら意味はありません。

    なので、ファイル読み込み処理~ファイル作成処理の部分を、BackgroundWorkerなりなんなりを使って別スレッド処理するようにしましょう。そうすればタイマもSystem.Windows.Forms.Timerのままで問題ありませんし。

    • 回答の候補に設定 星 睦美 2014年3月20日 2:13
    • 回答としてマーク 星 睦美 2014年3月26日 2:13
    2014年3月19日 10:53

すべての返信

  • どのみちUIスレッドは単一です。タイマをスレッドタイマに変えたところで、UIの変更にはUIスレッドを使わざるを得ないので、UIスレッドで重い処理をやっているなら意味はありません。

    なので、ファイル読み込み処理~ファイル作成処理の部分を、BackgroundWorkerなりなんなりを使って別スレッド処理するようにしましょう。そうすればタイマもSystem.Windows.Forms.Timerのままで問題ありませんし。

    • 回答の候補に設定 星 睦美 2014年3月20日 2:13
    • 回答としてマーク 星 睦美 2014年3月26日 2:13
    2014年3月19日 10:53
  • Hongliangさま

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

    そうだったのですか。。。ファイル処理の方を別スレッドにしないといけなかったのですね。それでやってみます!結果はまたご報告させていただきます。

    2014年3月20日 0:34
  • だいぶご報告が遅れまして申し訳ありません。期末のバタバタで当業務から離れていました。

    ファイル処理を別スレッドにし、Windows Formsのタイマーを使用して修正したところ、点滅させることができました!大変ありがとうございました。

    ただ、なぜかCursorが砂時計に変わらなくなってしまって難航してます。UI側に置いても別スレッド側に置いてもなぜか変わりません。これはもう少し調べてみます。とにかく、実現できてとても助かりました!ありがとうございました!

    2014年4月1日 2:36
  • カーソルが砂時計にならないのは、ファイル処理を別スレッドにしたことでハンドラから抜けてしまい、メッセージが適切に処理されるようになったからだと思います。

    なので、マウスカーソルが変わらないのではなく、一瞬だけ変わるけど、そのあとすぐに元に戻ってしまう状態なのだと思います。

    それと、砂時計にならなくなったということなので、マウス操作も含め、ユーザー操作を受け入れ可能な状態になっていると思います。ファイル処理を行うボタンを処理中にも押せていませんか?

    今までと段取りが変わったことで、待機状態を作り出せない状況になっていると思いますので、それを疑似的に作り出す状態(メッセージは適切に処理しつつ、不適切なユーザー操作をすべてブロックする仕組み)を考慮する必要があると思います。

    C++の話なので直接参考にはなりませんが、1月にこのネタでセッションやったので資料のリンクを張っておきます。

    [勉強会]東京87資料公開


    とっちゃん@わんくま同盟, Microsoft MVP for Visual C++ (Oct 2005-) http://blogs.wankuma.com/tocchann/

    • 回答としてマーク arubi_momo 2014年4月7日 3:01
    2014年4月2日 2:46
  • とっちゃんさま

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

    そうなんです。ファイル処理中に他のユーザ操作が受け入れられる状態になってしまいました。色々試してみたところ、UseWaitCursorでFormのカーソルを待機状態にすることで一応解決することはできました。

    とっちゃんさんがおっしゃる「メッセージは適切に処理しつつ、不適切なユーザ操作をブロックする仕組み」という方法もあるんですね。わざわざリンクまで貼っていただきありがとうございます。ぜひ参考にさせていただきます!

    2014年4月7日 5:01