Staticをタイマーで色変更

[戻る]
まさ 2003/11/11(火) 01:17:29
過去ログを参照したのですが、タイマーと共にカラー変更する記載はなく、
唯一有った書き込みもリンク切れでしたので質問させていただきます。
(http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200209/02090084.txt)

Win2000,VC6.0,MFC,ダイアログで作っています。

表題の通り、時間の経過と共にスタティックの背景色を変えたいのですが、
正しく動いてくれません。

現在 OnCtlColorに、
HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

    if (pWnd->GetDlgCtrlID() == IDST_MES) {  // 変更したいのはIDST_MES
        pDC->SetTextColor(RGB(0,0,0));       // テキスト色は黒固定
        pDC->SetBkColor(RGB(m_nCol,m_nCol,m_nCol));  // 背景のみ変化させる
        return (HBRUSH)::CreateSolidBrush(RGB(m_nCol,m_nCol,m_nCol));
     }
     return hbr;
}

そして、タイマーで、
void CTestDlg::InitSysTime()  // InitDialogで呼び出します
{
    if(m_bTimer == FALSE){
        SetTimer(156,200,NULL);  // 0.2秒毎にタイマー動作
        m_bTimer = TRUE;
    }
}
void CTestDlg::OnTimer(UINT nIDEvent) 
{
   if (nIDEvent == 156)          // 156はタイマー識別のためのID
   {
       InitSysTime();
   }
   m_nCol--;                  // タイマーの経過と共に色を減色していきます
   if (m_nCol<0) m_nCol=255;  // m_nColはInitDialogで255を初期値設定済み    
                              // <---- ※
   CDialog::OnTimer(nIDEvent);
}

と、いうような感じでコーディングしています。
ですが、最初のダイアログ表示時に1度だけカラーが設定されるだけで、あとは何も起こりませ
ん。
※印のところに、MessageBoxを表示して0.2秒毎の通過は確認しています。
また、ダメ元で※印のところにUpdateWindow()を全体を再描画しましたが、
変わりませんでした。

書き込みが長くなってしまい、申し訳ありませんが、どなたかご指導ください。
よろしくお願いいたします。

まさ 2003/11/11(火) 01:22:32
上記の件に追加です。
0.2秒毎というのは計ったわけではありませんが、実行と共に無数のメッセージボックスが
表示されたため「通過している」と解釈させて頂きました。
尚、これを SetTimer(156,2000,NULL);としたら、(当然ですが)2秒毎に表示されました。

愚暗 2003/11/11(火) 01:34:15
※印のところに
Invalidate(FALSE);
ではどうでしょう?

akey 2003/11/11(火) 03:04:31
質問の内容は、愚暗さんの回答の通りだと思いますので注意をひとつ

>現在 OnCtlColorに、
>HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
>{
>    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
   :
>>>      return (HBRUSH)::CreateSolidBrush(RGB(m_nCol,m_nCol,m_nCol));

これは、リソースリークするのでやめた方が良いでしょう

理由は、過去ログを「リソースリーク」で検索してみてください

まさ 2003/11/11(火) 11:50:54
愚暗さん、akeyさん、情報ありがとうございます。

今日は出先なので、すぐに確認する事はできないのですが、

まず、愚暗さんのアドバイスのInvalidate(FALSE);で動作を確認したいと思います。

そして、akeyさんのアドバイスに関して、メモリリークについて過去ログを調べました。

これについては、メンバ変数として
 CBrush m_brush[255]; を宣言し、
InitDialogで
 for(i=0; i<255; i++){
   m_brush[i].CreateSolidBrush( RGB(i,i,i) );
 }
よりブラシを作成し、OnCtlColorではこのブラシの配列を使用してみます。
そしてデストラクタで同じくループでDeleteObject()をやってみます。

後ほど改めてご報告させていただきます。よろしくお願いいたします。

アイススケーター 2003/11/11(火) 18:21:09
InitSysTime()はInitDialogで1回コールすればいいと思います。

一部をちょっと修正してみました。

void CTestDlg::OnTimer(UINT nIDEvent) 
{
   if (nIDEvent == 156)          // 156はタイマー識別のためのID
   {
      m_nCol--;                  // タイマーの経過と共に色を減色していきます
      if (m_nCol<0) m_nCol=255;  // m_nColはInitDialogで255を初期値設定済み    
                              // <---- ※
//       InitSysTime();      <---不要
   Invalidate(FALSE);
   }
   CDialog::OnTimer(nIDEvent);
}

まさ 2003/11/12(水) 00:00:13
[[解決]]
先ほど、私の意図する通りに動作しました。

まずは愚暗さんのアドバイスに従い、Invalidate(FALSE);だけ追加して
実行してみましたら、数秒という早さで全ての色が出なくなってしまいました。
これがakeyさんが言っていたリソースリークの現象なのですね。

次に、メンバ変数にCBrush型の配列 CBrush m_brush[255];を持ち、
InitDialog()でCreateSolidBrushで配列全てにRGBを変えたブラシを作成し、
それをOnCtlColor()でreturnするようにしました。
(分かりづらくて申し訳ありません。)

そうしましたら、見事に色が滑らかに変化してくれました。
ただ、0.2秒ごとのInvalidate、そして用意した配列要素数も多いため、
非常にゆっくりとした色の変化になっています。これは今後調整していきます。


また、アイススケーターさんのタイマーに関するご指摘ありがとうございました。
確かにInitSysTime()を無駄に呼んでいました。
SetTimerだけをInitDialogで実行し、OnTimer()内をアイススケーターさんのご指導通りに
修正させていただきました。コードも随分とスッキリさせる事ができました。

色の変更に限らず、タイマーの使い方、リソースリークに関することも同時に学習でき、
私なりには大収穫です。
愚暗さん、akeyさん、アイススケーターさん、アドバイス本当にありがとうございました。

末筆になりますが、ご返信が遅くなりましたことをお詫びいたします。

まさ 2003/11/12(水) 00:05:53
度々申し訳ありません。

「数秒で色が出なくなった」というのは、
タイマーをSetTimer(156,1,NULL)として実行した結果によるものです。
タスクマネージャのプログラムのメモリ使用量があっという間に増えていました。

今後、メモリについては常に意識して取り組みたいと思います。

古いスレッドには追加発言できません。