VC讲座17
- 格式:doc
- 大小:38.00 KB
- 文档页数:4
第一章基于VC++的OpenGL编程讲座之概述前言随着计算机多媒体技术、可视化技术及图形学技术的发展,我们可以使用计算机来精确地再现现实世界中的绚丽多彩的三维物体,并充分发挥自身的创造性思维,通过人机交互来模拟、改造现实世界,这就是目前最为时髦的虚拟现实技术。
通过这种技术,建筑工程师可以直接设计出美观的楼房模型;军事指挥员可以模拟战场进行军事推演,网民可以足不出户游览故宫博物馆等名胜古迹等。
而虚拟现实技术最重要的一部分内容就是三维图形编程。
当前,三维图形编程工具中最为突出的是SGI公司的OpenGL(Open Graphics Language,开放式的图形语言),它已经成为一个工业标准的计算机三维图形软件开发接口,并广泛应用于游戏开发、建筑、产品设计、医学、地球科学、流体力学等领域。
值得一提的是,虽然微软有自己的三维编程开发工具DirectX,但它也提供OpenGL图形标准,因此,OpenGL可以在微机中广泛应用。
目前,OpenGL在国内外都掀起了热潮,但国内对这一领域介绍的资料并不是很多,特别是有志于在图形图像方面进行深入研究的读者朋友,常常苦于不掌握OpenGL编程接口技术,无法向纵深领域扩展。
为了开启三维图形编程这扇神秘大门,本讲座在结合OpenGL 有关理论知识的基础上,着重介绍Visual C++6.0开发环境中的编程实现,由于水平有限,本讲座可能无法面面俱到,存在一些疏漏,但相信它可以将开启"神秘大门"的钥匙交给读者朋友们。
一、OpenGL的特点及功能OpenGL是用于开发简捷的交互式二维和三维图形应用程序的最佳环境,任何高性能的图形应用程序,从3D动画、CAD辅助设计到可视化访真,都可以利用OpenGL高质量、高性能的特点。
OpenGL自1992年出现以来,逐渐发展完善,已成为一个唯一开放的,独立于应用平台的图形标准,一个典型的OpenGL应用程序可以在任何平台上运行--只需要使用目标系统的OpenGL库重新编译一下。
vc 课程设计指针一、教学目标本章节的教学目标是让学生掌握指针的基本概念、运算和应用。
具体包括:1.知识目标:学生能够理解指针的定义、特点和作用,掌握指针的赋值、解引用和指针运算。
2.技能目标:学生能够运用指针解决实际问题,如通过指针访问数组元素、修改内存数据等。
3.情感态度价值观目标:学生能够认识到指针在编程中的重要性,培养对指针操作的兴趣和自信心。
二、教学内容本章节的教学内容主要包括以下几个部分:1.指针的概念:介绍指针的定义、特点和作用,使学生理解指针的基本概念。
2.指针的运算:讲解指针的赋值、解引用和指针运算,让学生掌握指针的基本操作。
3.指针与数组:通过实例展示如何使用指针访问数组元素,修改数组数据,使学生学会指针与数组的结合应用。
4.指针与函数:介绍指针作为函数参数的使用,让学生理解指针在函数调用过程中的作用。
三、教学方法为了达到本章节的教学目标,将采用以下教学方法:1.讲授法:通过讲解指针的概念、运算和应用,让学生掌握指针的基本知识。
2.案例分析法:通过分析实际案例,让学生学会指针在解决问题中的具体运用。
3.实验法:安排课堂实验,让学生亲自动手操作,加深对指针的理解和记忆。
四、教学资源为了支持本章节的教学内容和教学方法,将准备以下教学资源:1.教材:选择合适的编程教材,提供指针相关知识的学习支持。
2.参考书:推荐一些关于指针操作的参考书籍,供学生课后深入学习。
3.多媒体资料:制作PPT、视频等多媒体资料,帮助学生更直观地理解指针的概念和操作。
4.实验设备:准备计算机、编程环境等实验设备,让学生能够进行指针操作的实践。
五、教学评估本章节的评估方式将包括以下几个方面:1.平时表现:通过学生在课堂上的参与度、提问回答和小组讨论等表现进行评估。
2.作业:布置相关的指针操作练习题,评估学生的理解和应用能力。
3.考试:安排一次针对本章节内容的考试,包括选择题、填空题和编程题,全面测试学生的掌握程度。
VC6讲座(十七)使用定时器在上一讲中我们学习了利用ClassWizard来添加对话框类、控件的成员变量和通知消息处理函数的方法,并在OnAddtask()和OnEdittask()两个菜单命令处理函数中使用了在第十五讲中编辑好的对话框资源IDD_ADDTASK,现在的Schedule已经具备了与用户交互的绝大部分功能,但是它还有一个最重要的功能即报警功能没有实现,因此心铃准备在本讲中介绍一下如何在VC6中使用定时器,然后给Schedule加入相应的代码。
很多应用程序都需要使用定时器,以便定期检查状态,并重新绘图。
学过VB的朋友知道,VB 中的定时器是一个控件,我们只需要放置一个定时器控件到窗体之上,然后设置其属性,并在程序中处理该控件产生的定时事件就行了。
不过在VC中并没有定时器控件,我们可以通过两种方法来使用定时器:一种是直接调用WIN32函数SetTimer(),另一种则是调用CWnd::SetTimer(),实际上这两种方法的本质是一样的,下面我们就来看看后者的使用方法。
设置和释放定时器CWnd::SetTimer()的功能是给当前窗口设置一个定时器,该函数的原型为:UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );由于一个窗口可以同时设置几个定时器,SetTimer()的第一个参数nIDEvent起标识不同定时器的作用,我们可以任意取值,只要不与其它定时器的标识重复就行了,以便将来能正确分辨出是哪个定时器发出的定时消息。
nElapse表示每隔多少毫秒产生一次定时消息。
lpfnTimer是一个函数指针,如果传递一个NULL指针,那么在产生定时中断时,Windows会把一条WM_TIMER消息放入到程序的消息队列之中,最终由CWnd对象相应的处理函数来处理该消息,如果传递了一个真正的函数指针,那么在产生定时中断时,Windows将直接调用该函数,由该函数来处理定时消息。
这也就是说,我们可以使用两种方式来处理定时消息,它们有什么区别呢?首先,WM_TIMER是一条低优先级的消息,如果消息队列之中还有其它高优先级的消息,那么WM_TIMER将被堵塞,直到最后才会被处理;其次,WM_TIMER被程序从消息队列中取回之后,还要经过一系列的过程才能被传递到它的处理函数。
把这两点结合起来可以看出,在第一种方式下,定时消息有可能要拖延一段时间才会被处理,而第二种方式则不同,由于Windows将直接调用指定的函数,所以延迟时间要短得多。
由于Schedule对实时性要求并不苛刻,只要能精确到分钟左右就可以了,另外Schedule内部要进行的运算和处理也不多,所以心铃决定选用第一种方式,准备在视类中处理定时消息。
在第十二讲给出的CScheduleView::OnInitialUpdate()的最后一行语句便是设置定时器的代码,现在我们可以把它前面的注释符号删掉了,这个定时器将使Schedule在每过20秒左右的时间得到一次重新检查各事件状态的机会。
定时器是一种有限的系统资源,如果多个程序都需要使用定时器,那么有可能会出现设置不成功的情况,因此我们应在调用SetTimer()函数时检查它的返回值,如果返回值是0,就表示系统中已经没有可用的定时器了。
Schedule没有进行这步检查,心铃想请大家自己添上,并决定在出现这种情况时应该怎么办。
SetTimer()还有一个作用是它能够重新设置已分配的定时器的定时间隔,只要在nIDEvent中传递已分配的定时器的标识,那么该定时器的定时间隔就会改变成nElapse中指定的新值。
在程序退出时,我们应该将已分配的定时器释放掉,为此我们利用ClassWizard为视类添加一个处理WM_DESTROY消息的函数OnDestroy(),并编写以下代码:void CScheduleView::OnDestroy() {KillTimer(1);CListCtrl & lst=(this->GetListCtrl());CImageList *pImageList=lst.GetImageList(LVSIL_SMALL);delete pImageList;CListView::OnDestroy();}KillTimer()用于释放定时器,其参数应等于SetTimer()的nIDEvent,如果程序分配了多个定时器,那么应调用多次KillTimer()。
OnDestroy()同时也把与CListView内部的List控件关联的图象列表释放了。
编写消息处理函数使用定时器的第一种方式需要用到一个回调函数,该函数必须具有以下原型:void CALLBACK EXPORT TimerProc( HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime );由于我们不使用这种方式,所以TimerProc各参数的含义请大家自己查阅MSDN库,下面我们来看看如何为第二种方式编写消息处理函数。
首先我们利用ClassWizard为视类添加一个处理WM_TIMER消息的函数OnTimer(),它只有一个参数nIDEvent,检查这个值便可以知道WM_TIMER消息是由哪个定时器发出的。
下面便是OnTimer()的实现代码:void CScheduleView::OnTimer(UINT nIDEvent) {CTime tiNow=CTime::GetCurrentTime();CTimeSpan tdif(0,0,15,0);CScheduleDoc * pDoc=GetDocument();CString Message;struct ScheduleItem* pUp,*pDown;pUp=pDoc->m_pNearestTaskUp;pDown=pDoc->m_pNearestTaskDown;if(nIDEvent==1) {if( ( (pUp!=NULL) && (pUp->ti<tiNow-tdif) ) ||( (pDown!=NULL) && (pDown->ti<=tiNow+tdif) ) ) {pDoc->SearchNearestTask(); //更新事件条目的状态pDoc->UpdateState();pDoc->UpdateAllViews(NULL,0,NULL); //更新显示if((pDown!=NULL) && ( pDown->ti <= (tiNow+tdif) )) {AfxGetMainWnd()->ShowWindow(SW_NORMAL);SetForegroundWindow(); //把窗口显示在前台Message="请注意:\""; //准备提示信息Message += pDown->des;Message += "\" 的时间很快就要到了!";KillTimer(1); //必须先暂时中断定时器AfxMessageBox(Message);SetTimer(1,20000,NULL); //重新设置定时器}}}//CListView::OnTimer(nIDEvent); 将ClassWizard 生成的这行代码注释掉}在上面的代码中,我们首先检查处于时间边界的两个事件条目,判断是否需要改变它们的状态,如果是的话,就重新搜索处于时间边界的两个新事件条目,更新链表中各事件的状态,并更新显示。
对于刚从等待报警状态(状态2)进入报警状态(状态1)的事件,我们有必要以某种方式通知用户,提醒他已经到了应做某某事情的时间。
上面的代码首先将程序主窗口以正常方式显示,然后把窗口设置成前台,这两条语句组合起来便可以把Schedule 显示在前台,即便它当时处于最小化状态,上述语句也能将它的窗口弹出来。
窗口显示出来后,我们接着再显示一个消息框(见图17-1),其中给出了某某事情的时间已到了的提示信息。
消息框本质上是一个非常简单的由系统控制的对话框,上一讲给出的代码中也用到了它,我们使用的函数是MFC 类库包装过的AfxMessageBox(),它比直接使用WIN32函数MessageBox()要稍微简单一些,但缺点是不能设置消息的标题条。
除了上述两个函数外,CWnd 类也有一个MessageBox()成员函数,其功能与WIN32函数类似,大家以后可以根据需要选择使用。
大家是否注意到了,上面的代码在显示消息框之前调用了一次KillTimer(),从消息框返回后又调用了一次SetTimer(),为什么要这样做呢?这个问题实际上涉及到了WM_TIMER 消息的一些内在特点。
设置了定时器后,程序的窗口处理函数将会定期收到一条WM_TIMER 消息,如果OnTimer()内部的处理需要花费很长的时间,就有可能在还未退出它之前,程序又收到一条WM_TIMER 消息,此时会出现两种情况:一种是OnTimer()的内部调用了消息框或对话框,当前正在等待用户输入,在这种情况下,当前CPU 的控制权实际上掌握在Windows 手中,而不在程序手中,因此Windows 将再次调用OnTimer()(称为“重入”,重复进入的意思),这样可能会造成不良后果,例如将再次显示出一个消息框或对话框,或者由于后一次调用改变了全局变量,从而对前一次调用产生影响;另一种情况是OnTimer()内部正在进行大量的处理,但没有调用任何可能把控制权交还给Windows 的函数,那么第二个WM_TIMER 消息将被保留在程序的消息队列之中,如果因为OnTimer()迟迟不能返回,最后导致第三个、第四个甚至更多的WM_TIMER 消息也到来了,此时后面来的WM_TIMER 消息将会冲掉前面的WM_TIMER 消息,也即消息队列中只保留最后一条WM_TIMER 消息,其余的都被丢弃了,这与WM_PAINT 消息是类似的。
总之,上面两种情况均说明了OnTimer()或其它处理定时消息的函数不适合完成耗时很长的处理,如果不得已要进行这种处理,那么应考虑设立一些保护措施,以防止出现异常现象。
Schedule 属于第一种情况,于是心铃选择了在显示消息框之前先暂时中断定时器,从消息框返回之后再重置定时器的方法。
除此之外,我们也可以不暂停定时器,但必须设置一个初始值为假的重入标志,每次进入OnTimer()时首先检查该标志是否为真,如果是真(表示本次调用是重入)则马上退出函数,如果是假则把该标志置为真,然后进行各种处理,最后在退出函数之前又把该标志置为假,这种方法可以有效地避免因重入而带来不良的后果。