定时器不起作用,求助!

时间:2021-06-04 05:18:08
我的程序试个对话框程序。设置定时器后OnTimer()函数不起作用。经过调试发现,是因为我再OnPain()函数中屏蔽了 CPaintDC dc(this);这句话引起的。
因为对话框的背景用位图显示,用了二次缓存的方式,在OnPain()函数中的操作大致如下:
void CBMSIIDlg::OnPaint() 
{
// CPaintDC dc(this); // device context for painting我就是屏蔽了这行代码

// TODO: Add your message handler code here
CClientDC dc(this);
CRect  rc;
GetClientRect(&rc);

if (NULL == m_memdc.GetSafeHdc())
{
m_bitmap.CreateCompatibleBitmap(&dc,rc.Width(),rc.Height());//创建兼容位图
m_memdc.CreateCompatibleDC (&dc);//创建内存DC
m_memdc.SelectObject(&m_bitmap);

m_bitmap2.LoadBitmap(IDB_BITMAP_TEST1);
m_memdc2.CreateCompatibleDC (&dc);
m_memdc2.SelectObject(&m_bitmap2);

m_memdc.BitBlt(0,0,rc.Width(),rc.Height(),&m_memdc2,0,0,SRCCOPY);
}
         CBrush  brush,* poldbrush;
CPen  pen,* poldpen;  
         brush.CreateSolidBrush(RGB(0,0,0));
poldbrush=m_memdc.SelectObject(&brush);
pen.CreatePen(PS_NULL,0,0);
poldpen = m_memdc.SelectObject(&pen);

         m_memdc.Rectangle(&rc);

         /*///////////////////
         ...
         //这部分是用m_memdc做的一些GDI绘制操作
         ...
         */

         if (NULL != m_memdc.GetSafeHdc() )
{
dc.BitBlt(0,0,rc.Width(),rc.Height(),&m_memdc,0,0,SRCCOPY);
}
}
对话框上有五个按钮,开始是隐藏的,当单击对话框后显示按钮,过6秒后在隐藏按钮,具体操作如下:
void CBMSIIDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
         // TODO: Add your message handler code here and/or call default

         m_time = CTime::GetCurrentTime();
SetTimer(1,1000,NULL);
GetDlgItem(IDC_BUT_CELL)->ShowWindow(SW_SHOW);
GetDlgItem(IDC_BUT_ALARM)->ShowWindow(SW_SHOW);
GetDlgItem(IDC_BUT_SETUP)->ShowWindow(SW_SHOW);
GetDlgItem(IDC_BUT_CHANGE)->ShowWindow(SW_SHOW);
GetDlgItem(IDC_BUT_NEXT)->ShowWindow(SW_SHOW);

UpdateWindow();
}

void CBMSIIDlg::OnTimer(UINT nIDEvent) 
{
// TODO: Add your message handler code here and/or call default

         if (nIDEvent == 1)
{
CTime  time;
time = CTime::GetCurrentTime();
if (time - m_time >= 6)
{
m_bitmap.DeleteObject();
m_memdc.DeleteDC();

m_bitmap2.DeleteObject();
m_memdc2.DeleteDC();

GetDlgItem(IDC_BUT_CELL)->ShowWindow(SW_HIDE);
GetDlgItem(IDC_BUT_ALARM)->ShowWindow(SW_HIDE);
GetDlgItem(IDC_BUT_SETUP)->ShowWindow(SW_HIDE);
GetDlgItem(IDC_BUT_CHANGE)->ShowWindow(SW_HIDE);
GetDlgItem(IDC_BUT_NEXT)->ShowWindow(SW_HIDE);

UpdateWindow();
m_bclick=true;
KillTimer(1);
}
}
}

现在OnTimer()函数不起作用,如果我不屏蔽掉OnPain()函数中的CPaintDC dc(this);这一行的话,OnTimer()函数就没事了。
现在的问题是:我必须要屏蔽掉OnPain()函数中的CPaintDC dc(this);这句话。因为如果我不屏蔽的话,其他线程中的Invalidate()操作就会使屏幕刷新时有闪动(我的是WinCE系统,用EVC开发,和VC6.0差不多)。

