作者:手机用户2502897397 | 来源:互联网 | 2023-05-17 14:20
我想用定时器实现曲线的动态输出,可是我把划线函数ShowData放在定时器中,定时器没有实现划线函数ShowData的功能,请问这是怎么回事呢?我的划线函数没有问题,如果在OnPaint函数中直
我想用定时器实现曲线的动态输出,可是我把划线函数ShowData放在定时器中,定时器没有实现划线函数ShowData的功能,请问这是怎么回事呢 ?我的划线函数没有问题,如果在OnPaint函数中直接调用划线函数ShowData可以输出一条曲线。
void CDCDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
CDC memDC ;
memDC.CreateCompatibleDC(&dc) ;
CPen Oldpen(PS_SOLID,2,RGB(128,128,128)) ;
CPen pen(PS_SOLID,2,RGB(0,255,0)) ;
CBrush oldbrush(RGB(0,255,255));
CBrush newbrush(RGB(255,255,0));
dc.SelectObject(&pen) ;
CWnd* pImage=GetDlgItem(IDC_STATIC) ;
pImage->GetDC() ;
pImage->GetWindowRect(&rect) ;
ScreenToClient(&rect) ; //将屏幕坐标转换为客户区坐标
//dc.Ellipse(&rect) ; //画圆
dc.Rectangle(&rect) ;
CRect newrect ;
newrect.left=rect.left+20 ;
newrect.right=rect.right-20 ;
newrect.top=rect.top+20 ;
newrect.bottom=rect.bottom-20 ;
//ShowData(&dc) ;
SetTimer(0,3000,NULL) ;
UpdateWindow() ;
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CDCDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CDCDlg::OnTimer(UINT nIDEvent)
{
CPaintDC dc(this); // device context for painting
CDC memDC ;
memDC.CreateCompatibleDC(&dc) ;
CPen Oldpen(PS_SOLID,2,RGB(128,128,128)) ;
CPen pen(PS_SOLID,2,RGB(0,255,0)) ;
CBrush oldbrush(RGB(0,255,255));
CBrush newbrush(RGB(255,255,0));
dc.SelectObject(&pen) ;
ShowData(&dc) ;
CDialog::OnTimer(nIDEvent);
}
void CDCDlg::ShowData(CDC *dc)
{
//static int count=1 ;
double lx=rect.left ;
double rx=rect.right ;
double dy=rect.bottom ;
double step=(rx-lx)/1000 ;
for(int i=0;i<1000;i++)
{
X[i]=lx+step*i ;
Y[i]=100+cos(X[i]/20)*50+50+rand()/1000;
}
dc->MoveTo(lx,dy) ;
for(i=0;i<1000;i++)
{
dc->LineTo(X[i],Y[i]);
}
}
19 个解决方案
SetTimer(0,3000,NULL) ; 第一个参数得是非零的值
这样是画不上的,在OnPaint里面绘制。在OnTimer里面把要绘制的东西,以model的形式保存下来。。。
在OnTimer中调用Invalidate()就可以了,没有必要在里面再获取dc进行绘制。
一般最好能够把绘制的功能都放在OnPaint里面实现。
OnPaint()函数里还调用了UpdateWindow() ......
nintendo_dskay你好, 在OnTimer中调用Invalidate()的作用是什么 ? 绘制功能都在OnPaint中实现是不是就不需要OnTimer函数了 ?
绘制完成后还要更新,否则是显示不出来的
而OnPaint自动更新
healer_kx 你好,
在OnTimer里面把要绘制的东西,以model的形式保存下来,
这句话我不太理解,具体一点说应该在OnTimer中做什么呢 ?
nintendo_dskay 你好,
按照你的要求我把程序修改如下,但是还是不能实现动态显示啊,是不是我的定时器用的不对啊 ,请指教一下,谢谢。
void CDCDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
CDC memDC ;
memDC.CreateCompatibleDC(&dc) ;
CPen Oldpen(PS_SOLID,2,RGB(128,128,128)) ;
CPen pen(PS_SOLID,2,RGB(0,255,0)) ;
CBrush oldbrush(RGB(119,136,153));
CBrush newbrush(RGB(255,255,0));
dc.SelectObject(&pen) ;
CWnd* pImage=GetDlgItem(IDC_STATIC) ;
pImage->GetDC() ;
pImage->GetWindowRect(&rect) ;
ScreenToClient(&rect) ; //将屏幕坐标转换为客户区坐标
dc.Rectangle(&rect) ;
dc.FillRect(&rect,&oldbrush);
}
void CDCDlg::OnTimer(UINT nIDEvent)
{
Invalidate() ;
CDialog::OnTimer(nIDEvent);
}
void CDCDlg::ShowData(CDC *dc)
{
//static int count=1 ;
double lx=rect.left ;
double rx=rect.right ;
double dy=rect.bottom ;
double step=(rx-lx)/1000 ;
for(int i=0;i<1000;i++)
{
X[i]=lx+step*i ;
Y[i]=100+cos(X[i]/20)*50+50+rand()/1000;
}
dc->MoveTo(lx,dy) ;
for(i=0;i<1000;i++)
{
dc->LineTo(X[i],Y[i]);
}
}
第一个:在OnPaint中调用SetTimer本身就是错误的,OnPaint会被调用多次,每更新一次就会调用一次,按你的代码,你会设置多个定时器的。
第二个:在OnTimer中画图不是不行,但是在OnTimer中获取CPaintDC 是不合适的,CPaintDC一般只用在OnPaint中,这涉及到无效区的设置,在定时器中不应该用这个,你可以用其它的方式获取DC,比如用CClientDC dc(this);或是用GetDC都可以,在客户画图用CClientDC是很方便的。
第三个:上面不少人说的方法是正确的,在OnTimer中不画图,仅仅是调用Invalidate()更新,将画图部分还是放在OnPaint中,这种方法是常用的方法。
nintendo_dskay 你好,
用你说的方法可以了,不过闪了很厉害,这个怎么解决呢,用双缓冲法可以吗 ?
你能不能告诉我OnPaint调用SetTimer后其刷新一次的间隔时间是不是由定时器决定的 ?
我在OnPaint()函数中调用SetTimer和在 下面的OnRunStop()中调用SetTimer效果是一样的。这二者有区别嘛 ?为什么在OnPaint()函数中调用SetTimer会设置多个定时器呢 ? 谢谢
==========
SetTimer是设置定时器,每调用一次就会设置一个定时器,OnRunStop应该是一个按钮或是菜单的处理函数吧,它一般只有在你点击它时才会被调用,而OnPaint则是出现无效区就会调用,比如你的窗口被别的窗口挡住了,你点一下你的窗口,它又回到了最前面,这时OnPaint就会被调用一次,或是做一次最大化操作,OnPaint又会被调用一次,如果将SetTimer放在OnPaint中,那会设置很多的定时器,因为你用的语句是SetTimer(1,...)也就是说定时器ID是一样的,所以每调用一次,前一个定时器就会被新定时器取代,所以在OnPaint中调用SetTimer的时间间隔根本就说不清。
闪得厉害就重写WM_ERASEBKGND的消息处理,在里面直接返回TRUE,这样就不闪了。
闪烁最好的解决办法还是双缓冲,其实你的OnPaint里面已经基本可以用双缓冲了,就是CDC memDC.
你把OnPaint里面用到的dc全部先换成memDC,也就是先把要画的东西画在内存DC上,然后用dc.BitBlt()将memDC里面的内容复制到dc上,这样就可以了,其中的参数可以参考msdn。