丁 智,肖 宇
OpenGL是图形硬件的软件接口[1-2],由于其具有稳定性好、可移植性强等特点,目前已成为广泛应用的跨平台三维图形绘制引擎,也是当前事实上应用最广泛的三维图形标准[1].OpenGL的一个显著特点是它独立于操作系统、窗口系统和硬件系统环境,这种运行平台的无关性造就了OpenGL的成功,但同时也为OpenGL应用开发带来了不便.OpenGL程序员必须利用不同操作系统平台提供的图形用户界面(Graphics User Interface,GUI)支持函数,才能开发OpenGL应用[3],而掌握相关既定窗口系统的接口功能函数和可视化编程方法,通常需要较长时间的学习[4].为了解决初学者的这一困难,美国Silicon Graphics公司的MARK K开发了一个简易的窗口系统工具包GLUT(OpenGL Utility Toolkit)[5].GLUT是 一 个跨平台的轻量级窗口系统,能够满足一般图形应用的开发要求.由于几乎所有操作系统上都标配了GLUT包,因此以GLUT为基础的OpenGL程序可以不加修改地运行于不同平台,如Windows、Linux和Mac等.
然而,GLUT仅提供了简单的事件处理功能,并不支持单复选按钮、拖动条、组合框、文本框等控件,更没有提供类似于下拉菜单和对话框等图形用户界面元素[5].这给基于OpenGL和GLUT开发图形应用程序的用户带来了不便.在通常情形下,大多数图形应用程序需要通过GUI实现对图形绘制过程的交互式控制[6],以增加相关程序的灵活性和界面友好性.
另一方面,OpenGL具有强大的图形处理能力,能够胜任GUI所需的所有绘制功能.因此可以借助GLUT的窗口事件处理功能,并配合OpenGL绘制功能实现自己所需的图形控件,为应用程序提供个性化的图形用户界面.
本文在分析GLUT事件处理过程和OpenGL绘制功能的基础上,以实例讨论如何基于二者来构造图形控件的问题.所有的控件均采用C++类进行封装,并提供必要的接口函数对它们进行控制.本文实现的图形控件C++类具有高可复用性.
现代操作系统均为用户提供了易于操作、用户友好的图形用户界面[3,7].运行于其上的应用一般提供了按钮、滑动条、文本框、单选和复选按钮等,使用户可以通过拖动鼠标等简单操作完成对相关程序运行参数的选择或调节.
对用户而言,其对程序的控制主要是通过图形控件提供的界面来实现的;在一般用户的认识中,应用程序在屏幕上绘制出的有形控件便是程序本身.本节以滑动条、单选和复选按钮三种控件讨论如何基于OpenGL实现控件的图形界面设计.
图1(a)为Windows系统提供的滑动条控件的外观,其由固定不动的滑动导轨和能够在导轨上左右滑动的控制滑块组成.本节先讨论如何模仿Windows系统的滑动条图形效果.通过观察不难发现,滑动条导轨实质上是由一条黑色线段下衬一条等长的白色线段构成,两条平行线段的两头又绘制了两条黑色和白色短线段进行修饰.由于人类视觉上的原因,最终看到的滑动导轨呈现出一种下凹立体效果.滑动控制块是一个用背景色绘制的矩形块,为了使其呈现出凸出于背景的立体效果,在矩形块的顶端和左侧各绘制了一条白色线段,再在其右侧和底端分别绘制出一条黑色线段.控制块的位置可通过鼠标的拖动进行控制.
图1 标准Windows操作系统图形控件的示例
在知道具体位置的情况下,滑动条控件可以直接运用OpenGL中绘制长方形和线段的命令实现.如下列指令可绘制线段.
图2中,右下侧为本文模仿Windows系统中的滑动条绘制出的控件外观效果,左侧为垂直方向放置的滑动条绘制效果.在设计控件时,实现者可以根据自己的需要,设计具有个性化外观的滑动条.如在图2的右上角,滑动控制块采用了与Windows系统中不同的外观款式,其中滑动导轨也更宽了.
图2 基于OpenGL绘制出各种滑动条的外观
图1(b)为单选控件的可视化界面,它由一组单选按钮及其名称和分组框等部分组成.相对于滑动条的界面外观而言,单选和复选按钮的绘制过程要稍微复杂一点.这里介绍Windows系统下的单选和复选按钮在OpenGL下的实现,其原理同样适用于其他个性化按钮的绘制.
用户将Windows系统下的单选和复选按钮进行放大,可以发现两种按钮的位图表示,参见图3.一旦得到位图,便可以用OpenGL的位图绘制函数来实现控件外观的绘制.
令a∈[0, 255],并用{}a3表示{a,a,a},则{}a3表示整数值的RGB颜色三元组,即为某种灰度.这时,可以通过分析图3得到相关位图的数组表示,其中图3(a)的位图可以表示为二维向量数组icon.
图3 Windows操作系统中单选和复选按钮的位图
需要注意的是,为了适应OpenGL的数据格式要求,图3(a)中位图最后一行的数据位于数组icon的第一行,位图倒数第二行的数据位于数组的第二行,依次类推.
图3(a)为被选中状态的单选按钮图标,图3(b)为被选中状态的复选按钮图标,两者所对应的未被选中状态的按钮图标可以通过用颜色{200}3分别替换位图中央的“十”字和对勾标志处的位图像素得到.
得到相关位图的数组表示,便可利用OpenGL的位图绘制函数进行绘制.具体实现方式如下:
其中,xpos和ypos为放置图标的窗口坐标值.每个单、复选按钮后面都有一个标记选项内容的文字标签,绘制文字标签的任务可由如下OpenGL和GLUT函数完成.
图4为采用以上方法绘制出来的单选和复选按钮图标及相关控件,其中图4(c)为方形单选按钮,中间划“×”表示该按钮处为“选中”状态.
图4 用本文方法绘制出的单选按钮及控件
为使用户能够借助鼠标等设备通过控件界面与应用程序进行互相操作,需将控件界面与窗口事件关联起来[8].本节以滑动条为例进行说明.
滑动条控件通常由鼠标设备控制,并且通过鼠标按键的按下并移动拖动滑块在滑轨上运动改变控件所调节的数值.因此,每当鼠标键(设为左键)按下时,控件必须检测当前的鼠标光标是否落在屏幕滑动条控件所在的区域内.如果鼠标光标未落在该区域内,滑动条控件将不对该事件进行响应;如果鼠标光标落在了该区域内,则说明用户当前按下鼠标的行为是想拖动滑动条的滑块运动,这时将滑动条控件设置为激活状态.激活状态将一直维持到鼠标左键抬起为止.鼠标左键在滑动条区域内按下时,控件被激活;鼠标左键松开抬起时,控件由激活状态转为睡眠状态.
当滑动条控件处在激活状态(鼠标左键被按下)时,如果用户移动鼠标,说明用户欲通过移动滑块调整滑动条表示的值.在基于GLUT的应用程序中,鼠标运动时GLUT窗口系统将会截获该鼠标运动事件,并将该事件交给先前由glutMouseMotionFunc()所注册的回调函数[9]处理.该回调函数将会得到由系统传给它的包含当前鼠标光标在应用程序窗口中坐标的反馈信息.为了使控件能够针对鼠标的运动情况调节滑块的位置,需将控件响应鼠标运动的函数放在该回调函数中进行调用,并仅在控件处在激活状态时执行调节滑块的功能(即对左键未按下时的鼠标运动不作响应).由于该响应函数可以得到鼠标光标在屏幕上的实时位置,故其可通过该光标位置信息修改滑块当前位置所表示的数值.
当鼠标滑块表示的值被修改时,控件将触发一个窗口重绘的系统请求,该事件使窗口系统进一步调用控件图形界面的绘制函数,重新绘制控件界面,并在新的位置绘制控件滑块.于是对用户而言,界面所产生的效果即为其按下鼠标键的操作“拖动”控件滑块运行,并通过调节滑块的位置确定自己所要的数值.
滑动条所调节数值的范围,以及滑块变动所引起数值变化的幅度,均是由封装该控件的类内部变量决定.控件外部可以通过该类所提供的公共成员函数引用或修改这些变量以及滑块表示的值,从而最终达到使应用程序相关变量改变的目的.
本文给出的滑动条控件类的定义如下,相关变量和成员函数的意义在程序的注释中给出.
以set-开头的函数的主要功能是设置滑动条内部参数的值,如函数setPosition()用来设定滑动条左上角位置在窗口坐标系中的坐标值,setLength()用来设置绘制出的滑动条长度,setRange()用来设置滑动条调节的数值范围;函数value()返回当前滑块位置所对应的调节值.show()、button()、slide()三个函数用来响应鼠标事件[1,2,6],其中show()用来绘制滑动条的可视化外观,其在基于GLUT的应用程序中,由glutDisplayFunc()所注册的绘制回调函数调用,而button()和slide()则分别由经glutMouseFunc()和glutMotionFunc()所注册的响应鼠标事件的回调函数调用.
其他控件均可以采用类似方法实现.由于采用了面向对象方法对所有控件分别进行C++类封装,故可由每一控件类定义若干实体对象,各对象之间相对独立而不会相互干扰,对外为用户提供了与应用程序进行交互的界面和接口;同时,面向对象方法也使这些控件能够在同一应用或不同应用中得到高度复用.
设计人员基于OpenGL和GLUT,在Visual C++6.0环境下开发并实现了标签(Label)、滑动条、单选和复选、文本框等一系列控件.所有控件均以C++类的形式进行封装,并对外提供简单易用接口.
在图5中,设计人员给出了两张以本文控件作为图形用户界面的程序运行效果截图.程序主窗口的工作区被分为两部分:左侧大部分为图形绘制区,右侧部分为控件绘制区.其中图形绘制区为主窗口的子窗口,它注册了属于自己的回调函数,子窗口对各类事件的响应均由它自己的回调函数完成;控件绘制区中的所有控件均由主窗口所注册的相关回调函数驱动,主窗口通过这些控件的接口函数获取其当前状态参数,并适时向子窗口传递(可通过全局变量或公共缓冲区等实现),控制图形绘制区的绘图行为.因此,除了相关参数的传递外,主窗口和子窗口的事件处理过程是绝缘的,这种处理简化了程序开发过程,降低了图形用户界面开发的难度和复杂性.
图5 配备本文控件的应用程序界面
图5(a)和图5(b)右侧的控件绘制区中,从上至下依次放置了标签、单选、水平和垂直滑动条3类控件.其中单选控件用来确定绘制图形的形状,可分别选择茶壶、球体、圆环等6种形体;三个水平滑动条分别用来调节图形绘制区背景颜色RGB分量的值,取值范围均为[0,1],当前RGB值进一步由控件绘制区最上面的三个标签控件以文字形式进行显示;而三个垂直滑动条控件分别用来控制所绘制的图形绕坐标系的X、Y、Z轴的旋转角度,取值范围均为[0,360].在图5(a)中,程序在白色背景上绘制了一个茶壶模型;而在图5(b)中,通过单选控件选择了绘制圆环,并通过调节控制颜色和旋转的滑动条改变了工作区中的背景和绘制图形的旋转角度.
本文给出一种基于OpenGL和GLUT图形用户界面可视化控件实验的实现方法,讨论了控件的外观绘制方法和控件的事件驱动机制,并实现了相关控件面向对象的设计和实现,并以实例展示了部分控件的应用.实验表明,本文方法制作的控件响应窗口事件的速度快捷,易学易用,易于操作,且可复用性好,适用于轻量级交互式图形应用程序的开发.