这个问题应该如何解决?我现在有如下疑问,希望大家帮我分析一下:
1)为什么我屏蔽掉CPaintDC dc(this);这句话后,OnTimer()函数就不起作用呢?难道这句话还会对消息队列产生什么影响?
2)我想过自己写个定时器的回调函数,用来触发定时器的设置。这个回调函数写法大致如下:
    static void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime);
这个函数在程序执行时倒是可以执行,但问题是,我现在不知道怎么关掉这个自定义的定时器回调函数?应该如何关掉呢?总不能还用KillTimer(1);这个函数吧?

11 个解决方案

#1


1)为什么我屏蔽掉CPaintDC dc(this);这句话后,OnTimer()函数就不起作用呢?难道这句话还会对消息队列产生什么影响? 
============
这个问题好像前几天有人问过,CPaintDC dc(this)这个语句中CPaintDC的构造函数和析构函数中会调用BeginPaint和EndPaint这两个函数来处理无效区,如果在WM_PAINT中不调用这两个函数,无效区总是存在,这样,系统总是不停地发WM_PAINT消息,这样,WM_TIMER消息就会被阻塞住.所以你的OnTimer就不起作用了.
2)我想过自己写个定时器的回调函数,用来触发定时器的设置。这个回调函数写法大致如下: 
    static void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime); 
这个函数在程序执行时倒是可以执行,但问题是,我现在不知道怎么关掉这个自定义的定时器回调函数?应该如何关掉呢?总不能还用KillTimer(1);这个函数吧? 
===========================
还是用KillTimer啊,后面的参数还是用定时器ID号啊,你关的不是回调函数,而是定时器.

#2


谢谢L上的朋友,第二个问题我好像明白了。
但对于第一个问题,有没有什么方法可以解决的?我还是想在实在不行的情况下自己写定时器回调函数。

#3


在OnPaint中调用CPaintDC是应该的,如果不用它的话,当调用Invalidate()时会造成无效区不会被处理的问题,你如果实在不想调用CPaintDC,是不是可以考虑将绘图的代码不放到OnPaint中去。

#4


1楼讲的太明白了,狂顶
自己写定时器回调函数也没有用啊,照样会阻塞。

注视放开不就可以了

#5


这样处理会堵塞程序的.........CPaintDC是需要用的

#6


应该不会吧,没有理由啊..
莫非...内存泄漏了??

#7


不应该屏蔽啊。

#8


我就是不想在调用Invalidate()时刷新,才屏蔽CPaintDC的~~

感谢3L的朋友,你的想法我倒是要试一下,看看效果怎么样,我先改下代码~~一会回来~~

#9


自己写重绘部分吧~

#10


或者在 OnPaint 中 加BOOL 判断重绘的部分

#11


应该是解决了,现在改成如下:
void CBMSIIDlg::OnPaint() 
{
CPaintDC dc(this); // device context for painting

// TODO: Add your message handler code here

// Do not call CDialog::OnPaint() for painting messages
}
自己写重绘部分:
void CBMSIIDlg::drawmemory()
{
CClientDC dc(this);
CRect  rc;
GetClientRect(&rc);
     
        if (NULL == m_memdc.GetSafeHdc()) 
       { 
            m_bitmap.CreateCompatibleBitmap(&dc,rc.Width(),rc.Height());//创建兼容位图 
              m_memdc.CreateCompatibleDC (&dc);//创建内存DC 
            m_memdc.SelectObject(&m_bitmap); 

            m_bitmap2.LoadBitmap(IDB_BITMAP_TEST1); 
            m_memdc2.CreateCompatibleDC (&dc); 
            m_memdc2.SelectObject(&m_bitmap2); 

            m_memdc.BitBlt(0,0,rc.Width(),rc.Height(),&m_memdc2,0,0,SRCCOPY); 
       } 
        CBrush  brush,* poldbrush; 
        CPen  pen,* poldpen;  
        brush.CreateSolidBrush(RGB(0,0,0)); 
        poldbrush=m_memdc.SelectObject(&brush); 
        pen.CreatePen(PS_NULL,0,0); 
        poldpen = m_memdc.SelectObject(&pen); 

        m_memdc.Rectangle(&rc); 

        /*/////////////////// 
        ... 
        //这部分是用m_memdc做的一些GDI绘制操作 
        ... 
        */ 

        if (NULL != m_memdc.GetSafeHdc() ) 
        { 
              dc.BitBlt(0,0,rc.Width(),rc.Height(),&m_memdc,0,0,SRCCOPY); 
        } 
}
感谢大家的帮忙,呵呵~~~
不过心里还是总感觉有点不对劲~~~~

