大家都知道,Z让网能够自动地适应用户讄的分辨率Q在|页制作q程中h们采用了癑ֈ比的讄方式Q从而页面的所有元素从新排版,保证原来的格式。但如果你在面上用了层,你会发现当浏览器大小改变Ӟ层的位置却没有改变,l果它和其他的元素之间的配合出现了错位现象,面变得杂ؕ无章了。而我们是不能够强制用户用特定的分L率的Q那么就只有惛_法让层的位置也能够象表格一h据浏览器大小的改变而重新定位,q就需要合理地使用相对定位和绝对定位了?/p>
l对定位Qposition:absoluteQ:卛_默认的定位方式,l对于浏览器左上角的边缘开始计定位数倹{?/p>
相对定位Qposition:relativeQ:层的位置相对于某个元素设|,该元素位|改变,则层的位|相应改变?/p>
Ҏ两种定位方式Q不隑֏玎ͼ使用相对定位的层才是真正实现设计者思想的方式,从而完全掌握层的排版?
那么Q绝对定位有没有用呢Q当然有用了Q当你的|页全部使用层来排版Q而且面是用默认的居左攄的,那么使用默认的绝对定位方式可以方便的排版Q提高设计的工作效率?/p>
在Dreamweaver中,插入的层虽然都是使用的绝对(absoluteQ定位方式,但是插入的方式不同,带来的效果是不同的。前面我们已l知道,使用菜单插入的层是没有定位的坐标的,只有当你使用鼠标拖动该层改变其位|后Q才会写入坐标倹{而拖拉出来的层的初始位置坐标是鼠标开始动作时的坐标?/p>
h一个概念:由Dreanweaver赋予坐标值的层是l对于浏览器边缘定位的层。不带坐标值的层则是相对于某元素定位的层!
所以,最单的讄相对定位层的的方式就是:选定插入层的位置Q例如某个单元格或者页面中某处Q将光标停留在该位置Q然后选择Insert-->LayerQ即可在该位|创Z个固定大的层,q个层就是相对于该位|定位的了。需要注意,采用q种方式创徏的层Q你只可以用鼠标调整它的大,l对不可以移动它的位|!也就是说Q在属性面板上Q层的位|栏中(Left TopQ绝对不可以有数倹{?/p>
很多情况下,插入的层的位|ƈ不一定准,特别是Dreamweaverq真正的所见即所得的软gQ网늚排版只有到浏览器中显C才可以真正看到排版的表玎ͼ所以上面所说的Ҏ显的过于简单而容易出问题了。这个时候,你需要给层一个定位的参照物,让它真正地做到相对的定位?/p>
单的参照物可以是一个父层,卛_插入一个相对定位的I白的层Q在此层中插入你真正需要的层,而这个层是可以随意拖拉改变位|的。但q样毕竟在网中多插入了一个空白的层,我想它一定不是专业的|页设计师所希望的。下面我们介l用CSS来实现真正的相对定位的层?/p>
我们需要先讄一?a >CSS ClassQ来定义定位的方式ؓ相对Q?/p>
.ceng { position: relative; }
然后Q赋予你所需要的参照物(可以?a > table,tr,td... Q一?a > Css属性ؓq个cR这h览器׃以它的左上角为原点,建立新的坐标pR再在这个参照物的下U插入层Q则层绝对于该参照物定位Q如果你需要改变层的位|,你可以直接在层的属性面板上输入Left Top的数|不可以用鼠标拖拉)Q切记此数值的坐标原点是你所指定的参照物Q而不是浏览器的边~(在Dreamweaver中编辑时Q该层看h象是l对于页面边~定位的Q但在浏览器中,它是l对于你所指定的参照物的)?/p>
很多朋友使用层是Z{到动态的效果Q例如用时间线让某个物体运动v来,增加|页的动感,那么相对定位后的层还可以q动吗?回答当然是肯定的。由于定?a >对象的两个位|需要拖动该对象改变位置Q所以用简单的层定位的Ҏ是不行的Q但如果你用CSS来设|相对定位的效果的话Q那么就完全可以实现了。只是需要注意,定义q动的初始位|和l束位置Ӟ你仍然不可以使用鼠标拖拉Q而只能自行输入Left和Top的数倹{?/p>
本来层的使用q不是很复杂的,但我却把它单独作Z个章节,原因是层的定位有一定难度,希望朋友们看q以上的介绍后,在Dreamweaver中多实验几次Q否则还是容易出现问题的?/p>
OKQ关于层的用就说这么多?/p>
本文介绍一U方法,AjaxQ用它可以构徏更ؓ动态和响应更灵敏的Web应用E序。该Ҏ的关键在于对览器端的JavaScript?DHTML和与服务器异步通信的组合。本文也演示了启用这U方法是多么单:利用一个Ajax框架Q指DWRQ构造一个应用程序,它直接从览器与后端服务q行通信。如果用得当,q种强大的力量可以应用E序更加自然和响应灵敏,从而提升用L览体验?/p>
该应用程序中所使用的示例代码已打包为单独的WAR文gQ可供下载?/p>
?/strong>
术语Ajax用来描述一l技术,它ɋ览器可以ؓ用户提供更ؓ自然的浏览体验。在Ajax之前QWeb站点强制用户q入提交/{待/重新昄范例Q用L动作L与服务器?#8220;思考时?#8221;同步。Ajax提供与服务器异步通信的能力,从而用户从请?响应的@环中解脱出来。借助于AjaxQ可以在用户单击按钮Ӟ使用JavaScript和DHTML立即更新UIQƈ向服务器发出异步hQ以执行更新或查询数据库。当hq回Ӟ可以?JavaScript和CSS来相应地更新UIQ而不是刷新整个页面。最重要的是Q用L至不知道览器正在与服务器通信QWeb站点看v来是x响应的?/p>
虽然Ajax所需的基架构已经出现了一D|_但直到最q异步请求的真正威力才得到利用。能够拥有一个响应极其灵敏的Web站点实Ȁ动h心,因ؓ它最l允许开发h员和设计人员使用标准的HTML/CSS/JavaScript堆栈创徏“桌面风格的(desktop-likeQ?#8221;可用性?/p>
通常Q在J2EE中,开发h员过于关注服务和持久性层的开发,以至于用L面的可用性已l落后。在一个典型的J2EE开发周期中Q常怼听到q样的话Q?#8220;我们没有可投入UI的时?#8221;?#8220;不能用HTML实现”。但是,以下Web站点证明Q这些理由再也站不住脚了Q?/p>
所有这些Web站点都告诉我们,Web应用E序不必完全依赖于从服务器重新蝲入页面来向用户呈现更攏V一切似乎就在瞬间发生。简而言之,在涉及到用户界面的响应灵敏度Ӟ基准讑־更高了?/p>
定义Ajax
Adaptive Path公司的Jesse James Garrettq样定义AjaxQ?/p>
Ajax不是一U技术。实际上Q它由几U蓬勃发展的技术以新的强大方式l合而成。Ajax包含Q?/p>
q非常好Q但Z么要以Ajax命名呢?其实术语Ajax是由Jesse James Garrett创造的Q他说它?#8220;Asynchronous JavaScript + XML的简?#8221;?/p>
Ajax的工作原?/strong>
Ajax的核心是JavaScript对象XmlHttpRequest。该对象在Internet Explorer 5中首ơ引入,它是一U支持异步请求的技术。简而言之,XmlHttpRequest使您可以使用JavaScript向服务器提出hq处理响应,而不d用户?/p>
在创建Web站点Ӟ在客L执行屏幕更新为用h供了很大的灵zL。下面是使用Ajax可以完成的功能:
一切皆有可能!但愿它能够激发您开始开发自qZAjax的站炏V然而,在开始之前,让我们介l一个现有的Web站点Q它遵@传统的提?{待/重新昄的范例,我们q将讨论Ajax如何提升用户体验?/p>
Ajax可用于那些场景?——一个例子:MSN Money面
前几天,在浏览MSN Money面的时候,有一?a target=_blank>关于房地产投资的文章引v了我的好奇心。我军_使用站点?#8220;Rate this article”Q评h文)功能Q鼓励其他的用户׃Ҏ间来阅读q篇文章。在我单击vote按钮q等待了一会儿之后Q整个页面被hQ在原来投票问题所在的地方出现了一个漂亮的感谢画面?/p>
而Ajax能够使用L体验更加愉快Q它可以提供响应更加灉|的UIQƈ消除面h所带来的闪烁。目前,׃要刷新整个页面,需要传送大量的数据Q因为必重新发送整个页面。如果用AjaxQ服务器可以q回一个包含了感谢信息?00字节的消息,而不是发?6,813字节的消息来h整个面。即使用的是高速InternetQ传?6K?/2K的差别也非常大。同样重要的是,只需要刷C投票相关的一节Q而不是刷新整个屏q?/p>
让我们利用Ajax实现自己的基本投系l?/p>
原始的AjaxQ直接用XmlHttpRequest
如上所qͼAjax的核心是JavaScript对象XmlHttpRequest。下面的CZ文章评hpȝ带您熟悉Ajax的底层基本知识:http://tearesolutions.com/ajax-demo/raw-ajax.html。注Q如果您已经在本地WebLogic容器中安装了ajax-demo.warQ可以导航到http://localhost:7001/ajax-demo/raw-ajax.htmlQ?/p>
览应用E序Q参与投,q亲眼看它如何运转。熟悉了该应用程序之后,l箋阅读Q进一步了解其工作原理l节?/p> 首先Q您拥有一些简单的定位Ҏ讎ͼ它连接到一个JavaScriptcastVote(rank)函数?
function castVote(rank) { var url = "/ajax-demo/static-article-ranking.html"; var callback = processAjaxResponse; executeXhr(callback, url); }
该函Cؓ您想要与之通信的服务器资源创徏一个URLq调用内部函数executeXhrQ提供一个回调JavaScript函数Q一旦服务器响应可用Q该函数p执行。由于我希望它运行在一个简单的Apache环境中,“cast vote URL”只是一个简单的HTML面。在实际情况中,被调用的URL记录票数ƈ动态地呈现包含投票L的响应?/p> 下一步是发出一个XmlHttpRequesthQ?
function executeXhr(callback, url) { // branch for native XMLHttpRequest object if (window.XMLHttpRequest) { req = new XMLHttpRequest(); req.onreadystatechange = callback; req.open("GET", url, true); req.send(null); } // branch for IE/Windows ActiveX version else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); if (req) { req.onreadystatechange = callback; req.open("GET", url, true); req.send(); } } }
如您所见,执行一个XmlHttpRequestq不单,但非常直观。和q_一P在JavaScript领域Q大部分的工作量都花在确保浏览器兼容斚w。在q种情况下,首先要确定XmlHttpRequest是否可用。如果不能用Q很可能要用Internet ExplorerQ这样就要用所提供的ActiveX实现?/p>
executeXhr()Ҏ中最关键的部分是q两行:
req.onreadystatechange = callback; req.open("GET", url, true);
W一行定义了JavaScript回调函数Q您希望一旦响应就l它p动执行,而req.open()Ҏ中所指定?#8220;true”标志说明您想要异步执行该h?/p> 一旦服务器处理完XmlHttpRequestq返回给览器,使用req.onreadystatechange指派所讄的回调方法将被自动调用?
function processAjaxResponse() { // only if req shows "loaded" if (req.readyState == 4) { // only if "OK" if (req.status == 200) { $('votes').innerHTML = req.responseText; } else { alert("There was a problem retrieving the XML data:\n" + req.statusText); } } }
该代码相当简z,q且使用了几个敎ͼq得难以一下子看出发生了什么。ؓ了弄清楚q一点,下面的表|引用?a target=_blank>http://developer.apple.com/internet/webcontent/xmlhttpreq.htmlQ列举了常用的XmlHttpRequest对象属性?/p>
属?/strong> |
描述 |
onreadystatechange |
每次状态改变所触发事g的事件处理程?/p> |
readyState |
对象状态|
|
responseText |
从服务器q程q回的数据的字符串Ş?/p> |
responseXML |
从服务器q程q回的DOM兼容的文档数据对?/p> |
status |
从服务器q回的数字代码,比如404Q未扑ֈQ或200Q就l) |
statusText |
伴随状态码的字W串信息 |
现在processVoteResponse()函数开始显C出其意义了。它首先查XmlHttpRequest的整体状态以保证它已l完成(readyStatus == 4Q,然后Ҏ服务器的讑֮询问h状态。如果一切正常(status == 200Q?׃用innerHTML属性重写DOM?#8220;votes”节点的内宏V?/p>
既然您亲眼看CXmlHttpRequest对象是如何工作的Q就让我们利用一个旨在简化JavaScript与Java应用E序之间的异步通信的框架来对具体的l节q行抽象?/p>
Ajax: DWR方式
按照与文章评Ll相同的程Q我们将使用Direct Web RemotingQDWRQ框架实现同L功能?/p>
假定文章和投结果存储在一个数据库中,使用某种对象/关系映射技术来完成抽取工作。ؓ了部|v来尽可能地简单,我们不会使用数据库进行持久性存储。此外,Z应用E序可能通用Q也不用Web框架。相反,应用E序从一个静态HTML文g开始,可以认ؓ它由服务器动态地呈现。除了这些简化措施,应用E序q应该用Spring Framework兌一切,以便L看出如何在一?#8220;真实?#8221;应用E序中用DWR?/p>
现在应该下蝲CZ应用E序q熟悉它。该应用E序被压~ؓ标准的WAR文gQ因此您可以把它攄CQ何一个Web容器中——无需q行配置。部|完毕之后,可以导航到http://localhost:7001/ajax_demo/dwr-ajax.html来运行程序?/p>
?. 可用的服?/p> 单击ajaxSampleSvc链接Q查看有兛_何在HTML面内直接用服务的CZ实现。其中包含的两个JavaScript文g完成了大部分的功能:
<script type='text/javascript' src='/ajax-demo/dwr/interface/ajaxSampleSvc.js'></script> <script type='text/javascript' src='/ajax-demo/dwr/engine.js'></script>
ajaxSampleSvc.js是动态生成的Q?/p>
function ajaxSampleSvc() { } ajaxSampleSvc.castVote = function(callback, p0) { DWREngine._execute(callback, '/ajax-demo/dwr', 'ajaxSampleSvc', 'castVote', p0); }
现在可以使用JavaScript对象ajaxSampleSvc替换所有的XmlHttpRequest代码Q从而重构raw-ajax.html文g。可以在dwr-ajax.html文g中看到改动的l果Q下面是新的JavaScript函数Q?/p>
function castVote(rank) { ajaxSampleSvc.castVote(processResponse, rank); } function processResponse(data) { var voteText = "Thanks for Voting!
" + "Current ranking: " + data.voteAverage + " out of 5
" + "Number of votes placed: " + data.numberOfVotes + "
"; $('votes').innerHTML = voteText; }
惊h地简单,不是吗?由ajaxSampleSvc对象q回的Article域对象序列化Z个JavaScript对象Q允许在它上面调用诸如numberOfVotes()和voteAverage()之类的方法。在动态生成ƈ插入到DIV元素“votes”中的HTML代码内用这些数据?/p>
下一步工?/strong>
在后l文章中Q我l有关Ajax的话题,涉及下面q些斚wQ?/p>
像许多技术一PAjax是一把双刃剑。对于一些用例,其应用程序其实没有必要用AjaxQ用了反而有损可用性。我介l一些不适合使用的模式,H出说明Ajax的一些消极方面,q展CZ些有助于~和q些消极斚w的机制。例如,?a >Netflix电媄览?/a>来说QAjax是合适的解决Ҏ吗?或者,如何提示用户实Z一些问题,而再ơ单L钮也无济于事Q?/p>
在用AjaxӞ最初的文档DOM会发生一些变化,q且有大量的面状态信息存储在客户端变量中。当用户跟踪一个链接到应用E序中的另一个页面时Q状态就丢失了。当用户按照惯例单击Back按钮Ӟ呈现l他们的是缓存中的初始页面。这会用户感到非常qhQ?/p>
使用JavaScript在客L执行更多的工作时Q如果事情不按预期方式进行,需要一些调试工h帮助弄清出现了什么问题?/p>
l束?/strong>
本文介绍了AjaxҎQƈ展示了如何用它来创Z个动态且响应灉|的Web应用E序。通过使用DWR框架Q可以轻村֜把Ajax融合到站点中Q而无需担心所有必L行的实际道工作?/p>
特别感谢Getahead IT咨询公司的Joe Walker和他的团队开发出DWRq样奇的工兗感谢你们与世界׃n它!
Java事g处理
从概念上Ԍ事g是一U在"源对??监听者对?之间Q某U状态发生变化的传递机制。事件有许多不同的用途,例如在Windowspȝ中常要处理的鼠标事g、窗口边界改变事件、键盘事件等。在Java中则是定义了一个普通的、可扩充的事件机Ӟq种机制能够Q?/p>
对事件类型和传递的模型的定义和扩充提供一个公共框Ӟq合于广泛的应用?/p>
与Java语言和环境有较高的集成度?/p>
事g能被描述环境捕获和触发?/p>
能其它构造工具采取某U技术在设计时直接控制事Ӟ以及事g源和事g监听者之间的联系?/p>
事g机制本n不依赖于复杂的开发工兗?/p>
事g从事件源到监听者的传递是通过对目标监听者对象的JavaҎ调用q行的。对每个明确的事件的发生Q都相应地定义一个明的JavaҎ。这些方法都集中定义在事件监听者(EventListenerQ接口中Q这个接口要l承 java.util.EventListener。实C事g监听者接口中一些或全部Ҏ的类是事g监听者。伴随着事g的发生,相应的状态通常都封装在事g状态对象中Q该对象必须l承自java.util.EventObject。事件状态对象作为单参传递给应响应该事g的监听者方法中。发出某U特定事件的事g源的标识是:遵从规定的设计格式ؓ事g监听者定义注册方法,q接受对指定事g监听者接口实例的引用。有Ӟ事g监听者不能直接实C件监听者接口,或者还有其它的额外动作Ӟp在一个源与其它一个或多个监听者之间插入一个事仉配器类的实例,来徏立它们之间的联系?/p>
事g状态对象(Event State ObjectQ?br>
与事件发生有关的状态信息一般都装在一个事件状态对象中Q这U对象是java。util。EventObject的子cR按设计习惯Q这U事件状态对象类的名应以Eventl尾。例如:
public class MouseMovedExampleEvent extends java。util。EventObject
{ protected int xQ?yQ?br>/* 创徏一个鼠标移动事件MouseMovedExampleEvent */
MouseMovedExampleEvent(java.awt.Component sourceQ?Point location) {
super(source);
x = location.x;
y = location.y;
}
/* 获取鼠标位置*/
public Point getLocation() {
return new Point(x, y);
}}
事g监听者接口(EventListener InterfaceQ与事g监听?/p>
׃Java事g模型是基于方法调用,因而需要一个定义ƈl织事g操纵Ҏ的方式。事件操U|法都被定义在l承了java。util?EventListenercȝEventListener接口中,按规定,EventListener接口的命名要以Listenerl尾。Q何一个类如果xU在EventListener接口中定义的Ҏ都必M实现q个接口方式q行。这个类也就是事件监听者。例如:
/*先定义了一个鼠标移动事件对?/
public class MouseMovedExampleEvent extends java。util。EventObject {
// 在此cM包含了与鼠标Ud事g有关的状态信?br> ...
}
/*定义了鼠标移动事件的监听者接?/
interface MouseMovedExampleListener extends java。util。EventListener {
/*在这个接口中定义了鼠标移动事件监听者所应支持的Ҏ*/
void mouseMoved(MouseMovedExampleEvent mme);
}
在接口中只定义方法名Q方法的参数和返回值类型。如Q上面接口中的mouseMovedҎ的具体实现是在下面的ArbitraryObjectcM定义的?/p>
class ArbitraryObject implements MouseMovedExampleListener {
public void mouseMoved(MouseMovedExampleEvent mme)
{ ... }
?/p>
ArbitraryObject是MouseMovedExampleEvent事g的监听者?/p>
事g监听者的注册与注销
Z各种可能的事件监听者把自己注册入合适的事g源中Q徏立源与事件监听者间的事件流Q事件源必须Z件监听者提供注册和注销的方法。在前面的bound属性介l中已看Cq种使用q程Q在实际中,事g监听者的注册和注销要用标准的设计格式Q?/p>
public void add< ListenerType>(< ListenerType> listener)Q?br>public void remove< ListenerType>(< ListenerType> listener)Q?/p>
首先定义了一个事件监听者接口:
public interface ModelChangedListener extends java。util。EventListener {
void modelChanged(EventObject e);
}
接着定义事g源类Q?/p>
public abstract class Model {
private Vector listeners = new Vector(); // 定义了一个储存事件监听者的数组
/*上面设计格式中的< ListenerType>在此处即是下面的ModelChangedListener*/
public synchronized void addModelChangedListener(ModelChangedListener mcl)
{ listeners.addElement(mcl); }//把监听者注册入listeners数组?br>public synchronized void removeModelChangedListener(ModelChangedListener mcl)
{ listeners.removeElement(mcl); file://把监听者从listeners中注销
?br> /*以上两个Ҏ的前面均冠以synchronizedQ是因ؓq行在多U程环境Ӟ可能同时有几个对象同时要q行注册和注销操作Q用synchronized来确保它们之间的同步。开发工hE序员用这两个Ҏ建立源与监听者之间的事g?/
protected void notifyModelChanged() {/**事g源用本Ҏ通知监听者发生了modelChanged事g*/
Vector l;
EventObject e = new EventObject(this);
/* 首先要把监听者拷贝到l数组中,ȝEventListeners的状态以传递事件。这h保在事件传递到所有监听者之前,已接收了事g的目标监听者的对应Ҏ暂不生效?/
synchronized(this) {
l = (Vector)listeners.clone();
}
for (int i = 0; i < l.size(); i++) {
/* 依次通知注册在监听者队列中的每个监听者发生了modelChanged事gQ?br> q把事g状态对象e作ؓ参数传递给监听者队列中的每个监听?/
((ModelChangedListener)l.elementAt(i)).modelChanged(e);
}
}
?/p>
在程序中可见事g源ModelcL式地调用了接口中的modelChangedҎQ实际是把事件状态对象e作ؓ参数Q传递给了监听者类中的modelChangedҎ?/p>
适配c?/p>
适配cLJava事g模型中极光要的一部分。在一些应用场合,事g从源到监听者之间的传递要通过适配cL"转发"。例如:当事件源发出一个事Ӟ而有几个事g监听者对象都可接收该事gQ但只有指定对象做出反应Ӟp在事件源与事件监听者之间插入一个事仉配器类Q由适配器类来指定事件应该是由哪些监听者来响应。适配cLZ事g监听者,事g源实际是把适配cM为监听者注册入监听者队列中Q而真正的事g响应者ƈ未在监听者队列中Q事件响应者应做的动作由适配cd定。目前绝大多数的开发工具在生成代码Ӟ事g处理都是通过适配cLq行的?/p>
C#事g处理
在?NET应用E序开发中Q不是WEB FormsQASP。NETQ还是Windows FormsQ都涉及到大量对象的事g响应及处理,比如客户在线提交一份订单、或是在WindowsH口上移动鼠标等都将有事件发生。那么在C#中,是怎样声明事gqؓ事gd响应Ҏ的呢Q?/p>
在C#中,事g(Events)成员是用来声明一个类事g的。在cM声明一个事件成员一般采用如下的语法形式Q?/p>
public event 代表?事g名?/p>
如在ControlcM声明了一个Click事g成员Q其语法如下Q?/p>
public event EventHandler Click;
在C#中,增加了一个新的数据类型delegate来解决事件处理问题。代表数据类型非常类gC语言中的指针Q其与指针不同的是,其是代码是安全的Q可理的。由于C#本n的简易性,对于没有使用qC及指针的E序来说Q理解delegate也是非常Ҏ的?/p>
在C#中,通过使用delegateQ你可以通过"+="操作W非常容易地为。Net对象中的一个事件添加一个甚臛_个响应方法;q可以通过非常单的"-="操作W取消这些响应方法。如下面为temp按钮dClick事g的语句:
temp。Click+=new System.EventHandler(this.Test);//为testd事g处理Ҏ
在上面声明事件的语句中,Eventhandler是一个delegate(代表)cdQ其在。Netcd中如下声明的Q?/p>
public delegate void EventHandler(object senderQEventArgs e);
q样Q所有Ş?void 函娄?object 参数名,EventArgs 参数?;的函数都可以作ؓControlcȝClick事g响应Ҏ了。如下面所定义的一个事件响应方法:
private void button1_Click(object senderQ?System.EventArgs e)
׃是通过delegate来处理事Ӟ因此Q可能通过累加使一个事件具有多个响应方法;与此同时Q还可以使一个方法作为多个事件的响应Ҏ(注意Q在 C#语言cM的event成员后面只能出现"+="?-="两个表示d与取消事件响应函数的操作W?。不是ASP。Netq是一般的Windows Forms ~程Q在C#中,基本上我们遇到的事g响应Ҏ都是说明成如下的形式Q?/p>
private void button1_Click(object senderQ?System。EventArgs e)
那么Q一个事件响应方法的存取权限、返回值类型、参数及cd甚至Ҏ名称{是否都必须固定不变呢?{案是:不是Q?/p>
一般情况下Q事件的响应Ҏ中都有两个参敎ͼ其中一个代表引发事件的对象即senderQ由于引发事件的对象不可预知的,因此我们把其声明成ؓ objectcdQ所有的对象都适用。第二个参数代表引发事g的具体信息,各种cd的事件中可能不同Q这要根据类中事件成员的说明军_?/p>
我们知道Q事件是通过delegate来处理的。假讑ְ要表CZ件说明成如下形式Q?/p>
delegate int MyEventHandler(object senderQ?ToolBarButtonClickEventArgs e);
则当涉及上面的事件响应函数声明时Q就要声明成如下的形式Q?/p>
private int MyTest(object senderQToolBarButtonClickEventArgs e) {}
在给对象d事g响应Ҏ时就可以用如下的代码实现Q?/p>
Control。Event+=new MyEventHandler(MyTest);
ȝ来说QJava事g处理更直接,单。而C#事g处理׃引用代理Q得程序更灉|Q更体现E序之间的松藕合性。美国神鸟(Stryon http://www.stryon.com.cnQ公司宣布在Java开发^C实现微Y?NETQ命名ؓiNET。ƈ于近期推出iNET?Beta3版本Q其中就包括用Java实现了C#的三U事件处理机制?/p>
一、预备知识—程序的内存分配
一个由c/C++~译的程序占用的内存分ؓ以下几个部分
1、栈区(stackQ—由~译器自动分配释放,存放函数的参数|局部变量的值等。其操作方式cM于数据结构中的栈?br>2、堆区(heapQ—一般由E序员分配释放,若程序员不释放,E序l束时可能由OS回收。注意它与数据结构中的堆是两回事Q分配方式倒是c?/p>
g链表Q呵c?br>3、全局区(静态区Q(staticQ—全局变量和静态变量的存储是放在一块的Q初始化的全局变量和静态变量在一块区域,未初始化的全局变量
和未初始化的静态变量在盔R的另一块区域。程序结束后ql释放?br>4、文字常量区—常量字W串是攑֜q里的。程序结束后ql释放?br>5、程序代码区—存攑ևC的二q制代码?/p>
二、例子程?br>q是一个前辈写的,非常详细
//main.cpp
int a=0; //全局初始化区
char *p1; //全局未初始化?br> main()
{
intb;?br> char s[]="abc"; //?br> char *p2; //?br> char *p3="123456"; //123456\0在常量区Qp3在栈上?br> static int c=0Q?nbsp; //全局Q静态)初始化区
p1 = (char*)malloc(10);
p2 = (char*)malloc(20); //分配得来?0?0字节的区域就在堆区?br> strcpy(p1,"123456"); //123456\0攑֜帔R区,~译器可能会它与p3所?123456"优化成一个地斏V?br>}
二、堆和栈的理论知?br>2.1甌方式
stack:
ql自动分配。例如,声明在函C一个局部变量int b;pȝ自动在栈中ؓb开辟空?br>heap:
需要程序员自己甌Qƈ指明大小Q在c中malloc函数
如p1=(char*)malloc(10);
在C++中用newq算W?br>如p2=(char*)malloc(10);
但是注意p1、p2本n是在栈中的?/p>
2.2
甌后系l的响应
栈:只要栈的剩余I间大于所甌I间Q系l将为程序提供内存,否则报异常提示栈溢出?br>堆:首先应该知道操作pȝ有一个记录空闲内存地址的链表,当系l收到程序的甌Ӟ
会遍历该链表Q寻扄一个空间大于所甌I间的堆l点Q然后将该结点从I闲l点链表中删除,q将该结点的I间分配l程序,另外Q对?/p>
大多数系l,会在q块内存I间中的首地址处记录本ơ分配的大小Q这P代码中的delete语句才能正确的释放本内存I间。另外,׃扑ֈ
的堆l点的大不一定正好等于申L大小Q系l会自动的将多余的那部分重新攑օI闲链表中?/p>
2.3甌大小的限?br>栈:在Windows?栈是向低地址扩展的数据结构,是一块连l的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是pȝ预先规定好的
Q在WINDOWS下,栈的大小?MQ也有的说是1MQM是一个编译时q定的常数Q,如果甌的空间超q栈的剩余空间时Q将提示overflow?/p>
因此Q能从栈获得的空间较?br>堆:堆是向高地址扩展的数据结构,是不q箋的内存区域。这是由于系l是用链表来存储的空闲内存地址的,自然是不q箋的,而链表的遍历
方向是由低地址向高地址。堆的大受限于计算机系l中有效的虚拟内存。由此可见,堆获得的I间比较灉|Q也比较大?/p>
2.4甌效率的比较:
?ql自动分配,速度较快。但E序员是无法控制的?br>?是由new分配的内存,一般速度比较慢,而且Ҏ产生内存片,不过用v来最方便.
另外Q在WINDOWS下,最好的方式是用Virtual Alloc分配内存Q他不是在堆Q也不是在栈,而是直接在进E的地址I间中保留一块内存,虽然?/p>
h最不方ѝ但是速度快,也最灉|?/p>
2.5堆和栈中的存储内?br>栈:在函数调用时Q第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句Q的地址Q然后是函数的各个参敎ͼ在大?/p>
数的C~译器中Q参数是由右往左入栈的Q然后是函数中的局部变量。注意静态变量是不入栈的?br>当本ơ函数调用结束后Q局部变量先出栈Q然后是参数Q最后栈指针指向最开始存的地址Q也是dC的下一条指令,E序p点l?/p>
q行?br>堆:一般是在堆的头部用一个字节存攑֠的大。堆中的具体内容q序员安排?/p>
2.6存取效率的比?/p>
char s1[]="aaaaaaaaaaaaaaa";
char *s2="bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在q行时刻赋值的Q?br>而bbbbbbbbbbb是在~译时就定的;
但是Q在以后的存取中Q在栈上的数l比指针所指向的字W串(例如?快?br>比如Q?br>#include
voidmain()
{
char a=1;
char c[]="1234567890";
char *p="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇~代?br>10:a=c[1];
004010678A4DF1movcl,byteptr[ebp-0Fh]
0040106A884DFCmovbyteptr[ebp-4],cl
11:a=p[1];
0040106D8B55ECmovedx,dwordptr[ebp-14h]
004010708A4201moval,byteptr[edx+1]
004010738845FCmovbyteptr[ebp-4],al
W一U在d时直接就把字W串中的元素d寄存器cl中,而第二种则要先把指针D到edx中,在根据edxd字符Q显然慢了?/p>
2.7结Q?br>堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜Q发出申P、付钱、和吃(使用Q,吃饱了就赎ͼ不必理会切菜、洗菜等准备工作和洗、刷锅等
扫尾工作Q他的好处是快捷Q但是自由度?br>使用堆就象是自己动手做喜Ƣ吃的菜_比较ȝQ但是比较符合自q口味Q而且自由度大?/p>