第一篇:Java AWT编程总结
1.什么是GUI?
a)GUI是Graphics User Interface的全称,意思是图形用户界面.2.为什么需要GUI?
a)图形用户界面能够让最终用户通过鼠标拖动、单击等动作就可以操作整个应用,从而提高应用的用户体验效果,使程序受到用户的欢迎.3.Java通过AWT和SWING来完成GUI图形用户界面编程.4.AWT
a)AWT是SUN公司提供的一个基本的GUI类库,被称为抽象工具集(Abstract
Window-Toolkit),它为Java应用程序提供了基本的组件.b)AWT组件需要调用运行平台的图形界面来创建和平台一致的对等体,所以AWT只
能使用所有平台都支持的公共组件,因此AWT只能够提供一些 常用的GUI组件.5.AWT的主要组成部分
a)Component,代表一个具体图形表示能力的对象,可以在屏幕上显示,并与用户交互.通常我们把它称为”组件”.b)MenuComponent,代表图形界面的菜单.i.MenuBar,代表菜单条.ii.Menu,代表一个菜单项的集合.iii.MenuItem,代表一个菜单项.c)Container,代表一个AWT组件容器,可以盛装其他Commponent组件,它继承自
Component抽象类,本身也代表一个Component组件.i.Window,可独立存在的顶级窗口.1.Frame,代表一个窗体.2.Dialog,代表一个对话框
a)FileDialog代表一个文件对话框,用于打开或保存文件.Panel,可容纳其他组件,但不能独立存在,必须被添加到其他容器中.ii.iii.ScrollPane,带滚动条的容器.d)LayoutManager,布局管理器,表示容器管理其他组件的方式.i.ii.iii.iv.v.vi.FlowLayout,流式布局,类似于Window平台记事本的文本布局方式.BorderLayout,边框布局,只能盛装5个组件,这5个组件分别位于边框布局容器的东西南北中五个方位.GridLayout,网格布局,将组件以网格形式显示在容器中.GridBagLayout,网格包布局,一种较为复杂的布局管理器,依赖GridBagConstraints来约束组件.CardLayout,卡片布局,以时间来管理容器内的组件,将组件看作是一张张卡片,每次显示最外面一张卡片(组件).BoxLayou,箱式布局,通常与Box容器结合使用.6.AWT 的事件
a)应用程序响应用户的某个动作或请求,如用户单击了一下鼠标,用户请求关闭应用
程序窗口等.b)AWT编程中,所有事件的处理都必须交给特定的对象来完成,我们将这个特定的对
象称为事件监听器.c)AWT的事件处理机制是一种委派式的事件处理方式,通过将某个事件监听器注册
到用户指定的组件,当用户进行某个操作并触发指定事件时,应用程序会自动产生一个事件(Event)对象并作为参数传给事件监听器中的事件处理器,然后由事件监
听器通知事件处理器来响应用户,完成用户的请求.d)不同的事件需要不同的事件监听器,不同的监听器需要实现不同的监听器接口.e)事件监听器接口:为某个特定事件定义了响应用户请求的方法,当用户将某个事件
监听器注册到指定组件上以响应特定的事件时,则该事件监听器必须实现对应的事件监听器接口才能对用户的请求进行有效处理.例如,用户点击了鼠标右键,希望打开某个应用程序的右键菜单,则注册到该应用程序上的事件监听器必须实现鼠标事件监听器接口,并实现该接口内部某些方法来完成用户的请求.f)事件适配器,很多时候,我们只需要实现某个事件监听器接口中个别方法就能完成应用程序的实际需求,但实现该事件监听器接口的类必须实现该接口中所有的抽象方法,这会造成代码的冗余.而事件适配器可以帮我们解决这个问题,事件适配器实现了所有的拥有多个抽象方法的事件监听器接口,并空实现了这些接口中所有的抽象方法,所谓空实现,就是方法中没有任何实现代码,因此,我们可以通过继承对应事件监听器接口的事件适配器抽象类,并实现我们感兴趣的方法来完成应用需求即可.g)Java事件处理过程中主要涉及的三类对象
i.事件源,通常为普通组件.ii.事件,通常指用户的某个操作,如单击了一下鼠标,按了一下回车键.iii.事件监听器,负责监听事件源上所发生的事件,并作出响应.h)AWT事件监听器的实现形式
i.ii.内部类形式 顶级类形式
iii.类本身作为事件监听器
iv.匿名内部类形式
v.注:目前最为流行的事件监听器的实现形式是内部类形式和匿名内部类形式.7.AWT绘图
a)AWT绘图的实现过程.i.重写画布类的paint方法,绘图图形.ii.注册事件监听器到指定的组件.iii.调用Component类的repaint方法绘制图形.b)AWT实现绘图主要涉及的对象
i.ii.c)Component类的子类Canvas类,它代表一个画布.Graphics,代表一个画笔,可以在Canvas的子类中绘制用户自订的图形.Image类代表了位图,它的一个主要的实现类BufferedImage是可以访问图形数据
缓冲区,并可以返回一个Graphics对象来绘制该BuuferedImage.d)可以使用ImageIO工具类的ImageReader和ImageWriter读写磁盘上的位图文件.8.AWT的优缺点
a)AWT在许多非桌面环境,如嵌入式设备中有着自己的优势,它的主要优点如下:i.ii.iii.iv.更少的内存:对运行在有限环境中的GUI程序的开发,是合适的。2.更少的启动事件:由于AWT组件是本地由操作系统实现的。绝大多数的二进制代码已经在如系统启动的时候被预装载了,这降低了它的启动事件。3.更好的响应:由于本地组件由操作系统渲染。4.成熟稳定的:能够正常工作并很少使你的程序崩溃。
b)同样它也有不少的缺点
i.ii.iii.更少组件类型:表和树这些重要的组件缺失了。它们是桌面应用程序中普遍使用的。2.缺乏丰富的组件特征:按钮不支持图片。3.无扩展性:AWT的组件是本地组件。JVM中的AWT类实例实际只是包含本地
组件的引用。唯一的扩展点是AWT的Canvas组件,可以从零开始创建自定义组
件。然而无法继承和重用一个已有的AWT组件
9.AWT总结:AWT是SUN不推荐使用的工具集,实际开发中很少使用AWT而是使用SUN公司
和Netscape公司共同开发的一个新的用户界面库-Swing来开发GUI应用程序,AWT是图形用户界面编程的基础,它的布局管理、事件机制、剪贴板操作等内容仍然适用于Swing GUI编程.
第二篇:Mudos编程总结[推荐]
Mudos编程总结
1,Mudos系统调用系统 MudLib系统文件 的过程和一些特点
Mudos启动以后先要寻找一个配置文件,用来配置MudLib文件系统的一些信息(这里时config.cfg),找不到就无法启动。找到以后根据配置文件里面的参数进行初始化Mudos,然后调用配置文件里面的两个入口文件,即simul_efun.c和master.c。首先载入simul_efun文件并生成一个特殊的全局对象,这个对象用于定义一些全局使用的函数,也可以重载Mudos中的Efun函数,这些新定义的文件使用起来和Efun是一样的。然后系统会调用master.c文件并生成一个全局对象(主控对象),主控对象用于系统的全局控制,包括全局对象的加载,错误信息的跟踪处理等。接下来,系统会根据主控对象中的定义,载入一些系统需要用到的全局对象。到此,Mudos系统就启动完成了。
2、用户连接系统后的处理过程。。
当用户通过客户端进行连接以后,Mudos系统会调用master对象特有的connect()函数,通过这个函数编程人员需要创建并返回一个用户对象,系统会将用户连接到这个用户对象上,即是说这个用户对象就代表了这个用户。到此,就算完成了用户的连接过程。
3、用户的登陆后的处理过程
当Mudos系统调用master的connect函数创建并返回一个用户对象以后,用户对象会调用特有的logon()函数,这个函数用来把用户的设置都设置好并进行游戏。注:最好在这里重新建立一个用户对象,然后通过exec函数把用户的连接转移到新的对象上,然后删除这个对象。
4、Mudos系统中的系统中 对象
simul_efun对象、master主控对象和用户对象这三种对象都是系统提供的特殊对象,其 中simul_efun对象和master主控对象在系统中只有一个实例,即不能被clone也不能new创建,而用户对象主要的作用就是用来创建用户并完成初始化的对象,用户每次登陆都会自动生成一个,用户登陆完成后最好删除它。这里需要指出主控对象和用户对象都有特有的一些函数,这些函数提供给Mudos系统来调用的,用来完成一些系统需要处理的事情。
5、Master主控对象
object connect()程序连接后调用的函数,创建并返回一个用户对象。string *epilog(int load_empty)返回一个包含物件文件名称的数组, 其中所有的文件为启动游戏之前必须预先载入的对象.void preload(string file)系统按照epilog函数返回的数组载入全局对象后调用次函数,用来判断对象是否成功创建 static void crash(string error, object command_giver, object current_object)当系统异常终止(crash)时, 就调用主控物件中的此函数,用来记录一些系统crash的log信息。void log_error(string file, string message)编译程序发生任何错误系统都会调用此函数,用于发现是哪个对象出了什么错误。用于记录编译程序时出现的错误信息。
string error_handler(mapping error, int caught)主控物件处理错误的函数,此函数让 mudlib 代替系统处理错误情形。用来处理系统运行时出现的错误信息。string get_root_uid()取得
root 使用者识别名称需要获取系统的uid时调用此函数。string get_bb_uid()取得骨架使用者识别名称。string creator_file(string str)系统创建任何对象时都会调用此函数,用来获得系统初始化对象的uid值。mixed compile_object(string file)提供虚拟对象,当系统无法按照给定的路径载入对象时调用此函数。如果返回值是0,系统将不会载入这个对象,如果返回值是一个对象,系统会把这个对象当作是系统要载入的对象。一般来说,这里会返回一个void对象。string object_name(object ob)系统调用此函数以知晓一个物件的名称。string domain_file(string str)返回一个指定对象所属的区域,系统调用此函数来获得对象的区域。string author_file(string str)返回一个指定对象所属的作者,系统调用此函数来获得对象的作者。int save_ed_setup(object who, int code)ed()函数储存一个使用者的编辑程序设定或组态设定时调用 int retrieve_ed_setup(object who)ed()函数取得使用者的编辑程序设定或组态设定 string make_path_absolute(string file)ed()函数调用此函数以转换文件的相对路径名称为绝对路径名称 string get_save_file_name(string fname)ed()函数使用者不正常断线时, 此函数应返回与原来文件不同的名称, 以免覆写原来的文件 string privs_file(string file)为新创造的对象指定一个私有字符串。创建任何对象时系统都会调用此函数.对象的文件名称为其参数,返回的字符串就用作此对象的私有字符串。void slow_shutdown(int minutes)告知 mud 目前正处于缓慢关闭的过程中.当系统无法从堆中配置更多的内存, 而只能使用保留的内存区块时, 主控物件会调用此函数.此函数只有在组态文件中设定了「内存区块保留大小」才会被调用.距离关闭时间还剩下几分钟则为此函数的参数.void flag(string)当系统启动时, 处理 mudlib 所指定的特定标志.这个函数暂时还不是很了解。int valid_override(string file, string name)是否允许使用 efun:: 的情形,即是否允许运行efun重载前的函数。int valid_seteuid(object ob, string str)是否允许设定一个对象的euid。int valid_socket(object eff_user, string fun, mixed *info)是否允许调用socket 外部函数 int valid_asm(string file)
是否能使用asm{}来控制 LPC->C 编译的物件 int valid_compile_to_c(string file)是否允许由 LPC->C 的方式编译 int valid_hide(object who)是否允许一个对象具有匿踪和看到匿踪对象的能力 int valid_object(object ob)是否允许载入某个对象。int valid_save_binary(string filename)是否允许一个对象储存它的源代码 int valid_bind(object binder, object old_owner, object new_owner)是否允许bind()函数 即把某个对象的函数指针指向其他对象。int valid_write(string file, mixed user, string func)是否允许一个人有权限写入一个文件 int valid_read(string file, mixed user, string func)是否允许一个人有权限读取一个文件 int valid_shadow(object ob)控制哪些对象可以作为投影。int valid_link(string original, string reference)是否允许link()函数 int view_errors(object user)是否允许一个使用者看到错误消息 int valid_compile(string file)是否允许预先编译文件,这是22.2b14新加的设置6、、、、用户对象
void logon()主控对象conncet函数返回的用户对象会直接调用次函数,用以对用户对象的初始化处理。string process_input(string str)用户输入信息后调用此函数,字符串处理后再传递给本用户对象,用来处理用户输入信息。void net_dead()当用户对象断线时, 系统调用此函数。用来处理用户断线后的事情。void terminal_type(string term_type)用户对象登陆后调用,获得用户登陆的终端型号。void receive_message(string type, string str)用户对象的消息处理函数,系统的message()函数会把消息分配给各个符合条件的用户对象,用户对象接收到消息后调用此函数来接收并处理消息。void catch_tell(string message);无论系统对
一个对象送出任何消息都会调用此函数来处理这些消息.消息可以依照需要显示、丢弃、修改.此函数可以当作耳罩挡住某些消息, 也可以用于消息处理程序.void receive_snoop(string message);一个用户对象窥视另一个用户对象时, 所有窥视的文字会传递给用户对象中的这个函数.在此函数中, 您可以处理这些文字.次函数的内容, 通常会再传递给 receive()函数.void telnet_suboption(string buffer);
获得用户终端的一些设置。void write_prompt(void);如果在用户对象中有定义了次函数,则预设的提示符号该显示时, 系统将调用此函数.当用户正处于 input_to(输入文字)和 ed(编辑程序)状态时, 系统不会调用此函数7、、、、所有对象
void create(void);对象的构造函数,对象被系统载入后调用此函数来初始化对象。复制的对象也会调用。需要说明的是,系统第一次载入对象后会自动运行对象和其所有的父类中的create,复制的对象只运行对象自己的create。int id(string an_id);此函数被系统的present()函数调用, 以判断一个指定的对象是否以字符串an_id为识别名称id.如果an_id是此对象的识别名称之一, 就返回 1, 不是则返回 0。void init(void);当系统把对象A放入对象B时(即调用move_object()函数),如果A是人物对象,让A在B里调用A的init函数,同时调用B里面所有对象的init函数。不管A是不是人物对象,让B里所有人物对象调用A的init函数。int move_or_destruct(object dest);如果一个对象的环境对象被摧毁了, 就调用此函数, 并用于它的内容对象.dest是正要被摧毁的对象.如果 dest 不存在, 则 dest 为 0.如果 dest 中的对象没有把自己移出被摧毁的对象, 则也会被一起摧毁.int clean_up(int inherited);系统每过一段时间,对非激活对象调用 clean_up()函数.inherited指出此对象是否有别的对象继承.如果返回 0,此对象将永远不再调用 clean_up().如果返回 1, 则继续判断调用。通常一个对象在 clean_up()中所作的事, 是摧毁自己以节省内存.void reset(void);系统在每次reset之后(时间由系统设定),所有游戏中现存的对象都会调用reset()函数.reset()常用于检查宝物或怪物是否还在某个房间, 以判断要不要重新产生一份.8、、、、一些概念的说明
用户对象用户对象用户对象用户对象((((interactive()):):):):用户连接的对象就是用户对象,系统会调用用户对象的一些方法来实现用户的输入输出和消息处理等。如果用户对象断开连接,用户对象就变成为普通对象。但是系统会记录曾经是用户对象的对象,通过userp()函数可以判断一个对象是否曾经是用户对象。人物人物人物人物对象对象对象对象(living())::::人物对象是曾经呼叫过 enable_commands()的对象,当然用户对象也是人物对象。环境对象环境对象环境对象环境对象(environment())::::环境对象是通过move_object()函数激活的对象。激活激活激活激活对象对象对象对象::::在系统规定的(clear_up)时间内,曾经调用过init()函数的对象。复制复制复制复制对象对象对象对象(clonep())::::系统在第一次载入某个对象后会建立一个初始对象并存于系统内存中,以后每次重新建立对象包括new()、clone_object()、call_other()等都会通过拷贝这个初始对象来建立新的对象,每个拷贝出来的对象,系统都会指定一个递增的数字标识此对象。这里需要说明的是,new()等函数建立对象时,如果初始对象不存在的话,系统会自动载入并初始化此对象,并把此对象定为初始对象,然后再拷贝一个对象作为new()等函数的返回值。系统建立初始对象的时候会由父到子的调用对象所有的create()函数,而拷贝出来的对象只调用对象本身的create()函数。游戏中存在的对象都是复制出来的对象。初始对象只有系统才能调用。
对象对象对象对象uid值值值值::::这个值只能通过主控对象中的creator_file()函数赋值或者export_uid()函数传递。指明当前对象的使用者名称。对象对象对象对象euid值值值值::::对象有效的使用者名称,可以通过seteuid和geteuid函数设置和读取。对象的对象的对象的对象的继承继承继承继承、、、、构造及初始化构造及初始化构造及初始化构造及初始化::::Mudos启动以后,可以自动或者通过函数调用来创建和复制各种对象,Mudos系统的作用就是用来管理这些对象。Mudos在生成对象的时候有两种方式,一种是载入对象,一种是复制已经载入的对象。首先,Mudos是通过对象的文件名来寻找和定位对象的,当需要载入对象的时候,先检查对象是否已经载入,如果没有载入会检查对象是否有需要继承别的对象,如果需要就先载入需要继承的对象,然后再载入并生成需要载入的对象。对象的继承实际上是子对象先浅拷贝一份父对象(但不初始化),然后再构造自己。任何一个对象被载入内存或被复制出来都会执行create函数来初始化自己。9、、、、EFUN函数说明
This_object():这个函数返回由当前文件所建立或拷贝的对象。如果这个文件继承了另一个文件,那么另一个文件中的这个函数也返回由这个文件所建立或拷贝的对象。previous_object(n):返回调用此函数的第前n个对象,previous_object(0)= previous_object(),表示返回调用此函数的对象。This_interactive():返回调用此函数的用户对象。This_player():返回调用此函数的人物对象。This_player(1)返回This_interactive()Load_object():如果已经载入则返回已经载入的对象,否则载入对象并返回它。New():如果对象没载入则载入对象,并复制一个对象返回,否则复制已经载入的对象返回。这里需要指出的是复制对象的过程并不会载入被复制对象所要继承的对象。Clone_object():和new一样,目前不知道有什么区别。replace_program():这个函数是用当前对象的继承对象来替换当前对象,但是保留当前对象的全局变量。就是说如果被替换以后,当前对象就只有继承对象的方法,而当前对象所定义的方法都不存在了。
第三篇:描述性编程总结(范文)
一、描述性编程
1、QTP的运行原理
封装被测对象(TO)到对象仓库
对比对象仓库里的对象属性(TO)和运行时的真实被测对象的属性(RO)对比一致后,找得到相应的对象(RO),按照脚本驱动对象
2、RO & TO
TO:Test object 仓库对象
Ro:Runtime object 运行时对象
TO包含RO
Cancel button
text:TO:Cancel|取消
text:RO:Cancelor取消
3、GetTOProperty获取TO的属性值
属性值=GetTOProperty(“属性名”)
4、GetROProperty 获得RO的属性值
属性值=GetROProperty(“属性名”)
5、GetTOProperties 返回值是对象的集合(Set)
Set pops=GetTOProperties
For i=0 to pops.count-1
Pops(i).name获得属性名
Pops(i).value获得属性值
Next
.Count获得组合的总数
6、SetToProperty设置TO属性值
SetTOProperty “属性名”,”属性值”(runtime)
二、描述性编程
1、初级描述性编程(直描)
Object.(“属性名:=属性值”,” 属性名:=属性值”…)
Object:被测对象(类型)
Index2、代码简化
A.赋值给变量(set)
B.With…End With
With object
.statements
End With3、高级描述性编程(description)
Set mydes=description.create()
Mydes(“属性名”).value=”属性值”
Mydes(“属性名”).value=”属性值”
Dialog(“Login”).WinButton(mydes).Click4、ChildObjects
Set ChildO=ChildObjects(mydes)
Set ChilO=Dialog(“Login”).ChildObjects(mydes).count
For i=0 to ChildO.count-1
ChildO(i).click
next
第四篇:一点Duilib编程总结
一点Duilib编程总结
1.duilib简介
duilib是一个开源的DirectUI界面库,简洁但是功能强大。而且还是BSD的license,所以即便是在商业上,大家也可以安心使用。
现在大家可以从这个网站获取到他们所有的源码:/p/duilib/ 为了让我们能更简单的了解其机制,我们按照如下顺序一步一步的来对他进行观察:
工具库:用于支撑整个项目的基础
控件库:这是dui最关键的部分之一,相信也是大家最关注的部分之一,另外这里也来看看它是如何管理这些控件的
消息流转:有了控件库,我们需要将Windows窗口的原生消息流转给这些控件,另外在这里也来看看Focus,Capture等等的实现
资源组织和皮肤加载:有了上面所有的这些,我们再来看看它是如何自动创建皮肤的
简单使用:最后,来看看到底要如何使用它
以下是duilib工程带的一副总体设计图,在看代码之前看看这幅图,对看代码会很有帮助。
duilib: 2.工具库
由于duilib没有对外部的任何库进行依赖,所以在其内部实现了很多用于支撑项目的基础类,这些类分布在Util文件夹中:
UI相关:CPoint/CSize/CDuiRect 简单容器:CStdPtrArray/CStdValArray/CStdString/CStdStringPtrMap 上面这些类看名字就基本能够理解其具体的含义了,当然除了基本的基础库,还有一些和窗口使用相关的工具的封装:
窗口工具:WindowImplBase,这个工具我们在这里不详述,后面会再次提到。3.控件库
控件库在duilib的实现中被分为了两块:Core和Control:
Core中包含的是所有控件公用的部分,里面主要是一些基类和绘制的封装。Control中包含的就是各个不同的控件的行为了。Core部分和控件相关的类图非常简单: duilib-core: 3.1.控件基类:CControlUI CControlUI在整个控件体系中非常重要,它是所有控件的基类,也是组成控件树的基本元素,控件树中所有的节点都是一个CControlUI。
他基本包括了所有控件公共的属性,如:位置,大小,颜色,是否有焦点,是否被启用,等等等等。当然这个类中还提供了非常多的基础函数,用于重载来实现子控件,如获取控件名称和ClassName,是否显示,等等等等。
另外为了方便从XML中直接解析出控件的各个属性,这个类中还在提供了一个SetAttribute的方法,传入字符串的属性名称和值对特定的属性进行设置,内部其实就是挨个比较字符串去完成的,所以平时使用的时候就还是不要使用的比较好了,因为每个属性实际上都有特定的方法来获取和设置。
另外每个控件中还有几个事件管理的对象——CEventSource,这些对象会在特定的时机被触发,如OnInit,调用其中保存的各个回调函数。3.1.1.控件类型转换
这里我们就碰到一个问题,控件树中的每一个节点都是CControlUI,但是其实这些节点可能是文字,可能是图像,也有可能是列表,那么他怎么在这些控件指针之间进行转换呢?
强制转型不是一个好的选择,duilib中使用的是CControlUI::GetInterface,传入一个字符串,传出指向控件的指针。类似于COM的QueryInterface。
LPVOIDCControlUI::GetInterface(LPCTSTRpstrName){ if(_tcscmp(pstrName,_T(“Control”))==0)returnthis;returnNULL;} 3.2.容器基类:CContainerUI 有了基本的控件基类之后,我们就需要容器来将他管理起来,这个容器就是CContainerUI,其内部用一个数组来保存所有的CControlUI的对象,后续的所有工作,就都是基于这个对象来进行的了。
这样在CContainerUI里面,主要实现了一下几个功能: 子控件的查找:CContainerUI::FindControl 子控件的生命周期管理:是否销毁(在Remove的时候自动销毁)/是否延迟销毁(交给CPaintMangerUI去一起销毁)。
滚动条:所有的容器都支持滚动条,在其内部会对键盘和鼠标滚轮事件进行处理(CContainerUI::DoEvent),对其内部所有的元素调整位置,最后在绘制的时候实现滚动的效果
绘制:由于容器中有很多元素,所以为了加快容器的绘制,绘制的时候会获取其真正需要绘制的区域,如果子控件不在此区域中,那么就不予绘制了
3.3.控件实现
有了普通的基类和容器的基类之后,我们就可以在其之上搭建控件了。其类图大致如下:
duilib-control: 3.3.1.基本控件
duilib实现了非常多的基本控件,他们分布在Control文件夹下,每一个头文件就是一个控件,主要有:
CLabelUI/CTextUI/CEditUI/CRichEditUI CButtonUI/CCheckBoxUI/COptionUI(RadioButton)CScrollBarUI/CProgressUI/CSliderUI CListUI CDateTimeUI/CActiveXUI/CWebBrowserUI 3.3.2.Layout 除了基本控件之外,duilib为了辅助大家对界面元素进行布局,还在中间实现了专门用于Layout的元素:
CChildLayoutUI CHorizontalLayoutUI/CVerticalLayoutUI/CTileLayoutUI:纵向排列,横向排列格子排列
CTabLayoutUI:Tab 3.3.3.控件绘制
绘制控件实际上有很多代码都是可以抽取出来的,比如:九宫格拉伸图片,平铺图片等等工作,我们实际上都不需要每次都去重写。所以这部分代码被抽取出来,形成了CRenderEngine,这个类在Core/UIRender下。在这个里面,我们可以看到很多的用于绘制方法。
classUILIB_APICRenderEngine { public: //......staticvoidDrawLine(HDChDC,constRECT&rc,intnSize,DWORDdwPenColor);staticvoidDrawRect(HDChDC,constRECT&rc,intnSize,DWORDdwPenColor);staticvoidDrawRoundRect(HDChDC,constRECT&rc,intwidth,intheight,intnSize,DWORDdwPenColor);staticvoidDrawText(HDChDC,CPaintManagerUI*pManager,RECT&rc,LPCTSTRpstrText, DWORDdwTextColor,intiFont,UINTuStyle);staticvoidDrawHtmlText(HDChDC,CPaintManagerUI*pManager,RECT&rc,LPCTSTRpstrText, DWORDdwTextColor,RECT*pLinks,CDuiString*sLinks,int&nLinkRects,UINTuStyle);//......};3.4.控件管理:CPaintManagerUI 当所有这些基本的控件都准备好了之后,我们就只要将这些控件管理起来,这样一个基本的控件库就完成了,而这个管理就是CPaintManagerUI来负责的。
在duilib中,一个Windows的原生窗口和一个CPaintManagerUI一一对应。其主要负责如下几个内容,后面会分开来细说,现在先了解一个概念就行:
控件管理 资源管理
转化并分发Windows原生的窗口消息 为了实现上面这些功能,其中有几个用于管理控件和资源的关键的数据结构: m_pRoot:保存根控件的节点
m_mNameHash:保存控件名称Hash和控件对象指针的关系
m_mOptionGroup:保存控件相关的Group,这个Group并不是TabOrder,他用于实现Option控件
m_aCustomFonts:用来管理字体资源 m_mImageHash:用来管理图片资源
这些结构基本都可以看作是一堆列表和Map,这样可以用其来实现控件和资源的管理了。
4.消息流转 有了控件,现在我们的问题是,如何将原生的窗口消息分发给界面中所有的控件,使其行为和原生的一样呢?
4.1.窗口基础类:CWindowWnd 在duilib中,用来表示窗口的最基础的类是CWindowWnd,在这个类中实现了如下基本的内容:
原生窗口的创建(CWindowWnd::Create)Subclass(CWindowWnd::Subclass)
最基本的消息处理函数(CWindowWnd::__WndProc)和消息分发(CWindowWnd::HandleMessage)
模态窗口(CWindowWnd::ShowModal)
duilib通过这个类,将原生窗口的消息分发给其派生类,最后传给整个控件体系。另外在duilib中,需要进行消息处理的基本控件,都是从这个类继承出来的。
4.2.消息分发
一旦我们使用CWindowWnd类创建了窗口之后,消息就会通过CWindowWnd::HandleMessage进行分发,我们可以和WTL等其他的库一样,在此对原始的窗口消息进行处理。
LRESULTCWindowWnd::HandleMessage(UINTuMsg,WPARAMwParam,LPARAMlParam){ return�0�2::CallWindowProc(m_OldWndProc,m_hWnd,uMsg,wParam,lParam);} 当然如果我们觉得这样麻烦,我们也可以使用CPaintManagerUI来对其进行默认处理。我们上面提到CPaintManagerUI还会对所有的控件进行管理,这样,消息就传递给了窗口内部特定的控件了。
这些默认处理集中在CPaintManagerUI::MessageHandler()中,其内部会对很多窗口消息进行处理,并将其分发到对应的控件上去,比如对WM_LBUTTONDOWN的处理。
caseWM_LBUTTONDOWN: { //......POINTpt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};m_ptLastMousePos=pt;CControlUI*pControl=FindControl(pt);//......TEventUIevent={0};event.Type=UIEVENT_BUTTONDOWN;//......pControl->Event(event);} break;4.2.1.Focus&Capture 通过上面这个最简单的例子,我们基本可以猜到duilib对Focus和Capture的处理方法了:用一个成员变量保存对应的控件,在消息到达时直接转发消息。
在CPaintMainagerUI中,大家可以找到一个成员变量:m_pFocus,这个就是用来保存焦点控件的。在WM_KEYDOWN等键盘消息发生时,duilib就会模拟Windows行为,将消息直接转给当前Focus的控件。caseWM_KEYDOWN: { if(m_pFocus==NULL)break;TEventUIevent={0};event.Type=UIEVENT_KEYDOWN;//...m_pFocus->Event(event);//...} break;但是很奇怪的是,duilib里面并没有对Capture做处理,分发鼠标消息到对应的子控件上,可能是还没有完善的原因。
4.2.2.其他消息分发方式 除了Event以外,CPaintManagerUI还提供了其他几种用于处理消息的方法: Notifier:在窗口上处理一些控件的逻辑,可以将其看成和WM_NOTIFY差不多的功能
PreMessageFilter:消息预处理,这个大家肯定不陌生了。PostPaint:绘制后的回调
TranslateAccelerator:快捷键的处理
这里需要注意的是:PreMessageFilter和TranslateAccelerator是通过全局数组来实现的,这并不符合多线程的窗口编程要求,所以duilib对多线程的支持并不是很好!
4.3.WindowImplBase 为了简化duilib的使用,库中提供了一个非常方便的工具:WindowImplBase。这个类将常用的功能封装在其内部,比如Notifier和PreMessageFilter,并在其中提供了各种默认的虚回调函数,供派生类重载。通过这个类,我们可以非常方便的来实现一个简单的界面。
classUILIB_APIWindowImplBase :publicCWindowWnd ,publicCNotifyPump ,publicINotifyUI ,publicIMessageFilterUI ,publicIDialogBuilderCallback { //......virtualUINTGetClassStyle()const;//......virtualLRESULTOnClose(UINT/*uMsg*/,WPARAM/*wParam*/,LPARAM/*lParam*/,BOOL&bHandled);virtualLRESULTOnDestroy(UINT/*uMsg*/,WPARAM/*wParam*/,LPARAM/*lParam*/,BOOL&bHandled);//......5.资源组织和皮肤加载
好了,现在我们已经有了控件管理和控件库,现在我们需要让UI框架来帮忙组织这些资源,并且自动的来帮我们创建皮肤,减少我们的开发量。
duilib中的皮肤文件主要有几个部分组成: xml描述文件:描述窗口中控件的布局和样式 各种资源如图片
我们把这些资源放在一个文件夹中,这样就形成了基础的皮肤包。当然我们还可以将其组合成一个zip包,从而加快IO访问,但是修改起来就会相对麻烦。所以我们可以在debug中使用前者,而在release中使用后者。
我们可以在binskin下面找到duilib中自带demo的所有的皮肤包。皮肤中,最关键的部分就是这个xml描述文件了,一个xml描述文件对应着一个窗口的信息,如:控件的类型和样式等等。为了有一个直观的印象,我截取了duilib中ListDemo的xml描述文件的一部分放在这里:
<?xmlversion=“1.0”encoding=“utf-8”?>
... 为了通过配置文件自动创建皮肤,duilib提供了一个类:CDialogBuilder(DuiLibCoreUIDlgBuilder.h)。
这个类提供了从皮肤包(文件夹和zip格式)中的xml中创建皮肤的方法:CDialogBuilder::Create。内部实际上就是一个xml的解析,依次创建各式控件。除了创建控件,这个类还将一些可以复用的资源提取出来放入CPaintManagerUI中统一管理,如字体和图片等等。
6.简单使用
由于项目里面实在是带了太多太多的demo,而且在duilib的工程中,还有一个doc的目录,里面也非常详细的描述了要如何使用duilib来创建一个简单的工程。
所以关于duilib的简单使用,这里就不再详述了,这里就只列出GameDemo的main函数,这个函数非常的简单,但是已经基本可以表达了。
intAPIENTRYWinMain(HINSTANCEhInstance,HINSTANCE/*hPrevInstance*/,LPSTR/*lpCmdLine*/,intnCmdShow){ CPaintManagerUI::SetInstance(hInstance);CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath()+_T(“skin”));CPaintManagerUI::SetResourceZip(_T(“GameRes.zip”));HRESULTHr=�0�2::CoInitialize(NULL);if(FAILED(Hr))return0;CGameFrameWnd*pFrame=newCGameFrameWnd();if(pFrame==NULL)return0;pFrame->Create(NULL,_T(""),UI_WNDSTYLE_FRAME,0L,0,0,1024,738);pFrame->CenterWindow();�0�2::ShowWindow(*pFrame,SW_SHOWMAXIMIZED);CPaintManagerUI::MessageLoop();�0�2::CoUninitialize();return0;} 7.总结
总的来说,duilib还是一个很小巧好用的皮肤引擎的,但是他仍然有其不好的地方:对多线程的支持不好,不支持动画。但是无论如何,它还是不错的,所以如果你已经看到了这里,那么接下来跑到vs里面建一个工程,玩一把才是正经事~
第五篇:编程题总结
C作业汇总
1.short a,b=32767;/*short类型在内存中占2B*/ a=b+1;问:a的值是多少?并分析原因。
2.有一4位数整数,假设用abcd表示,请把这个4位数的每个数位用表达式表示出来。3.从键盘输入圆的半径r,计算并输出圆的面积s(要求:半径r定义为float型;圆周率定义为符号常量;面积s保留2位小数)#define PI 3.14159 #include
4.输入m>=3的正整数,判断m是否素数。画出算法流程图及NS图
5.有一函数:
x1 x y2x1 1x10
3x-11 x10 写一段程序,输入x,输出y值。
要求x,y声明为float类型,y保留2位小数。#include
if(x<1)
y=x;else
if(x<10)
y=2*x-1;
else
y=3*x-11;
}
printf(“y=%.2fn”,y);
x3x5x7x9,6.课后习题4.17(P159)利用泰勒级数sinxx计算sinx的3!5!7!9!值。要求最后一项的绝对值小于10,并统计出此时累加了多少项。#include
/*记录每个项数*/ int n=1,count=0;/*count记录累加了多少项*/
printf(“请输入x值(弧度):n”);scanf(“%f”,&x);
term=x/n;while(fabs(term)>1e-5)
/* while循环*/ {
sinx+=term;
count++;
n+=2;
term=-term*x*x/((n-1)*n);}
/* do
/*do while循环*/ {
sinx+=term;
count++;
n+=2;
term=-term*x*x/((n-1)*n);}while(fabs(term)>1e-5);
*/
printf(“sin(%.2f)=%.4fn”,x,sinx);printf(“一共累加了:%d项。n”,count);}
7.用牛顿迭代法求下面方程在1.5附近的根:
2x4x3x60 325
牛顿迭代公式:
x1x0f(x0)f(x0)
#include
/*y1记录f(x0),y2记录f(x0)的导数*/
do {
x0=x1;
y1=2*x0*x0*x0-4*x0*x0+3*x0-6;
y2=6*x0*x0-8*x0+3;
x1=x0-y1/y2;}while(fabs(x1-x0)>1e-5);
printf(“the root is:%.2fn”,x1);}
8.写一函数,输入一个16进制整数,输出相应的10进制数。例:从键盘输入2a,输出结果是42。
要求:若输入数据不合法,则输出提示信息。如输入了35g,输出“您输入的16进制数不合法!”。
#include
printf(“请输入一个16进制数字:n”);
while((c=getchar())!='n'){
if(c>='0' && c<='9')
sum=sum*16+c-'0';
else
if(c>='a' && c<='f')
sum=sum*16+c-87;
else
if(c>='A' && c<='F')
sum=sum*16+c-55;
else
{
printf(“您输入的16进制不合法.n”);
exit(0);
} }
printf(“相应的10进制数是:%dn”,sum);} 方法2:用字符串处理的方式 #include
printf(“请输入一个16进制数字:n”);gets(str);
for(i=0;str[i];i++){
if(str[i]>='0' && str[i]<='9')
sum=sum*16+str[i]-'0';
else
if(str[i]>='a' && str[i]<='f')
sum=sum*16+str[i]-87;
else
if(str[i]>='A' && str[i]<='F')
sum=sum*16+str[i]-55;
else
{
printf(“您输入的16进制不合法.n”);
exit(0);
} }
printf(“相应的10进制数是:%dn”,sum);} 方法3:用字符数组及指针处理的方式 #include
{ char str[20],*p=str;int sum=0;
printf(“请输入一个16进制数字:n”);gets(p);
while(*p){
if(*p>='0' && *p<='9')
sum=sum*16+*p-'0';
else
if(*p>='a' && *p<='f')
sum=sum*16+*p-87;
else
if(*p>='A' && *p<='F')
sum=sum*16+*p-55;
else
{
printf(“您输入的16进制不合法.n”);
exit(0);
}
p++;}
printf(“相应的10进制数是:%dn”,sum);} 9.编写一个小函数,其功能是计算两个整数的平均值,该函数要在主函数中调用。
#include
avg=average(x,y);
printf(“%d,%d的平均值是:%.2fn”,x,y,avg);}
float average(int x,int y)
{ return(x+y)/2.0;}
10.有N(N用宏定义为符号常量)个元素的一维整型数组,该数组中各元素值从键盘随机输入。然后,将这个整型数组中的值逆序存放。例如,原来5个元素的顺序为8、1、4、6、5,逆序之后各元素的值是5、6、4、1、8 #define N 5 #include
printf(“输入%d个整数,用空格或回车分隔:n”,N);for(i=0;i scanf(“%d”,&a[i]); printf(“数组原来的值是:n”);for(i=0;i printf(“%dt”,a[i]); for(i=0;i t=a[i]; a[i]=a[N-1-i]; a[N-1-i]=t;} printf(“n逆序之后数组的值是:n”);for(i=0;i printf(“%dt”,a[i]); printf(“n”);} 11.有N(N用宏定义为符号常量)个元素的一维整型数组,该数组中各元素值从键盘随机输入。然后,对该数组元素进行由小到大排序(要求,该功能用函数实现),输出数组中各元素值。最后,从键盘随机输入一个整数,并把该整数插入上述数组中(该功能用函数实现),使得插入该整数后的数组仍然有序,输出数组中各元素的值。#define N 5 #include int i,x;void sort(int array[],int n);void insert(int array[],int n,int x); printf(“输入%d个整数,用空格或回车分隔:n”,N);for(i=0;i scanf(“%d”,&a[i]); sort(a,N); /*调用sort对数组进行排序*/ printf(“n升序排序之后数组的值是:n”);for(i=0;i printf(“%d ”,a[i]); printf(“n输入一个x值插入到数组中:n”);scanf(“%d”,&x); insert(a,N,x); printf(“n插入%d之后数组的值是:n”,x);for(i=0;i printf(“%d ”,a[i]); printf(“n”);} void sort(int array[],int n)/*用选择法对数组array升序排序*/ { int i,j,t,min; for(i=0;i min=i; for(j=i+1;j if(array[j] min=j; if(min!=i) { t=array[i]; array[i]=array[min]; array[min]=t; } } } void insert(int array[],int n,int x){ int i,pos; for(i=0;i pos=i; for(i=n-1;i>=pos;i--) array[i+1]=array[i]; array[pos]=x;} 12.有一整型数组,N(N用宏定义为符号常量)个元素,该数组中各元素值从键盘随机输入。从键盘随机输入一个整数x,删除该数组中值与x相同的所有元素(该功能用函数实现),输出数组中各元素的值。#define N 5 #include printf(“输入%d个整数,用空格或回车分隔:n”,N);for(i=0;i scanf(“%d”,&a[i]); printf(“数组原来的值是:n”);for(i=0;i printf(“%dt”,a[i]); printf(“n请输入要删除的值x:n”);scanf(“%d”,&x); n=delet(a,N,x); /*n值是删除与x相同的元素后,数组剩余元素的个数。*/ printf(“删除%d之后数组的值是:n”,x);for(i=0;i printf(“%d ”,a[i]); printf(“n”); } int delet(int a[],int n,int x){ int i,j; for(i=0,j=0;i if(a[i]!=x) a[j++]=a[i]; return j;} 13.从键盘随机输入一字符串,将所有ASCII值为偶数的字符输出。例如:输入abc123,输出结果是b2(因为b的ASCII值是98,2的ASCII值是50,其他字符的ASCII值都是奇数) #include printf(“输入字符串:n”);gets(str); printf(“ASCII码是偶数的字符有:”);for(i=0;str[i];i++) if(str[i]%2==0)putchar(str[i]); printf(“n”);} 14.从键盘输入两个字符串s1,s2,把s2连接到s1的末尾。不能用strcat函数 #include printf(“输入两个字符串,输入回车键结束:n”);gets(str1);gets(str2); mystrcat(str1,str2); printf(“连接在一起的字符串是:n”);puts(str1); } void mystrcat(char *p1,char *p2){ while(*p1)p1++;while(*p2) *p1++=*p2++;*p1='';} 15.从键盘输入一个字符串,把其中最长的单词输出。单词定义为连续的一串英文字母。如输入I am a student.输出结果为student #include { char str[80];int i,start,len=0,lenthest=0,lenstart=0;int word=0; printf(“input a string:n”);gets(str); for(i=0;str[i];i++){ if(str[i]>='a' && str[i]<='z' || str[i]>='A'&&str[i]<='Z') if(!word) { word=1; start=i; } else { len++; } else if(word) { word=0; } } if(len>lenthest){ lenthest=len;lenstart=start;} len=0; printf(“the lenthest word is:n”);for(i=lenstart;i<=lenstart+lenthest;i++) putchar(str[i]); printf(“n”);} 16.有一整型数组,N(N用宏定义为符号常量)个元素,该数组中各元素值从键盘随机输入。编写函数calculate,计算出所有元素的最大值、最小值、平均值,结果在主函数中输出。#define N 5 #include printf(“输入%d个整数,用空格或回车分隔:n”,N);for(i=0;i scanf(“%d”,&a[i]); calculate(a,&max,&min,&avg); printf(“数组中所有元素的最大值、最小值、平均值分别是:n”);printf(“最大值max=%d,n”,max);if(word)if(len>lenthest){ lenthest=len; lenstart=start;} printf(“最小值min=%d,n”,min);printf(“平均值avg=%.2f,n”,avg); } void calculate(int a[],int *pmax,int *pmin,float *pavg){ int i;int sum; *pmax=*pmin=sum=a[0]; for(i=1;i if(a[i]>*pmax) *pmax=a[i]; if(a[i]<*pmin) *pmin=a[i]; sum=sum+a[i];} *pavg=(float)sum/N;}