#1


1)为什么我屏蔽掉CPaintDC dc(this);这句话后,OnTimer()函数就不起作用呢?难道这句话还会对消息队列产生什么影响? 
============
这个问题好像前几天有人问过,CPaintDC dc(this)这个语句中CPaintDC的构造函数和析构函数中会调用BeginPaint和EndPaint这两个函数来处理无效区,如果在WM_PAINT中不调用这两个函数,无效区总是存在,这样,系统总是不停地发WM_PAINT消息,这样,WM_TIMER消息就会被阻塞住.所以你的OnTimer就不起作用了.
2)我想过自己写个定时器的回调函数,用来触发定时器的设置。这个回调函数写法大致如下: 
    static void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime); 
这个函数在程序执行时倒是可以执行,但问题是,我现在不知道怎么关掉这个自定义的定时器回调函数?应该如何关掉呢?总不能还用KillTimer(1);这个函数吧? 
===========================
还是用KillTimer啊,后面的参数还是用定时器ID号啊,你关的不是回调函数,而是定时器.

#2


谢谢L上的朋友,第二个问题我好像明白了。
但对于第一个问题,有没有什么方法可以解决的?我还是想在实在不行的情况下自己写定时器回调函数。

#3


在OnPaint中调用CPaintDC是应该的,如果不用它的话,当调用Invalidate()时会造成无效区不会被处理的问题,你如果实在不想调用CPaintDC,是不是可以考虑将绘图的代码不放到OnPaint中去。

#4


1楼讲的太明白了,狂顶
自己写定时器回调函数也没有用啊,照样会阻塞。

注视放开不就可以了

#5


这样处理会堵塞程序的.........CPaintDC是需要用的

#6


应该不会吧,没有理由啊..
莫非...内存泄漏了??

#7


不应该屏蔽啊。

#8


我就是不想在调用Invalidate()时刷新,才屏蔽CPaintDC的~~

感谢3L的朋友,你的想法我倒是要试一下,看看效果怎么样,我先改下代码~~一会回来~~

#9


自己写重绘部分吧~

#10


或者在 OnPaint 中 加BOOL 判断重绘的部分

#11


应该是解决了,现在改成如下:
void CBMSIIDlg::OnPaint() 
{
CPaintDC dc(this); // device context for painting

// TODO: Add your message handler code here

// Do not call CDialog::OnPaint() for painting messages
}
自己写重绘部分:
void CBMSIIDlg::drawmemory()
{
CClientDC dc(this);
CRect  rc;
GetClientRect(&rc);
     
        if (NULL == m_memdc.GetSafeHdc()) 
       { 
            m_bitmap.CreateCompatibleBitmap(&dc,rc.Width(),rc.Height());//创建兼容位图 
              m_memdc.CreateCompatibleDC (&dc);//创建内存DC 
            m_memdc.SelectObject(&m_bitmap); 

            m_bitmap2.LoadBitmap(IDB_BITMAP_TEST1); 
            m_memdc2.CreateCompatibleDC (&dc); 
            m_memdc2.SelectObject(&m_bitmap2); 

            m_memdc.BitBlt(0,0,rc.Width(),rc.Height(),&m_memdc2,0,0,SRCCOPY); 
       } 
        CBrush  brush,* poldbrush; 
        CPen  pen,* poldpen;  
        brush.CreateSolidBrush(RGB(0,0,0)); 
        poldbrush=m_memdc.SelectObject(&brush); 
        pen.CreatePen(PS_NULL,0,0); 
        poldpen = m_memdc.SelectObject(&pen); 

        m_memdc.Rectangle(&rc); 

        /*/////////////////// 
        ... 
        //这部分是用m_memdc做的一些GDI绘制操作 
        ... 
        */ 

        if (NULL != m_memdc.GetSafeHdc() ) 
        { 
              dc.BitBlt(0,0,rc.Width(),rc.Height(),&m_memdc,0,0,SRCCOPY); 
        } 
}
感谢大家的帮忙,呵呵~~~
不过心里还是总感觉有点不对劲~~~~