﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-lishen226</title><link>http://www.blogjava.net/lishen226/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 28 Apr 2026 18:57:17 GMT</lastBuildDate><pubDate>Tue, 28 Apr 2026 18:57:17 GMT</pubDate><ttl>60</ttl><item><title>[转]JAVA Painting-Swing实现纪要一</title><link>http://www.blogjava.net/lishen226/archive/2009/10/20/298972.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Tue, 20 Oct 2009 01:58:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/10/20/298972.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/298972.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/10/20/298972.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/298972.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/298972.html</trackback:ping><description><![CDATA[<p><font style="background-color: #cce8cf">JAVA Painting-Swing实现纪要一<br />
首先推荐&lt;Painting in AWT and Swing&gt;by Amy Fowler。 <br />
Sun在JDK 1.0最初发布了图形API包,代号AWT (abstract windowing toolkit)，里面除对GUI基本支持（如结合各OS的事件分发机制等）外，自有一套重量级开发GUI的思路，并提供了一组常规使用的重量级组件。所谓重量级组件就是每个组件都引用一个本地对等体peer成员对象，这个对等体对象利用本地系统GUI API绘制组件。后来在JDK1.1，AWT包中引进了一套轻量级开发GUI的新思路，并提供了一组轻量级组件。所谓轻量级组件就是自身没有本地对等体，而借助重量级组件作为容器来绘制组件。JDK 1.1之后，sun在开发GUI思路上，在效率，扩展性等方面给出了很多创新，并基于这种新思路推出一套丰富的新组件（轻量级组件），sun为此打出一个新的响亮的代号---Swing，并推荐以后的GUI开发都应该基于SWING的GUI开发思路开展，应该使用或扩展这套SWING的组件。 <br />
不论是AWT模式还是SWING模式，Sun的GUI开发思路都是纯OO的。开发人员总是构建多个组件对象实例来组合建立GUI，这些对象是因不同的输入输出表现被封装为多种组件类的实例，而这些组件类是有合理的继承关系因而容易扩展的&#8220;套件&#8221;。而且两种模式最基本的统一的程序运行思路都是： <br />
1．通过建立各种组件的实例来负责GUI的工作。 <br />
2． 约定出GUI变化时机—java应用程序随需发出请求调用或对操作系统级某种操作的监听（如暴露被遮挡的窗口内容）。 <br />
3. 在时机到来时由&#8220;框架程序&#8221;来判断并调用应该调用的目标组件实例所提供的各种形式的paint方法（各组件在此方法里通过java 2d API包来实现自己的具体绘制逻辑）来完成各组件绘制。 <br />
4. 在GUI的整个生命周期里，通过以上的123模式来完成整个应用界面的随需而变。 <br />
下文将主要分析SWING模式。 <br />
Swing式 开发GUI的基本约定包括：SWING提供4个顶层容器JFrame,JDialog,JApplet,JWindow，如果是桌面应用，则GUI必须要有一个JFrame，如果是浏览器应用，则GUI必须要有一个JApplet。其他swing组件，或自定义开发的Swing组件都扩展自JComponent，并且其实例要存在于顶层容器的层次树中。下面是一个符合约定的GUI的运行分析。 <br />
import javax.swing.JFrame; <br />
import javax.swing.JLabel; <br />
public class BasicSwing { <br />
public static void main(String[] args) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; javax.swing.SwingUtilities.invokeLater(new Runnable() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; createAndShowGUI(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
private void createAndShowGUI() { <br />
JFrame frame = new JFrame("BasicSwing"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JLabel label=new JLabel("hello world"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frame.getContentPane().add(label); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frame.setSize(100,200); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frame.setVisible(true); <br />
} <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }); <br />
&nbsp;&nbsp;&nbsp; } <br />
} <br />
invokeLater方法在执行时首先会延迟创建getToolkit---系统属性awt.toolkit给出了要加载的类，在windows平台下即为WToolkit。WToolkit在初始化时会启动AWT-WINDOWS线程(setDaemon-true)，该线程将一直负责从win32系统中获取底层事件并简接挂到EventQueue事件队列中；同时激活AWT-Shutdown线程(setDaemon-false)，该线程一直监测是否满足关闭GUI的条件（peerMap is null；AWT-WINDOWS is busy；EDT is busy），若是则主动要求关闭EDT也就是GUI最终退出（因为GUI环境下只有EDT是非daemon线程）；WToolkit还有就是加载sun.java2d.Disposer类，其将在类加载初始化时启动Java2D Disposer线程(setDaemon-true, MAX_PRIORITY)，该线程将一直跟踪监测被废弃的注册记录（WToolkit算一个，还有各种peer），监测到后执行对应的Dispose类来完成相应的资源回收。 <br />
invokeLater方法同时会创建EventQueue挂在AppContext里，并马上向EventQueue提交InvocationEvent以执行上面例子中的Runable，这将导致启动第一个AWT-EventQueue-N线程（EDT-(setDaemon-false)）。 <br />
EDT启动后将一直从EventQueue获取AWTEVENT进行dispatch分发处理，处理过程中若遇到某些意外或被强制中断都有可能导致EDT熄火，此时AWT-Shutdown被notify检测彻底终止AWT的时机是否到来，若不满足条件新的EDT：AWT-EventQueue-N+1将被启动。 <br />
以上将建立起界面GUI的基本运行框架。上述例子的main线程很快退出，而EDT线程将处理InvocationEvent,处理过程即是执行Runable.run方法体。 <br />
在EDT中，JFrame被构造，在其构造过程中，会追加dispose记录即 <br />
(addRecord(JFrame.anchorObject, WindowDisposerRecord(appContext,this));)进Java2D Disposer以在失去引用时释放窗口资源。 <br />
随后JFrame被setvisible，在setvisible过程中，将通过WToolkit createFramePeer，并注册在AWT-Shutdown的peerMap中以支持AWT-AutoShutDown机制。 <br />
Setvisible中将促使调用peer.pShow-native代码，即发送给win32请求显示窗口，窗口被打开后awt_windows线程在eventloop中得到wm_paint消息进行处理，这是一个异步过程。 <br />
awt_windows处理中将有选择地通过RepaintManager加入重画记录区几何区域 <br />
RepaintManager. nativeAddDirtyRegio并调度重画线程单位在EDT中进行绘制 <br />
postEvent-InvocationEvent(ProcessingRunnable)，ProcessingRunnable随后 <br />
在EDT中run时将根据重画区记录执行可能的窗口内容绘制--即各子组件回调paint过程。 <br />
上述是SWING顶层重量级容器组件的一个绘制场景，可以看到是经由awt-windows eventloop到了底层事件后触发paint绘制；然而对轻量级swing组件，其paint都是通过java代码中对repaint调用而触发，其会向RepaintManager.addDirtyRegion，同时scheduleProcessingRunnable。这是整个GUI生命周期内对绘制的两种不同的触发方式，但触发后的处理都是交由RepaintManager。 <br />
回过头去看，JFrame被构造的时候就会创建root pane, layered pane,content pane, glass pane等,这些没有对等体的轻量级Swing组件在构造时都将repaint。虽然在创建windows对等窗口之前这些Swing组件就已经在要求绘制，但是RepaintManager能够协调好这个步调（具体即是当收到repaint请求时要判断情况，像这时的请求因为顶层容器还没有绘制则不会记录到重画区）。所以最终效果就是在peer.pshow的时候只能看到一个空窗口，随后底层消息到来后通过paint回调画这些子组件，最后hello world才显示出来。如果眼神好，能够看出这有一个&#8220;闪烁&#8221;。 <br />
这是一个最简单的swing应用程序的基本运行机制分析，下面再具体分析。 <br />
Swing的GUI总是由顶层容器组件和轻量级swing组件组合建立，顶层容器和其他组件区别主要在于顶层容器没有自身的paint逻辑。 <br />
所有顶层容器都是通过使用底层系统API来绘制对等体的方式进行paint，自身没有java2d的paint逻辑实现，对等体画成什么样顶层容器就是什么样，它只是可以控制对等体的一些可配显示属性。所以效果就是比如在windows平台上画一个jframe，除在桌面上显示一个窗口还会在任务栏上显示一个条目。Swing的4个顶层容器都是在addNotify时才会getToolkit().createPeer(this)（Frame/Dialog/Window）,而addNotify并不是在构造时被调用，而是在pack/show或setvisible（这3个所谓的realized具现化方法）时被调用。创建了对等体peer后还要通过peer.pShow（show/setVisible(true)调用）调用才会要求底层系统进行显示（所以只有pack是不会显示窗口的）。在显示窗口后底层消息队列得到通知，此后随着窗口被最小化后恢复或被遮盖后恢复等系统操作后同样能从底层消息得到通知，这时的监听处理将有选择地通知给RepaintManager一个重画请求进行窗口内容-子组件重画。 <br />
而轻量级swing组件将绘制有关的职责都委托给了ui成员对象，ui对象使用JAVA2D API 进行绘制，paint成什么样那就是这个组件的样子。具体就是在构造的时候即要updateUI{setUI(UIManger.getUI(this))}。UIManger会根据当前L&amp;F的选择，根据this.uiClassID来得到ui成员类并建立实例，以后的paint回调等都推托给ui成员类paint，这也算是一种策略模式。Setui的过程中除了保存这个ui实例外，将repaint来通知RepaintManager进行paint回调完成组件绘制。轻量级swing组件在addNotify时也会去创建对等体getToolkit().createPeer(this)( LightWeightPeer)，但这个peer的实现（NullComponentPeer）是个空壳子，只是作为一个轻量级组件的标记，以后的很多事件处理等都要判断peer是否instance of LightWeightPeer从而能够进行不同处理。同样的Addnotify也不是在构造时被调用，而是在被加入container时被调用。 <br />
注意：构造方法本身就是状态模式的第一状态，所以GUI组件的构造方法里就应该要努力完成自身的绘制来符合自己的地位。轻量级组件就是按这个意义在构造方法里去通知repaintmanager进行自身绘制的，但是顶层容器却将真正的绘制意图createPeer延迟到了具现方法里。这是因为首先一个合乎思维的表达逻辑是先有容器，再将子组件向容器里添加， 所以最顶层容器总是先行构造出来，然后再被一层层地追加轻量级子组件。如果最顶层容器在构造时就去具现，则就要求后续的构造都应该在EDT中进行，而且每次add子组件都要导致revalidate；但若将最顶层容器的绘制分离延迟到具现方法里，则可以表达是在容器里盛满了要显示的子组件后再一股脑具现绘制出来的概念，类似于在进行一次web页面的完整加载,然后注意在具现方法执行后如果要操作组件都在EDT中进行即可，而且顶层容器提供一个特有的pack方法，用来一次性对所有子组件验证大小位置进行重布局，pack之后再show，这样的一次性计算展现是最有效率的。 <br />
顶层容器和轻量级组件就是这样诞生并绘制的，在此后的生命周期里，都将按事件监听机制完成GUI随需而变，无论是系统事件，还是因为repaint调用主动post事件，事件到来后再在EDT中执行监听器里的paint绘制。Swing已经提供的顶层容器和轻量级组件因各自的定义已经注册了各自的paint监听，开发人员可以再行维护或按此模式开发新组件从而满足应用的需要。比如，jbutton默认有mousepress listener，在mousepress事件到来后，监听响应中会设置鼠标颜色加深来表示按下，然后再调用repaint要求重画，随后在EDT中执行jbutton的paint回调，此时按深颜色绘制，于是一个被按下的效果就出来了。 <br />
下面在具体分析各类事件的处理。 <br />
对于顶层容器的受底层事件消息的触发，当得到的通知是因为expose暴露隐藏区（暴露被遮蔽的部分或恢复最小化或第一次绘制等）时，处理过程会涉及到双缓存的处理，即如果可能，直接使用缓存中的旧图像信息进行覆盖而不再重新绘制。 <br />
所谓双缓存机制是将一整片的显示内容暂时写入一张内存空间里，然后一次性内存拷入显示区来进行显示，这样处理是因为如果直接写入显示区，随着显示区被该写入线程逐渐写入，可能经历多次屏幕刷新，导致每次刷新都形成过程图像，给人眼造成闪烁感觉；同时一个副收益就是可以针对每个窗口都做缓存待用（而不仅仅是针对一个屏幕双缓存），当窗口被遮挡的部分重现时直接拷贝缓存来覆盖，不用再执行绘画逻辑，提高了效率。 <br />
现在的OS一般都提供双缓存机制支持，如果底层系统自身支持以每个窗口为单位做双缓存，则该expose消息将被本地处理，不需要通知进行子组件的绘制；如果底层不支持，则该消息会到达wcomponetpeer.handleexpose中进行回调处理，此时swing机制下有一个参数控制的双缓存机制可以提供。这里的参数控制需要从RepaintManager的构造过程说起。 <br />
首先RepaintManager可以通过static setCurrentManager(SomeCurrentManager)来进行全局指定。默认情况使用currentRepaintManager(){new RepaintManager(BUFFER_STRATEGY_TYPE)}得到一个延迟创建的单例。RepaintManager有一段静态类初始化过程，涉及到双缓存设置： <br />
static { <br />
nativeDoubleBuffering = "true".equals(AccessController.doPrivileged( <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new GetPropertyAction("awt.nativeDoubleBuffering")));//JVM的启动参数控制，默认false <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String bs = AccessController.doPrivileged( <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new GetPropertyAction("swing.bufferPerWindow"));//是否每窗口缓存。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (headless) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_SPECIFIED_OFF; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (bs == null) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_NOT_SPECIFIED; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if ("true".equals(bs)) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_SPECIFIED_ON; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_SPECIFIED_OFF; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
} <br />
private RepaintManager(short bufferStrategyType) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If native doublebuffering is being used, do NOT use <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Swing doublebuffering. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doubleBufferingEnabled = !nativeDoubleBuffering; </font></p>
<p><font style="background-color: #cce8cf">this.bufferStrategyType = bufferStrategyType; </font></p>
<p><font style="background-color: #cce8cf">} <br />
public void setDoubleBufferingEnabled(boolean aFlag) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doubleBufferingEnabled = aFlag; </font></p>
<p><font style="background-color: #cce8cf">doubleBufferingEnabled（开启双缓存），nativeDoubleBuffering（利用本地双缓存机制），bufferStrategyType（每窗口双缓存策略） <br />
这几个参数将影响到RepaintManager的成员对象paintManager的选择，也算是一个策略模式，该paintManager是负责绘制的核心类。 <br />
private synchronized PaintManager getPaintManager() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (paintManager == null) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PaintManager paintManager = null; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (doubleBufferingEnabled &amp;&amp; !nativeDoubleBuffering) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch (bufferStrategyType) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case BUFFER_STRATEGY_NOT_SPECIFIED: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (((SunToolkit)Toolkit.getDefaultToolkit()). <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; useBufferPerWindow()) {//windows下是否禁用vista dwm,在没有声明bufferPerWindow的情况下由windows系统特性确定paintmanager。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paintManager = new BufferStrategyPaintManager(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case BUFFER_STRATEGY_SPECIFIED_ON: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paintManager = new BufferStrategyPaintManager(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // null case handled in setPaintManager <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setPaintManager(paintManager); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return paintManager; <br />
&nbsp;&nbsp;&nbsp; } <br />
void setPaintManager(PaintManager paintManager) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (paintManager == null) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paintManager = new PaintManager(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </font></p>
<p><font style="background-color: #cce8cf">} <br />
回到上文，当handleexpose时，通过getPaintEventDispatcher 来createPaintEvent，在UIManager.initialize根据RepaintManager.HANDLE_TOP_LEVEL_PAINT（属性swing.handleTopLevelPaint）确定是SwingPaintEventDispatcher还是直接使用PaintEventDispatcher。 <br />
若为false,在PaintEventDispatcher中，将直接创建PaintEvent-PAINT提交，此后该事件经合并后将由wcomponentpeer.handleEvent，该处理将通过一个自身维护的paintArea几何脏区域进行重画区域优化，最终委托给Container进行子组件绘制，这是非SWING模式-即AWT模式，没有双缓存的概念。 <br />
补充：在Swing和它的RepainManager出现以前，GUI的模式-AWT模式总是要先形成一个PaintEvent（触发可能来自底层消息-PAINT类型，也可能来自repaint-UPDATE类型），post给EventQueue，并组织一次合并： <br />
public abstract class WComponentPeer{ <br />
void handlePaint(int x, int y, int w, int h) { <br />
&nbsp;&nbsp;&nbsp; System.out.println("handlePaint&gt;&gt;&gt;"+x+":"+y+":"+w+":"+h); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; postPaintIfNecessary(x, y, w, h); <br />
&nbsp;&nbsp;&nbsp; } </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp; private void postPaintIfNecessary(int x, int y, int w, int h) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( !ComponentAccessor.getIgnoreRepaint( (Component) target) ) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher(). <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; createPaintEvent((Component)target, x, y, w, h); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (event != null) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; postEvent(event); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
} <br />
public class PaintEventDispatcher { <br />
public PaintEvent createPaintEvent(Component target, int x, int y, int w, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int h) { </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new PaintEvent((Component)target, PaintEvent.PAINT, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Rectangle(x, y, w, h)); <br />
&nbsp;&nbsp;&nbsp; } </font></p>
<p><font style="background-color: #cce8cf">public abstract class Component{ <br />
public void repaint(long tm, int x, int y, int width, int height) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (this.peer instanceof LightweightPeer) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~~~ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parent.repaint(tm, px, py, pwidth, pheight); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (isVisible() &amp;&amp; (this.peer != null) &amp;&amp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (width &gt; 0) &amp;&amp; (height &gt; 0)) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PaintEvent e = new PaintEvent(this, PaintEvent.UPDATE, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Rectangle(x, y, width, height)); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Toolkit.getEventQueue().postEvent(e); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
} </font></p>
<p><font style="background-color: #cce8cf">public class EventQueue{ <br />
private void postEvent(AWTEvent theEvent, int priority) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (coalesceEvent(theEvent, priority)) {//post之前总是需要合并 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </font></p>
<font style="background-color: #cce8cf">
<p><br />
private boolean coalesceEvent(AWTEvent e, int priority) { </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (e instanceof PaintEvent) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return coalescePaintEvent((PaintEvent)e);//对paintevent进行一轮合并处理，导致同一重量级组件的多次paintevent被合并为一个paintevent等待dispatch。以提高效率 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </p>
<p>然后EDT中在Component.dispatchImpl中委托给wcomponentpeer处理。 </p>
<p>public abstract class Component{ </p>
<p>dispatchEventImpl{ <br />
/* <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 9. Allow the peer to process the event. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Except KeyEvents, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tpeer != null) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tpeer.handleEvent(e); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>public abstract class WComponentPeer{ </p>
<p>public void handleEvent(AWTEvent e) { </p>
<p>switch(id) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case PaintEvent.PAINT: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Got native painting <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paintPending = false; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Fallthrough to next statement <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case PaintEvent.UPDATE: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Skip all painting while layouting and all UPDATEs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // while waiting for native paint <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!isLayouting &amp;&amp; ! paintPending) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paintArea.paint(target,shouldClearRectBeforePaint()); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </p>
<p>Peer处理过程中将利用自身维护的PaintArea进行重画区域的优化，并执行子组件paint回调。 <br />
/** <br />
&nbsp;&nbsp;&nbsp;&nbsp; * Invokes paint and update on target Component with optimal <br />
&nbsp;&nbsp;&nbsp;&nbsp; * rectangular clip region. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * If PAINT bounding rectangle is less than <br />
&nbsp;&nbsp;&nbsp;&nbsp; * MAX_BENEFIT_RATIO times the benefit, then the vertical and horizontal unions are <br />
&nbsp;&nbsp;&nbsp;&nbsp; * painted separately.&nbsp; Otherwise the entire bounding rectangle is painted. <br />
&nbsp;&nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp;&nbsp; * @param&nbsp;&nbsp; target Component to &lt;code&gt;paint&lt;/code&gt; or &lt;code&gt;update&lt;/code&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp; * @since&nbsp;&nbsp; 1.4 <br />
&nbsp;&nbsp;&nbsp;&nbsp; */ <br />
&nbsp;&nbsp;&nbsp; public void paint(Object target, boolean shouldClearRectBeforePaint) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Component comp = (Component)target; <br />
~~~ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ra.paintRects[HORIZONTAL] != null &amp;&amp; ra.paintRects[VERTICAL] != null) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rectangle paintRect = ra.paintRects[HORIZONTAL].union(ra.paintRects[VERTICAL]); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int square = paintRect.width * paintRect.height; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int benefit = square - ra.paintRects[HORIZONTAL].width <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * ra.paintRects[HORIZONTAL].height - ra.paintRects[VERTICAL].width <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * ra.paintRects[VERTICAL].height; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // if benefit is comparable with bounding box <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (MAX_BENEFIT_RATIO * benefit &lt; square) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ra.paintRects[HORIZONTAL] = paintRect; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ra.paintRects[VERTICAL] = null; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; paintRects.length; i++) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ra.paintRects[i] != null <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; !ra.paintRects[i].isEmpty()) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Should use separate Graphics for each paint() call, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // since paint() can change Graphics state for next call. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Graphics g = comp.getGraphics(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (g != null) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g.setClip(ra.paintRects[i]); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i == UPDATE) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; updateComponent(comp, g); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (shouldClearRectBeforePaint) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g.clearRect( ra.paintRects[i].x, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ra.paintRects[i].y, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ra.paintRects[i].width, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ra.paintRects[i].height); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paintComponent(comp, g); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g.dispose(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; } <br />
若为true,在SwingPaintEventDispatcher.createPaintEvent， <br />
if (component instanceof RootPaneContainer) {//如果是顶层容器 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AppContext appContext = SunToolkit.targetToAppContext(component); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RepaintManager rm = RepaintManager.currentManager(appContext); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!SHOW_FROM_DOUBLE_BUFFER ||//参数swing.showFromDoubleBuffer控制，默认true确定swing//是否会考虑双缓存支持 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; !rm.show((Container)component, x, y, w, h)) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rm.nativeAddDirtyRegion(appContext, (Container)component, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x, y, w, h); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
return new IgnorePaintEvent(component, PaintEvent.PAINT, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Rectangle(x, y, w, h));//返回一个将被忽略的假事件提交 </p>
<p>如果SHOW_FROM_DOUBLE_BUFFER 考虑双缓存支持，将进行rm.show，其交给getPaintManager().show，这时的paintmanager是经过了前面所说的几个参数选择的，也就是说，考虑当前是否当前正使能双缓存doubleBufferingEnabled，是否不使用本地双缓存nativeDoubleBuffering， BUFFER_STRATEGY_TYPE是否指定了每窗口缓存的双缓存支持策略，如果没有指定策略是否或本地windows系统环境没有开启vista dwm效果，如果都满足将使用BufferStrategyPaintManager，借由swing提供每窗口双缓存机制，检查swing记录中是否具有有效缓存，若存在则会要求该区直接拷贝flip即可，如果没有成功执行双缓存拷贝，则将加入Repaintmanager重画区域进行swing模式的重画。 <br />
顶层容器除了在对等体发过消息后处理paint，也具有自己的repaint方法去主动创造绘画时机。 <br />
public void repaint(long time, int x, int y, int width, int height) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (RepaintManager.HANDLE_TOP_LEVEL_PAINT) {//属性swing.handleTopLevelPaint确定，默认true <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RepaintManager.currentManager(this).addDirtyRegion( <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this, x, y, width, height); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.repaint(time, x, y, width, height); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; } <br />
这里的repaint将首先确定RepaintManager.HANDLE_TOP_LEVEL_PAINT-如果不支持将委托给Component.repaint，形成PaintEvent并进行提交走AWT模式。支持的话将促使RepaintManager加入重画区后通过调度走SWING模式。SWING模式就是走RepaintManager的方式。自身的repaint不会去考虑每窗口双缓存直接拷贝区域，因为这时的需求就是要求重新绘画。 <br />
轻量级swing组件在自己的repaint方法去主动创造绘画时机。 <br />
JComponent.Repaint{RepaintManager.currentManager(this).addDirtyRegion}走SWING模式处理。 <br />
SWING模式都是借由RepaintManager来安排绘画，它维护了一个几何区域并负责重画的框架。外界总是要求先加入RepaintManager重绘区，在加入的同时激发起一个调度重画的 <br />
SunToolkit.getSystemEventQueueImplPP(context). <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(), <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; processingRunnable)) </p>
<p>InvocationEvent。 <br />
注意，通过上文分析，对于顶层容器处理底层消息的触发时，走swing处理模式而通过swingpaintEventdispatcher去创建painitevent时除向repaintmanager登记脏区（如果不使用每窗口双缓存策略）外，还要额外post一个IgnorePaintEvent。该paintevent在随后的EDT里按awt模式走peer处理时并没有加入awt的重画脏区，实际上忽略掉了绘制意义，这样做避免了在swing和awt两种模式的重复绘制，但同时形成依然将paint事件通知到组件的效果。 <br />
public void coalescePaintEvent(PaintEvent e) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rectangle r = e.getUpdateRect(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(e instanceof IgnorePaintEvent)) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paintArea.add(r, e.getID()); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></p>
<img src ="http://www.blogjava.net/lishen226/aggbug/298972.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-10-20 09:58 <a href="http://www.blogjava.net/lishen226/archive/2009/10/20/298972.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Swing中的多线程</title><link>http://www.blogjava.net/lishen226/archive/2009/10/20/298965.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Tue, 20 Oct 2009 01:49:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/10/20/298965.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/298965.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/10/20/298965.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/298965.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/298965.html</trackback:ping><description><![CDATA[<p><font style="background-color: #cce8cf">Swing中的多线程<br />
关键字: swing中的多线程 <br />
本文关于Swing中的多线程，发表于1998年4月。一个月后，我们发表了另一篇文章《使用Swing Worker线程》，该文更深入地讨论了这一主题。要更好地了解多线程在Swing中如何工作，我们建议你把这两篇文章都看一下。 <br />
注意：在2000年9月我们修改了这篇文章和它的例子以适用于一个更新版本的SwingWorker类。SwingWorker类的这个版本修正了一些微妙的线程bug。 </font></p>
<p><font style="background-color: #cce8cf">Swing API的设计目标是强大、灵活和易用。特别地，我们希望能让程序员们方便地建立新的Swing组件，不论是从头开始还是通过扩展我们所提供的一些组件。 <br />
出于这个目的，我们不要求Swing组件支持多线程访问。相反，我们向组件发送请求并在单一线程中执行请求。 <br />
本文讨论线程和Swing组件。目的不仅是为了帮助你以线程安全的方式使用Swing API，而且解释了我们为什么会选择现在这样的线程方案。 <br />
本文包括以下内容： </font></p>
<p><font style="background-color: #cce8cf">单线程规则：Swing线程在同一时刻仅能被一个线程所访问。一般来说，这个线程是事件派发线程（event-dispatching thread）。 </font></p>
<p><font style="background-color: #cce8cf">规则的例外：有些操作保证是线程安全的。 <br />
事件分发：如果你需要从事件处理（event-handling）或绘制代码以外的地方访问UI，那么你可以使用SwingUtilities类的invokeLater()或invokeAndWait()方法。 </font></p>
<p><font style="background-color: #cce8cf">创建线程：如果你需要创建一个线程――比如用来处理一些耗费大量计算能力或受I/O能力限制的工作――你可以使用一个线程工具类如SwingWorker或Timer。 </font></p>
<p><font style="background-color: #cce8cf">为什么我们这样实现Swing：我们用一些关于Swing的线程安全的背景资料来结束这篇文章。 </font></p>
<p><font style="background-color: #cce8cf">Swing的规则是： <br />
一旦Swing组件被具现化（realized），所有可能影响或依赖于组件状态的代码都应该在事件派发线程中执行。 </font></p>
<p><font style="background-color: #cce8cf">这个规则可能听起来有点吓人，但对许多简单的程序来说，你用不着为线程问题操心。在我们深入如何撰写Swing代码之前，让我们先来定义两个术语：具现化（realized）和事件派发线程（event-dispatching thread）。 <br />
具现化的意思是组建的paint()方法已经或可能会被调用。一个作为顶级窗口的Swing组件当调用以下方法时将被具现化：setVisible(true)、show()或（可能令你惊奇）pack()。当一个窗口被具现化，它包含的所有组件都被具现化。另一个具现化一个组件的方法是将它放入到一个已经具现化的容器中。稍后你会看到一些对组件具现化的例子。 <br />
事件派发线程是执行绘制和事件处理的线程。例如，paint()和actionPerformed()方法会自动在事件派发线程中执行。另一个将代码放到事件派发线程中执行的方法是使用SwingUtilities类的invokeLater()方法。 <br />
所有可能影响一个已具现化的Swing组件的代码都必须在事件派发线程中执行。但这个规则有一些例外： </font></p>
<p><font style="background-color: #cce8cf">有些方法是线程安全的：在Swing API的文档中，线程安全的方法用以下文字标记： <br />
This method is thread safe, although most Swing methods are not. <br />
（这个方法是线程安全的，尽管大多数Swing方法都不是。） </font></p>
<p><font style="background-color: #cce8cf">一个应用程序的GUI常常可以在主线程中构建和显示：下面的典型代码是安全的，只要没有（Swing或其他）组件被具现化： </font></p>
<font style="background-color: #cce8cf">
<p><br />
public class MyApplication { <br />
public static void main(String[] args) { <br />
&nbsp;&nbsp; JFrame f = new JFrame("Labels"); <br />
&nbsp;&nbsp; // 在这里将各组件&nbsp; <br />
&nbsp;&nbsp; // 加入到主框架&#8230;&#8230;&nbsp; <br />
&nbsp;&nbsp; f.pack();&nbsp; <br />
&nbsp;&nbsp; f.show();&nbsp; <br />
&nbsp;&nbsp; // 不要再做任何GUI工作&#8230;&#8230;&nbsp; <br />
&nbsp;&nbsp; }&nbsp; <br />
} </p>
<p>上面所示的代码全部在&#8220;main&#8221;线程中运行。对f.pack()的调用使得JFrame以下的组件都被具现化。这意味着，f.show()调用是不安全的且应该在事件派发线程中执行。尽管如此，只要程序还没有一个看得到的GUI，JFrame或它的里面的组件就几乎不可能在f.show()返回前收到一个paint()调用。因为在f.show()调用之后不再有任何GUI代码，于是所有GUI工作都从主线程转到了事件派发线程，因此前面所讨论的代码实际上是线程安全的。 </p>
<p>一个applet的GUI可以在init()方法中构造和显示：现有的浏览器都不会在一个applet的init()和start()方法被调用前绘制它。因而，在一个applet的init()方法中构造GUI是安全的，只要你不对applet中的对象调用show()或setVisible(true)方法。 <br />
要顺便一提的是，如果applet中使用了Swing组件，就必须实现为JApplet的子类。并且，组件应该添加到的JApplet内容窗格（content pane）中，而不要直接添加到JApplet。对任何applet，你都不应该在init()或start()方法中执行费时的初始化操作；而应该启动一个线程来执行费时的任务。 </p>
<p>下述JComponent方法是安全的，可以从任何线程调用：repaint()、revalidate()、和invalidate()。repaint()和revalidate()方法为事件派发线程对请求排队，并分别调用paint()和validate()方法。invalidate()方法只在需要确认时标记一个组件和它的所有直接祖先。 </p>
<p>监听者列表可以由任何线程修改：调用addListenerTypeListener()和removeListenerTypeListener()方法总是安全的。对监听者列表的添加/删除操作不会对进行中的事件派发有任何影响。 </p>
<p>注意：revalidate()和旧的validate()方法之间的重要区别是，revalidate()会缓存请求并组合成一次validate()调用。这和repaint()缓存并组合绘制请求类似。 <br />
大多数初始化后的GUI工作自然地发生在事件派发线程。一旦GUI成为可见，大多数程序都是由事件驱动的，如按钮动作或鼠标点击，这些总是在事件派发线程中处理的。 <br />
不过，总有些程序需要在GUI成为可见后执行一些非事件驱动的GUI工作。比如： </p>
<p>在成为可用前需要进行长时间初始化操作的程序：这类程序通常应该在初始化期间就显示出GUI，然后更新或改变GUI。初始化过程不应该在事件派发线程中进行；否则，重绘组件和事件派发会停止。尽管如此，在初始化之后，GUI的更新/改变还是应该在事件派发线程中进行，理由是线程安全。 </p>
<p>必须响应非AWT事件来更新GUI的程序：例如，想象一个服务器程序从可能运行在其他机器上的程序得到请求。这些请求可能在任何时刻到达，并且会引起在一些可能未知的线程中对服务器的方法调用。这个方法调用怎样更新GUI呢？在事件派发线程中执行GUI更新代码。 </p>
<p>SwingUtilities类提供了两个方法来帮助你在事件派发线程中执行代码： </p>
<p>invokeLater()：要求在事件派发线程中执行某些代码。这个方法会立即返回，不会等待代码执行完毕。 </p>
<p>invokeAndWait()：行为与invokeLater()类似，除了这个方法会等待代码执行完毕。一般地，你可以用invokeLater()来代替这个方法。 </p>
<p><br />
下面是一些使用这几个API的例子。请同时参阅《The Java Tutorial》中的&#8220;BINGO example&#8221;，尤其是以下几个类：CardWindow、ControlPane、Player和OverallStatusPane。 </p>
<p>使用invokeLater()方法 </p>
<p>你可以从任何线程调用invokeLater()方法以请求事件派发线程运行特定代码。你必须把要运行的代码放到一个Runnable对象的run()方法中，并将此Runnable对象设为invokeLater()的参数。invokeLater()方法会立即返回，不等待事件派发线程执行指定代码。这是一个使用invokeLater()方法的例子： </p>
<p><br />
Runnable doWorkRunnable = new Runnable() { <br />
&nbsp;&nbsp;&nbsp; public void run() { doWork(); } <br />
}; <br />
SwingUtilities.invokeLater(doWorkRunnable); </p>
<p><br />
使用invokeAndWait()方法 </p>
<p>invokeAndWait()方法和invokeLater()方法很相似，除了invokeAndWait()方法会等事件派发线程执行了指定代码才返回。在可能的情况下，你应该尽量用invokeLater()来代替invokeAndWait()。如果你真的要使用invokeAndWait()，请确保调用invokeAndWait()的线程不会在调用期间持有任何其他线程可能需要的锁。 <br />
这是一个使用invokeAndWait()的例子： </p>
<p><br />
void showHelloThereDialog()&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws Exception { <br />
&nbsp;&nbsp;&nbsp; Runnable showModalDialog = new&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Runnable() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JOptionPane.showMessageDialog( <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myMainFrame, "Hello There"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; }; <br />
&nbsp;&nbsp;&nbsp; SwingUtilities.invokeAndWait <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (showModalDialog); <br />
} </p>
<p>类似地，假设一个线程需要对GUI的状态进行存取，比如文本域的内容，它的代码可能类似这样： </p>
<p><br />
void printTextField() throws Exception { <br />
&nbsp;&nbsp;&nbsp; final String[] myStrings =&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new String[2]; </p>
<p>&nbsp;&nbsp;&nbsp; Runnable getTextFieldText =&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Runnable() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myStrings[0] =&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; textField0.getText(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myStrings[1] =&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; textField1.getText(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; }; <br />
&nbsp;&nbsp;&nbsp; SwingUtilities.invokeAndWait <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (getTextFieldText); </p>
<p>&nbsp;&nbsp;&nbsp; System.out.println(myStrings[0]&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + " " + myStrings[1]); <br />
} </p>
<p>如果你能避免使用线程，最好这样做。线程可能难于使用，并使得程序的debug更困难。一般来说，对于严格意义下的GUI工作，线程是不必要的，比如对组件属性的更新。 <br />
不管怎么说，有时候线程是必要的。下列情况是使用线程的一些典型情况： </p>
<p>执行一项费时的任务而不必将事件派发线程锁定。例子包括执行大量计算的情况，会导致大量类被装载的情况（如初始化），和为网络或磁盘I/O而阻塞的情况。 </p>
<p>重复地执行一项操作，通常在两次操作间间隔一个预定的时间周期。 </p>
<p>要等待来自客户的消息。 </p>
<p>你可以使用两个类来帮助你实现线程： </p>
<p>SwingWorker：创建一个后台线程来执行费时的操作。 </p>
<p>Timer：创建一个线程来执行或多次执行某些代码，在两次执行间间隔用户定义的延迟。 </p>
<p><br />
使用SwingWorker类 </p>
<p>SwingWorker类在SwingWorker.java中实现，这个类并不包含在Java的任何发行版中，所以你必须单独下载它。 <br />
SwingWorker类做了所有实现一个后台线程所需的肮脏工作。虽然许多程序都不需要后台线程，后台线程在执行费时的操作时仍然是很有用的，它能提高程序的性能观感。 <br />
SwingWorker's get() method. Here's an example of using SwingWorker: <br />
要使用SwingWorker类，你首先要实现它的一个子类。在子类中，你必须实现construct()方法还包含你的长时间操作。当你实例化SwingWorker的子类时，SwingWorker创建一个线程但并不启动它。你要调用你的SwingWorker对象的start()方法来启动线程，然后start()方法会调用你的construct()方法。当你需要construct()方法返回的对象时，可以调用SwingWorker类的get()方法。这是一个使用SwingWorker类的例子： </p>
<p><br />
...// 在main方法中： <br />
&nbsp;&nbsp;&nbsp; final SwingWorker worker =&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new SwingWorker() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Object construct() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expensiveDialogComponent(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; }; <br />
&nbsp;&nbsp;&nbsp; worker.start(); </p>
<p>...// 在动作事件处理方法中: <br />
&nbsp;&nbsp;&nbsp; JOptionPane.showMessageDialog <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (f, worker.get()); </p>
<p>当程序的main()方法调用start()方法，SwingWorker启动一个新的线程来实例化ExpensiveDialogComponent。main()方法还构造了由一个窗口和一个按钮组成的GUI。 <br />
当用户点击按钮，程序将阻塞，如果必要，阻塞到ExpensiveDialogComponent创建完成。然后程序显示一个包含ExpensiveDialogComponent的模式对话框。你可以在MyApplication.java找到整个程序。 </p>
<p>使用Timer类 </p>
<p>Timer类通过一个ActionListener来执行或多次执行一项操作。你创建定时器的时候可以指定操作执行的频率，并且你可以指定定时器的动作事件的监听者（action listener）。启动定时器后，动作监听者的actionPerformed()方法会被（多次）调用来执行操作。 <br />
定时器动作监听者（action listener）定义的actionPerformed()方法将在事件派发线程中调用。这意味着你不必在其中使用invokeLater()方法。 <br />
这是一个使用Timer类来实现动画循环的例子： </p>
<p><br />
public class AnimatorApplicationTimer&nbsp; <br />
&nbsp; extends JFrame implements&nbsp; <br />
&nbsp; ActionListener { <br />
&nbsp;&nbsp;&nbsp; ...//在这里定义实例变量 <br />
&nbsp;&nbsp;&nbsp; Timer timer; </p>
<p>&nbsp;&nbsp;&nbsp; public AnimatorApplicationTimer(...) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 创建一个定时器来&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 来调用此对象action handler。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer = new Timer(delay, this); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.setInitialDelay(0); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.setCoalesce(true); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp; } </p>
<p>&nbsp;&nbsp;&nbsp; public void startAnimation() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (frozen) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 什么都不做。应用户要求&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 停止变换图像。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 启动（或重启动）动画！ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.start(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; } </p>
<p>&nbsp;&nbsp;&nbsp; public void stopAnimation() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 停止动画线程。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.stop(); <br />
&nbsp;&nbsp;&nbsp; } </p>
<p>&nbsp;&nbsp;&nbsp; public void actionPerformed <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (ActionEvent e) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 进到下一帧动画。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frameNumber++; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 显示。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; repaint(); <br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; ... <br />
} </p>
<p>在一个线程中执行所有的用户界面代码有这样一些优点： </p>
<p>组件开发者不必对线程编程有深入的理解：像ViewPoint和Trestle这类工具包中的所有组件都必须完全支持多线程访问，使得扩展非常困难，尤其对不精通线程编程的开发者来说。最近的一些工具包如SubArctic和IFC，都采用和Swing类似的设计。 </p>
<p>事件以可预知的次序派发：invokeLater()排队的runnable对象从鼠标和键盘事件、定时器事件、绘制请求的同一个队列派发。在一些组件完全支持多线程访问的工具包中，组件的改变被变化无常的线程调度程序穿插到事件处理过程中。这使得全面测试变得困难甚至不可能。 </p>
<p>更低的代价：尝试小心锁住临界区的工具包要花费实足的时间和空间在锁的管理上。每当工具包中调用某个可能在客户代码中实现的方法时（如public类中的任何public和protected方法），工具包都要保存它的状态并释放所有锁，以便客户代码能在必要时获得锁。当控制权交回到工具包，工具包又必须重新抓住它的锁并恢复状态。所有应用程序都不得不负担这一代价，即使大多数应用程序并不需要对GUI的并发访问。 </p>
<p>这是的SubArctic Java Toolkit的作者对在工具包中支持多线程访问的问题的描述： <br />
我们的基本信条是，当设计和建造多线程应用程序，尤其是那些包括GUI组件的应用程序时，必须保证极端小心。线程的使用可能会很有欺骗性。在许多情况下，它们表现得能够极好的简化编成，使得设计&#8220;专注于单一任务的简单自治实体&#8221;成为可能。在一些情况下它们的确简化了设计和编码。然而，在几乎所有的情况下，它们都使得调试、测试和维护的困难大大增加甚至成为不可能。无论大多数程序员所受的训练、他们的经验和实践，还是我们用来帮助自己的工具，都不是能够用来对付非决定论的。例如，全面测试（这总是困难的）在bug依赖于时间时是几乎不可能的。尤其对于Java来说，一个程序要运行在许多不同类型的机器的操作系统平台上，并且每个程序都必须在抢先和非抢先式调度下都能正常工作。 <br />
由于这些固有的困难，我们力劝你三思是否绝对有使用线程的必要。尽管如此，有些情况下使用线程是必要的（或者是被其他软件包强加的），所以subArctic提供了一个线程安全的访问机制。本章讨论了这一机制和怎样在一个独立线程中安全地操作交互树。 <br />
他们所说的线程安全机制非常类似于SwingUtilities类提供的invokeLater()和invokeAndWait()方法。</font></p>
<img src ="http://www.blogjava.net/lishen226/aggbug/298965.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-10-20 09:49 <a href="http://www.blogjava.net/lishen226/archive/2009/10/20/298965.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Swing学习笔记之swing渲染基本原理</title><link>http://www.blogjava.net/lishen226/archive/2009/10/20/298927.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Tue, 20 Oct 2009 01:26:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/10/20/298927.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/298927.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/10/20/298927.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/298927.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/298927.html</trackback:ping><description><![CDATA[<p><font style="background-color: #cce8cf">Swing学习笔记之swing渲染基本原理</font></p>
<p><font style="background-color: #cce8cf">主要内容：事件，绘制，渲染，双缓冲，线程</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">一、 事件</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">1、事件来源：本地系统，应用程序本身</font></p>
<p><font style="background-color: #cce8cf">2、所有的事件都存储在一个队列里面</font></p>
<p><font style="background-color: #cce8cf">3、Java.awt.EventQueue从队列中取数据并派发，EventQueue的派发机制由单独的线程EDT（Event Dispatch Thread）处理。</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">二、绘制</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">1、绘制请求发起：awt或者swing本身、对swing发起请求</font></p>
<p><font style="background-color: #cce8cf">2、异步重绘请求：所有异步请求都是repaint()的变体，包括整个组建的绘制和组建某个区域的绘制</font></p>
<p><font style="background-color: #cce8cf">3、同步绘制请求：Jcomponent.paintImmediately()和Component.paint()</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">三、渲染</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">1、画家算法</font></p>
<p><font style="background-color: #cce8cf">2、paintComponent()</font></p>
<p><font style="background-color: #cce8cf">3、paint()</font></p>
<p><font style="background-color: #cce8cf">4、setpaque()</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">四、双缓冲</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">五、线程</font></p>
<p><font style="background-color: #cce8cf">1、swing线程包括：主线程（应用程序的主方法），工具包线程（扑获系统事件），EDT（将扑获的线程派发）</font></p>
<p><font style="background-color: #cce8cf">2、线程模型：单一的规则，所以要遵从此规则，尽量将事件让EDT进行派发。</font></p>
<p><font style="background-color: #cce8cf">3、invokeLater()</font></p>
<p><font style="background-color: #cce8cf">4、isEventDispatchThread()</font></p>
<p><font style="background-color: #cce8cf">5、invokeAndWait</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">六、定时器和事件派发</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">1、java.util.Timer</font></p>
<p><font style="background-color: #cce8cf">2、javax.swing.Timer</font></p>
<p><font style="background-color: #cce8cf">&nbsp;</font></p>
<p><font style="background-color: #cce8cf">七、SwingWorker</font></p>
<p><font style="background-color: #cce8cf">1、done()</font></p>
<p><font style="background-color: #cce8cf">2、doInBackground()</font></p>
<p><font style="background-color: #cce8cf">3、get</font></p>
<p><font style="background-color: #cce8cf">4、process</font></p>
<img src ="http://www.blogjava.net/lishen226/aggbug/298927.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-10-20 09:26 <a href="http://www.blogjava.net/lishen226/archive/2009/10/20/298927.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]GridBagLayout和GridBagConstraints</title><link>http://www.blogjava.net/lishen226/archive/2009/05/21/271992.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Thu, 21 May 2009 07:34:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/05/21/271992.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/271992.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/05/21/271992.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/271992.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/271992.html</trackback:ping><description><![CDATA[<p>自己想做个小程序，却在布局上犯了难，使用FlowLayout和BorderLayout这些功能不够强大，使用GridBagLayout却不会，只好求助于文档了。</p>
<p>文档对这个布局管理器介绍很详细，但是最痛苦的是英文。不过幸好它有实例，经过在网上查阅和推敲实例，终于对GridBagLayout的使用有了一个成型的了解，拿出来与大家分享。</p>
<p>GridBagLayout是一个灵活的布局管理器，部件如果想加入其中需借助GridBagConstraints，其中有若干个参数，解释如下：</p>
<p>gridx/gridy：组件的横纵坐标</p>
<p>gridwidth：组件所占列数，也是组件的宽度</p>
<p>gridheight：组件所占行数，也是组件的高度</p>
<p>fill：当组件在其格内而不能撑满其格时，通过fill的值来设定填充方式，有四个值</p>
<p>ipadx： 组件间的横向间距</p>
<p>ipady：组件间的纵向间距</p>
<p>insets：当组件不能填满其格时，通过insets来指定四周（即上下左右）所留空隙</p>
<p>anchor：同样是当组件不能填满其格时，通过anchor来设置组件的位置，anchor有两种值，绝对和相对的值分别有&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 若干个，文档中有，可自行查看</p>
<p>weightx：行的权重，通过这个属性来决定如何分配行的剩余空间</p>
<p>weighty：列的权重，通过这个属性来决定如何分配列的剩余空间</p>
<p>&nbsp;</p>
<p>还是文档实用，用例子来说话</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>import java.awt.*;</p>
<p>&nbsp;import java.util.*;</p>
<p>&nbsp;import java.applet.Applet;</p>
<p>&nbsp;</p>
<p>&nbsp;public class GridBagEx1 extends Applet {</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; protected void makebutton(String name,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GridBagLayout gridbag,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GridBagConstraints c) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Button button = new Button(name);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gridbag.setConstraints(button, c);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add(button);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public void init() {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GridBagLayout gridbag = new GridBagLayout();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GridBagConstraints c = new GridBagConstraints();</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setFont(new Font("SansSerif", Font.PLAIN, 14));</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setLayout(gridbag);</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.fill = GridBagConstraints.BOTH;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.weightx = 1.0;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button1", gridbag, c);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button2", gridbag, c);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button3", gridbag, c);</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.gridwidth = GridBagConstraints.REMAINDER; //end row</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button4", gridbag, c);</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.weightx = 0.0;&nbsp;&nbsp; //reset to the default</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button5", gridbag, c); //another row</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button6", gridbag, c);</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; c.gridwidth = GridBagConstraints.REMAINDER; //end row</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button7", gridbag, c);</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; c.gridwidth = 1;&nbsp;&nbsp;&nbsp;&nbsp; //reset to the default</p>
<p>&nbsp;&nbsp;&nbsp; c.gridheight = 2;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.weighty = 1.0;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button8", gridbag, c);</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.weighty = 0.0;&nbsp;&nbsp; //reset to the default</p>
<p>&nbsp;&nbsp;&nbsp; c.gridwidth = GridBagConstraints.REMAINDER; //end row</p>
<p>&nbsp;&nbsp;&nbsp; c.gridheight = 1;&nbsp;&nbsp; //reset to the default</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button9", gridbag, c);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makebutton("Button10", gridbag, c);</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setSize(300, 100);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String args[]) {</p>
<p>&nbsp;&nbsp;&nbsp; Frame f = new Frame("GridBag Layout Example");</p>
<p>&nbsp;&nbsp;&nbsp; GridBagEx1 ex1 = new GridBagEx1();</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; ex1.init();</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; f.add("Center", ex1);</p>
<p>&nbsp;&nbsp;&nbsp; f.pack();</p>
<p>&nbsp;&nbsp;&nbsp; f.setSize(f.getPreferredSize());</p>
<p>&nbsp;&nbsp;&nbsp; f.setVisible(true);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;}</p>
<p>&nbsp;</p>
<p>可以自行运行，查看其结果</p>
<p>文档对其各个按钮的参数设定解释如下：</p>
<p><br />
Button1, Button2, Button3: weightx = 1.0 <br />
Button4: weightx = 1.0, gridwidth = GridBagConstraints.REMAINDER <br />
Button5: gridwidth = GridBagConstraints.REMAINDER <br />
Button6: gridwidth = GridBagConstraints.RELATIVE <br />
Button7: gridwidth = GridBagConstraints.REMAINDER <br />
Button8: gridheight = 2, weighty = 1.0 <br />
Button9, Button 10: gridwidth = GridBagConstraints.REMAINDER </p>
<p>&nbsp;</p>
<p>对照着程序和运行结果，还有其参数设定，我的理解如下： </p>
<p>第一行：第一行之所以有四个按钮，关键点在于，weightx=1.0，这样就可以在前边的按钮后继续加入按钮，而button4成为行尾是因为其gridwidth = GridBagConstraints.REMAINDER，这句话就设定它是行的末尾。 <br />
第二行：既然第一行都有末尾了，那么再加入按钮的话，必定是另起一行了（这个道理）。此时加入了button5，而button5又被设定为了本行的最后一个（gridwidth = GridBagConstraints.REMAINDER），加之它又是第二行的第一个按钮，所以第二行只有一个按钮，就是button5。 <br />
第三行：button6不可避免的成为了第一个按钮，它被设定了gridwidth = GridBagConstraints.RELATIVE，表明button6要紧挨它前边的那个按钮和最后的那个按钮，也就是说它一定是倒数第二个按钮（为最后一个按钮的出现做好了准备）。button7出现了，由于有gridwidth = GridBagConstraints.REMAINDER，它就为第三行封了口。第三行结束。 <br />
第四行：这一行有一个特殊的按钮button8，它的设定为gridheight = 2, weighty = 1.0，即它占用两行一列（其实这个一列和两行都是相对的）。这一行还没封口，所以后面来的button9加在了这一行，因为它gridwidth = GridBagConstraints.REMAINDER，所以第四行封口。 <br />
第五行：这一行button8已经占据了第一个的位置（因为button8的gridheight=2），所以后来的button10加在第二，同样由于gridwidth = GridBagConstraints.REMAINDER，第五行封口。 </p>
<p>要理解GridBagLayout，最好从例子的理解开始，呵呵。 <br />
网上还有另外几篇介绍它的文章，大家也可参考 <br />
http://blog.163.com/everlee@126/blog/static/263574220089621157826/ <br />
http://hi.baidu.com/zml1003/blog/item/43728f6ee02a7bd980cb4afc.html <br />
文章出处：DIY部落(http://www.diybl.com/course/3_program/java/javajs/20090405/164188.html)</p>
 <img src ="http://www.blogjava.net/lishen226/aggbug/271992.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-05-21 15:34 <a href="http://www.blogjava.net/lishen226/archive/2009/05/21/271992.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]困扰了我一天的GridBagLayout终于解决了！</title><link>http://www.blogjava.net/lishen226/archive/2009/05/21/271854.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Thu, 21 May 2009 01:30:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/05/21/271854.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/271854.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/05/21/271854.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/271854.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/271854.html</trackback:ping><description><![CDATA[首先GridBagLayout这个布局治理器类只有一个构造函数；但是它必须和GridBagConstraints这个它的约束对象一起使用来设置组件的大小和位置！ <br />
<br />
说到这里不得不说GridBagConstraints的几个至关重要的属性fill , anchor, gridx, gridy, weightx, weighty , gridwidth, gridheight , insets ipdax ,ipday <br />
<br />
首先FILL的作用就是当组件的大小小于它的显示区域的时候设置是否改变它的大小由它的几个常量值GridBagConstraints.BOTH/NONE/VERTICAL/HORIZONTAL决定！ <br />
<br />
接着就是gridx,gridy这是组件的放置位置就不用说了 <br />
<br />
gridwidth ,gridheight这是扩大组件的显示区域的大小的一个是水平一个是垂直的 <br />
<br />
还有就是anchor是组件小于显示区域的时候组件的默认放置位置也就是东南西北中几个属性值 <br />
<br />
还有就是insets是几个组件的间距它有个构造函数new INSETS(a,b,c,d) 分别是上中下右的间距 <br />
<br />
还有就是内部的艰巨ipdax ipday 还有weightx weighty用来设置窗口变大时，各组件跟着变大的比例，当数字越大，表示组件能得到更多的空间，默认值皆为0。当然还有其它很多小细节 我很懒所以自己去官方的API
<div class="Hir246"></div>
<br />
<br />
你不要看说得这么简单但你要深刻体会其中的精髓却不轻易！！！！！！！！！！！ <br />
<br />
我自己的总结：当你设置组件的大小的时候务必要设置FILL属性假如不设那么任你怎么设置GRIDWIDTH 和GRIDHEIGHT的值那个组件是肯定不会变的还是默认值给 <br />
<br />
莫慌啊在想想啊 哦 还有当你设置了FILL为GridBagConstraints.BOTH的话你假如其它的组件不重新改设FILL那肯定水平会随着你的应用程序窗口慢慢拉大而变长！所以要记者 假如不想被拉大就必须重设它的值 <br />
<br />
还有gridwidth 和gridheight官方说的是改变显示区域的大小 但是我自己认为应该是长和宽的比例给 <br />
<br />
还有REMAINDER和RELATIVE这两个属性也很重要其中的自己慢慢体会因为用在GridBagConstraints的不同的属性上效果也不同所 <br />
<br />
RELATIVE <br />
指定此组件为其行或列（gridwidth、gridheight）中的倒数第二个组件，或者让此组件紧跟在以前添加的组件（gridx、gridy）之后 <br />
<br />
REMAINDER <br />
指定此组件是其行或列中的最后一个组件 <br />
<br />
（（ 而且默认拉大窗口不会增大显示区域 而且假如设置了 gridwidth = GridBagConstraints.REMAINDER那么即使设置了WEIGHTX=0.0这个组件和它的左面一个也会拉大！ <br />
<br />
其中的好处自己以后设计GUI是就会慢慢体会了 <br />
<br />
似乎现在只记得这么多了 <br />
<br />
假如以后想起会写的 <br />
<br />
因为我当初为了这个去BAIDU GOOGLE去搜遍了感觉都是些书书上的样 说得不太清楚 <br />
<br />
所以希望学这个的不要走弯路！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！祝大家设计GUI做得越来越漂亮！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！ <br />
<img src ="http://www.blogjava.net/lishen226/aggbug/271854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-05-21 09:30 <a href="http://www.blogjava.net/lishen226/archive/2009/05/21/271854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]java连接数据库大全</title><link>http://www.blogjava.net/lishen226/archive/2009/05/07/269349.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Thu, 07 May 2009 02:25:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/05/07/269349.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/269349.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/05/07/269349.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/269349.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/269349.html</trackback:ping><description><![CDATA[<p style="border-bottom: 1px dotted; margin: 15px auto; width: 760px" id="blogtitle_fks_085065086094088075093084094095080086086075085082085069" class="g_p_center g_t_wrap g_t_left g_t_20 g_c_pdin c07 brd01"><span style="font-family: '微软雅黑', '黑体', Arial, Helvetica, Sans-Serif">java连接数据库大全 </span><span class="g_t_10 c08">　2008-09-23 14:10</span></p>
<div style="width: 760px; margin-bottom: 20px" class="g_p_center g_t_right g_c_pdin g_h_20 c08">
<div class="g_p_left"><a style="font-size: 12px" id="aBelongClsfks_085065086094088075093084094095080086086075085082085069" class="g_c_ul c05" onclick="NEBlog.gPermaLinkPage.updownMenu.openSameClass('fks_095071081082088064081081074071084081089066080085080', 'java');" href="#">分类：java</a> </div>
<div>字号： <a style="font-size: 12px" id="bigfont" class="g_c_ul c05" onclick="NEBlog.gPermaLinkPage.updownMenu.changeFont('blogtext_fks_085065086094088075093084094095080086086075085082085069', 1);return false;" href="#">大</a><span style="display: none" id="bigfont_off" class="g_t_bold c07">大</span>&nbsp; <a style="font-size: 12px" id="middlefont" class="g_c_ul c05" onclick="NEBlog.gPermaLinkPage.updownMenu.changeFont('blogtext_fks_085065086094088075093084094095080086086075085082085069', 2);return false;" href="#">中</a><span style="display: none" id="middlefont_off" class="g_t_bold c07">中</span>&nbsp; <a style="display: none; font-size: 12px" id="smallfont" class="g_c_ul c05" onclick="NEBlog.gPermaLinkPage.updownMenu.changeFont('blogtext_fks_085065086094088075093084094095080086086075085082085069', 3);return false;" href="#">小</a><span style="display: inline" id="smallfont_off" class="g_t_bold c07">小</span> </div>
</div>
<div class="g_blog_list">
<div style="width: 760px" id="blogtext_fks_085065086094088075093084094095080086086075085082085069" class="g_t_center g_c_pdin g_p_center c07 content">
<p style="text-indent: 2em">开发中连接数据库的方式有多中,可以直接用jdbc连接,也可以配置服务器的连接池.写法也有多种,可以直接写在jsp页面中,但通常都会写个专用的类,用单态之类的设计模式把他封装起来.但其中的基本连接驱动形式代码是不变的,下面是些示例代码，你一定将jdbc的驱动程序放到服务器的类路径里，然后要在数据库里建一个表test,有两个字段比如为test1，test2，可以用下面SQL建 </p>
<p style="text-indent: 2em">create table test(test1 varchar(20),test2 varchar(20) </p>
<p style="text-indent: 2em">然后向这个表写入一条测试纪录 </p>
<p style="text-indent: 2em">那么现在开始我们的jsp和数据库之旅吧。 </p>
<p style="text-indent: 2em">一、jsp连接Oracle8/8i/9i数据库（用thin模式） </p>
<p style="text-indent: 2em">testoracle.jsp如下： </p>
<p style="text-indent: 2em">&lt;%@ page contentType="text/html;charset=gb2312"%&gt; </p>
<p style="text-indent: 2em">&lt;%@ page import="java.sql.*"%&gt; </p>
<p style="text-indent: 2em">&lt;html&gt; </p>
<p style="text-indent: 2em">&lt;body&gt; </p>
<p style="text-indent: 2em">&lt;%Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); </p>
<p style="text-indent: 2em">String url="jdbc:oracle:thin:@localhost:1521:orcl"; </p>
<p style="text-indent: 2em">//orcl为你的数据库的SID </p>
<p style="text-indent: 2em">String user="scott"; </p>
<p style="text-indent: 2em">String password="tiger"; </p>
<p style="text-indent: 2em">Connection conn= DriverManager.getConnection(url,user,password); </p>
<p style="text-indent: 2em">Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); </p>
<p style="text-indent: 2em">String sql="select * from test"; </p>
<p style="text-indent: 2em">ResultSet rs=stmt.executeQuery(sql); </p>
<p style="text-indent: 2em">while(rs.next()) {%&gt; </p>
<p style="text-indent: 2em">您的第一个字段内容为：&lt;%=rs.getString(1)%&gt; </p>
<p style="text-indent: 2em">您的第二个字段内容为：&lt;%=rs.getString(2)%&gt; </p>
<p style="text-indent: 2em">&lt;%}%&gt; </p>
<p style="text-indent: 2em">&lt;%out.print("数据库***作成功，恭喜你");%&gt; </p>
<p style="text-indent: 2em">&lt;%rs.close(); </p>
<p style="text-indent: 2em">stmt.close(); </p>
<p style="text-indent: 2em">conn.close(); </p>
<p style="text-indent: 2em">%&gt; </p>
<p style="text-indent: 2em">&lt;/body&gt; </p>
<p style="text-indent: 2em">&lt;/html&gt; </p>
<p style="text-indent: 2em">二、jsp连接Sql Server7.0/2000数据库 </p>
<p style="text-indent: 2em">testsqlserver.jsp如下： </p>
<p style="text-indent: 2em">&lt;%@ page contentType="text/html;charset=gb2312"%&gt; </p>
<p style="text-indent: 2em">&lt;%@ page import="java.sql.*"%&gt; </p>
<p style="text-indent: 2em">&lt;html&gt; </p>
<p style="text-indent: 2em">&lt;body&gt; </p>
<p style="text-indent: 2em">&lt;%Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance(); </p>
<p style="text-indent: 2em">String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs"; </p>
<p style="text-indent: 2em">//pubs为你的数据库的 </p>
<p style="text-indent: 2em">String user="sa"; </p>
<p style="text-indent: 2em">String password=""; </p>
<p style="text-indent: 2em">Connection conn= DriverManager.getConnection(url,user,password); </p>
<p style="text-indent: 2em">Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); </p>
<p style="text-indent: 2em">String sql="select * from test"; </p>
<p style="text-indent: 2em">ResultSet rs=stmt.executeQuery(sql); </p>
<p style="text-indent: 2em">while(rs.next()) {%&gt; </p>
<p style="text-indent: 2em">您的第一个字段内容为：&lt;%=rs.getString(1)%&gt; </p>
<p style="text-indent: 2em">您的第二个字段内容为：&lt;%=rs.getString(2)%&gt; </p>
<p style="text-indent: 2em">&lt;%}%&gt; </p>
<p style="text-indent: 2em">&lt;%out.print("数据库***作成功，恭喜你");%&gt; </p>
<p style="text-indent: 2em">&lt;%rs.close(); </p>
<p style="text-indent: 2em">stmt.close(); </p>
<p style="text-indent: 2em">conn.close(); </p>
<p style="text-indent: 2em">%&gt; </p>
<p style="text-indent: 2em">&lt;/body&gt; </p>
<p style="text-indent: 2em">&lt;/html&gt; </p>
<p style="text-indent: 2em">三、jsp连接DB2数据库 </p>
<p style="text-indent: 2em">testdb2.jsp如下： </p>
<p style="text-indent: 2em">&lt;%@ page contentType="text/html;charset=gb2312"%&gt; </p>
<p style="text-indent: 2em">&lt;%@ page import="java.sql.*"%&gt; </p>
<p style="text-indent: 2em">&lt;html&gt; </p>
<p style="text-indent: 2em">&lt;body&gt; </p>
<p style="text-indent: 2em">&lt;%Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance(); </p>
<p style="text-indent: 2em">String url="jdbc:db2://localhost:5000/sample"; </p>
<p style="text-indent: 2em">//sample为你的数据库名 </p>
<p style="text-indent: 2em">String user="admin"; </p>
<p style="text-indent: 2em">String password=""; </p>
<p style="text-indent: 2em">Connection conn= DriverManager.getConnection(url,user,password); </p>
<p style="text-indent: 2em">Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); </p>
<p style="text-indent: 2em">String sql="select * from test"; </p>
<p style="text-indent: 2em">ResultSet rs=stmt.executeQuery(sql); </p>
<p style="text-indent: 2em">while(rs.next()) {%&gt; </p>
<p style="text-indent: 2em">您的第一个字段内容为：&lt;%=rs.getString(1)%&gt; </p>
<p style="text-indent: 2em">您的第二个字段内容为：&lt;%=rs.getString(2)%&gt; </p>
<p style="text-indent: 2em">&lt;%}%&gt; </p>
<p style="text-indent: 2em">&lt;%out.print("数据库***作成功，恭喜你");%&gt; </p>
<p style="text-indent: 2em">&lt;%rs.close(); </p>
<p style="text-indent: 2em">stmt.close(); </p>
<p style="text-indent: 2em">conn.close(); </p>
<p style="text-indent: 2em">%&gt; </p>
<p style="text-indent: 2em">&lt;/body&gt; </p>
<p style="text-indent: 2em">&lt;/html&gt; </p>
<p style="text-indent: 2em">四、jsp连接Informix数据库 </p>
<p style="text-indent: 2em">testinformix.jsp如下： </p>
<p style="text-indent: 2em">&lt;%@ page contentType="text/html;charset=gb2312"%&gt; </p>
<p style="text-indent: 2em">&lt;%@ page import="java.sql.*"%&gt; </p>
<p style="text-indent: 2em">&lt;html&gt; </p>
<p style="text-indent: 2em">&lt;body&gt; </p>
<p style="text-indent: 2em">&lt;%Class.forName("com.informix.jdbc.IfxDriver").newInstance(); </p>
<p style="text-indent: 2em">String url = </p>
<p style="text-indent: 2em">"jdbc:informix-sqli://123.45.67.89:1533/testDB:INFORMIXSERVER=myserver; </p>
<p style="text-indent: 2em">user=testuser;password=testpassword"; </p>
<p style="text-indent: 2em">//testDB为你的数据库名 </p>
<p style="text-indent: 2em">Connection conn= DriverManager.getConnection(url); </p>
<p style="text-indent: 2em">Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); </p>
<p style="text-indent: 2em">String sql="select * from test"; </p>
<p style="text-indent: 2em">ResultSet rs=stmt.executeQuery(sql); </p>
<p style="text-indent: 2em">while(rs.next()) {%&gt; </p>
<p style="text-indent: 2em">您的第一个字段内容为：&lt;%=rs.getString(1)%&gt; </p>
<p style="text-indent: 2em">您的第二个字段内容为：&lt;%=rs.getString(2)%&gt; </p>
<p style="text-indent: 2em">&lt;%}%&gt; </p>
<p style="text-indent: 2em">&lt;%out.print("数据库***作成功，恭喜你");%&gt; </p>
<p style="text-indent: 2em">&lt;%rs.close(); </p>
<p style="text-indent: 2em">stmt.close(); </p>
<p style="text-indent: 2em">conn.close(); </p>
<p style="text-indent: 2em">%&gt; </p>
<p style="text-indent: 2em">&lt;/body&gt; </p>
<p style="text-indent: 2em">&lt;/html&gt; </p>
<p style="text-indent: 2em">五、jsp连接Sybase数据库 </p>
<p style="text-indent: 2em">testmysql.jsp如下： </p>
<p style="text-indent: 2em">&lt;%@ page contentType="text/html;charset=gb2312"%&gt; </p>
<p style="text-indent: 2em">&lt;%@ page import="java.sql.*"%&gt; </p>
<p style="text-indent: 2em">&lt;html&gt; </p>
<p style="text-indent: 2em">&lt;body&gt; </p>
<p style="text-indent: 2em">&lt;%Class.forName("com.sybase.jdbc.SybDriver").newInstance(); </p>
<p style="text-indent: 2em">String url =" jdbc:sybase:Tds:localhost:5007/tsdata"; </p>
<p style="text-indent: 2em">//tsdata为你的数据库名 </p>
<p style="text-indent: 2em">Properties sysProps = System.getProperties(); </p>
<p style="text-indent: 2em">SysProps.put("user","userid"); </p>
<p style="text-indent: 2em">SysProps.put("password","user_password"); </p>
<p style="text-indent: 2em">Connection conn= DriverManager.getConnection(url, SysProps); </p>
<p style="text-indent: 2em">Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); </p>
<p style="text-indent: 2em">String sql="select * from test"; </p>
<p style="text-indent: 2em">ResultSet rs=stmt.executeQuery(sql); </p>
<p style="text-indent: 2em">while(rs.next()) {%&gt; </p>
<p style="text-indent: 2em">您的第一个字段内容为：&lt;%=rs.getString(1)%&gt; </p>
<p style="text-indent: 2em">您的第二个字段内容为：&lt;%=rs.getString(2)%&gt; </p>
<p style="text-indent: 2em">&lt;%}%&gt; </p>
<p style="text-indent: 2em">&lt;%out.print("数据库***作成功，恭喜你");%&gt; </p>
<p style="text-indent: 2em">&lt;%rs.close(); </p>
<p style="text-indent: 2em">stmt.close(); </p>
<p style="text-indent: 2em">conn.close(); </p>
<p style="text-indent: 2em">%&gt; </p>
<p style="text-indent: 2em">&lt;/body&gt; </p>
<p style="text-indent: 2em">&lt;/html&gt; </p>
<p style="text-indent: 2em">六、jsp连接MySQL数据库 </p>
<p style="text-indent: 2em">testmysql.jsp如下： </p>
<p style="text-indent: 2em">&lt;%@ page contentType="text/html;charset=gb2312"%&gt; </p>
<p style="text-indent: 2em">&lt;%@ page import="java.sql.*"%&gt; </p>
<p style="text-indent: 2em">&lt;html&gt; </p>
<p style="text-indent: 2em">&lt;body&gt; </p>
<p style="text-indent: 2em">&lt;%Class.forName("org.gjt.mm.mysql.Driver").newInstance(); </p>
<p style="text-indent: 2em">String url ="jdbc:mysql://localhost/softforum?user=soft&amp;password=soft1234&amp;useUnicode=true&amp;characterEncoding=8859_1" </p>
<p style="text-indent: 2em">//testDB为你的数据库名 </p>
<p style="text-indent: 2em">Connection conn= DriverManager.getConnection(url); </p>
<p style="text-indent: 2em">Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); </p>
<p style="text-indent: 2em">String sql="select * from test"; </p>
<p style="text-indent: 2em">ResultSet rs=stmt.executeQuery(sql); </p>
<p style="text-indent: 2em">while(rs.next()) {%&gt; </p>
<p style="text-indent: 2em">您的第一个字段内容为：&lt;%=rs.getString(1)%&gt; </p>
<p style="text-indent: 2em">您的第二个字段内容为：&lt;%=rs.getString(2)%&gt; </p>
<p style="text-indent: 2em">&lt;%}%&gt; </p>
<p style="text-indent: 2em">&lt;%out.print("数据库***作成功，恭喜你");%&gt; </p>
<p style="text-indent: 2em">&lt;%rs.close(); </p>
<p style="text-indent: 2em">stmt.close(); </p>
<p style="text-indent: 2em">conn.close(); </p>
<p style="text-indent: 2em">%&gt; </p>
<p style="text-indent: 2em">&lt;/body&gt; </p>
<p style="text-indent: 2em">&lt;/html&gt; </p>
<p style="text-indent: 2em">七、jsp连接PostgreSQL数据库 </p>
<p style="text-indent: 2em">testmysql.jsp如下： </p>
<p style="text-indent: 2em">&lt;%@ page contentType="text/html;charset=gb2312"%&gt; </p>
<p style="text-indent: 2em">&lt;%@ page import="java.sql.*"%&gt; </p>
<p style="text-indent: 2em">&lt;html&gt; </p>
<p style="text-indent: 2em">&lt;body&gt; </p>
<p style="text-indent: 2em">&lt;%Class.forName("org.postgresql.Driver").newInstance(); </p>
<p style="text-indent: 2em">String url ="jdbc:postgresql://localhost/soft" </p>
<p style="text-indent: 2em">//soft为你的数据库名 </p>
<p style="text-indent: 2em">String user="myuser"; </p>
<p style="text-indent: 2em">String password="mypassword"; </p>
<p style="text-indent: 2em">Connection conn= DriverManager.getConnection(url,user,password); </p>
<p style="text-indent: 2em">Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); </p>
<p style="text-indent: 2em">String sql="select * from test"; </p>
<p style="text-indent: 2em">ResultSet rs=stmt.executeQuery(sql); </p>
<p style="text-indent: 2em">while(rs.next()) {%&gt; </p>
<p style="text-indent: 2em">您的第一个字段内容为：&lt;%=rs.getString(1)%&gt; </p>
<p style="text-indent: 2em">您的第二个字段内容为：&lt;%=rs.getString(2)%&gt; </p>
<p style="text-indent: 2em">&lt;%}%&gt; </p>
<p style="text-indent: 2em">&lt;%out.print("数据库***作成功，恭喜你");%&gt; </p>
<p style="text-indent: 2em">&lt;%rs.close(); </p>
<p style="text-indent: 2em">stmt.close(); </p>
<p style="text-indent: 2em">conn.close(); </p>
<p style="text-indent: 2em">%&gt; </p>
<p style="text-indent: 2em">&lt;/body&gt; </p>
<p style="text-indent: 2em">&lt;/html&gt; </p>
<p style="text-indent: 2em">八.连接access例子</p>
<p style="text-indent: 2em">public class AccessTest {</p>
<p style="text-indent: 2em">&nbsp;public static void main(String args[]) {</p>
<p style="text-indent: 2em">&nbsp; try {</p>
<p style="text-indent: 2em">&nbsp;&nbsp; String strurl = "jdbc:odbc:MS Access Database;DBQ=d:\\books.mdb";</p>
<p style="text-indent: 2em">&nbsp;&nbsp; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");</p>
<p style="text-indent: 2em">&nbsp;&nbsp; Connection conn = DriverManager.getConnection(strurl, "", "");</p>
<p style="text-indent: 2em">&nbsp;&nbsp; Statement stmt = conn.createStatement();</p>
<p style="text-indent: 2em">&nbsp;&nbsp; ResultSet rs = stmt.executeQuery("select * from books");</p>
<p style="text-indent: 2em">&nbsp;&nbsp; while (rs.next())</p>
<p style="text-indent: 2em">&nbsp;&nbsp; {</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp; System.out.print(rs.getString(1) + "&nbsp; ");</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp; System.out.print(rs.getString(2));</p>
<p style="text-indent: 2em">&nbsp;&nbsp; }</p>
<p style="text-indent: 2em">&nbsp; } catch (Exception e) {</p>
<p style="text-indent: 2em">&nbsp;&nbsp; System.out.println(e);</p>
<p style="text-indent: 2em">&nbsp; }</p>
<p style="text-indent: 2em">&nbsp;}</p>
<p style="text-indent: 2em">}</p>
</div>
二、JDBC连接MySql方式<br />
<br />
下面是使用JDBC连接MySql的一个小的教程 <br />
<br />
1、查找驱动程序<br />
<br />
MySQL目前提供的java驱动程序为Connection/J，可以从MySQL官方网站下载，并找到mysql-connector-java-3.0.15-ga-bin.jar文件，此驱动程序为纯java驱动程序，不需做其他配置。<br />
<br />
2、动态指定classpath<br />
<br />
如果需要执行时动态指定classpath，就在执行时采用－cp方式。否则将上面的.jar文件加入到classpath环境变量中。<br />
<br />
3、加载驱动程序<br />
<br />
try{<br />
Class.forName(com.mysql.jdbc.Driver);<br />
System.out.println(Success loading Mysql Driver!);<br />
}catch(Exception e)<br />
{<br />
System.out.println(Error loading Mysql Driver!);<br />
e.printStackTrace();<br />
}<br />
<br />
4、设置连接的url<br />
<br />
jdbc：mysql：//localhost/databasename[?pa=va][＆pa=va]　　<br />
<br />
三、以下列出了在使用JDBC来连接Oracle数据库时可以使用的一些技巧<br />
<br />
1、在客户端软件开发中使用Thin驱动程序<br />
<br />
在开发Java软件方面，Oracle的数据库提供了四种类型的驱动程序，二种用于应用软件、applets、servlets等客户端软件，另外二种 用于数据库中的Java存储过程等服务器端软件。在客户机端软件的开发中，我们可以选择OCI驱动程序或Thin驱动程序。OCI驱动程序利用Java本 地化接口（JNI），通过Oracle客户端软件与数据库进行通讯。Thin驱动程序是纯Java驱动程序，它直接与数据库进行通讯。为了获得最高的性 能，Oracle建议在客户端软件的开发中使用OCI驱动程序，这似乎是正确的。但我建议使用Thin驱动程序，因为通过多次测试发现，在通常情况 下，Thin驱动程序的性能都超过了OCI驱动程序。<br />
<br />
2、关闭自动提交功能，提高系统性能<br />
<br />
在第一次建立与数据库的连接时，在缺省情况下，连接是在自动提交模式下的。为了获得更好的性能，可以通过调用带布尔值false参数的Connection类的setAutoCommit()方法关闭自动提交功能，如下所示：<br />
<br />
conn.setAutoCommit(false);<br />
<br />
值得注意的是，一旦关闭了自动提交功能，我们就需要通过调用Connection类的commit()和rollback()方法来人工的方式对事务进行管理。<br />
<br />
3、在动态SQL或有时间限制的命令中使用Statement对象<br />
<br />
在执行SQL命令时，我们有二种选择：可以使用PreparedStatement对象，也可以使用Statement对象。无论多少次地使用同一个 SQL命令，PreparedStatement都只对它解析和编译一次。当使用Statement对象时，每次执行一个SQL命令时，都会对它进行解析 和编译。这可能会使你认为，使用PreparedStatement对象比使用Statement对象的速度更快。然而，我进行的测试表明，在客户端软件 中，情况并非如此。因此，在有时间限制的SQL操作中，除非成批地处理SQL命令，我们应当考虑使用Statement对象。<br />
<br />
此外，使用Statement对象也使得编写动态SQL命令更加简单，因为我们可以将字符串连接在一起，建立一个有效的SQL命令。因此，我认为，Statement对象可以使动态SQL命令的创建和执行变得更加简单。<br />
<br />
4、利用helper函数对动态SQL命令进行格式化<br />
<br />
在创建使用Statement对象执行的动态SQL命令时，我们需要处理一些格式化方面的问题。例如，如果我们想创建一个将名字O'Reilly插入表 中的SQL命令，则必须使用二个相连的&#8220;''&#8221;号替换O'Reilly中的&#8220;'&#8221;号。完成这些工作的最好的方法是创建一个完成替换操作的helper方 法，然后在连接字符串心服用公式表达一个SQL命令时，使用创建的helper方法。与此类似的是，我们可以让helper方法接受一个Date型的值， 然后让它输出基于Oracle的to_date()函数的字符串表达式。<br />
<br />
5、利用PreparedStatement对象提高数据库的总体效率<br />
<br />
在使用PreparedStatement对象执行SQL命令时，命令被数据库进行解析和编译，然后被放到命令缓冲区。然后，每当执行同一个 PreparedStatement对象时，它就会被再解析一次，但不会被再次编译。在缓冲区中可以发现预编译的命令，并且可以重新使用。在有大量用户的 企业级应用软件中，经常会重复执行相同的SQL命令，使用PreparedStatement对象带来的编译次数的减少能够提高数据库的总体性能。如果不 是在客户端创建、预备、执行PreparedStatement任务需要的时间长于Statement任务，我会建议在除动态SQL命令之外的所有情况下 使用PreparedStatement对象。<br />
<br />
6、在成批处理重复的插入或更新操作中使用PreparedStatement对象<br />
<br />
如果成批地处理插入和更新操作，就能够显著地减少它们所需要的时间。Oracle提供的Statement和 CallableStatement并不真正地支持批处理，只有PreparedStatement对象才真正地支持批处理。我们可以使用 addBatch()和executeBatch()方法选择标准的JDBC批处理，或者通过利用PreparedStatement对象的 setExecuteBatch()方法和标准的executeUpdate()方法选择速度更快的Oracle专有的方法。要使用Oracle专有的批 处理机制，可以以如下所示的方式调用setExecuteBatch()：<br />
<br />
PreparedStatement pstmt3D null;<br />
try {<br />
((OraclePreparedStatement)pstmt).setExecuteBatch(30);<br />
...<br />
pstmt.executeUpdate();<br />
} <br />
调用setExecuteBatch()时指定的值是一个上限，当达到该值时，就会自动地引发SQL命令执行，标准的executeUpdate()方 法就会被作为批处理送到数据库中。我们可以通过调用PreparedStatement类的sendBatch()方法随时传输批处理任务。<br />
<br />
7、使用Oracle locator方法插入、更新大对象（LOB）<br />
<br />
Oracle的PreparedStatement类不完全支持BLOB和CLOB等大对象的处理，尤其是Thin驱动程序不支持利用 PreparedStatement对象的setObject()和setBinaryStream()方法设置BLOB的值，也不支持利用 setCharacterStream()方法设置CLOB的值。只有locator本身中的方法才能够从数据库中获取LOB类型的值。可以使用 PreparedStatement对象插入或更新LOB，但需要使用locator才能获取LOB的值。由于存在这二个问题，因此，我建议使用 locator的方法来插入、更新或获取LOB的值。<br />
<br />
8、使用SQL92语法调用存储过程<br />
<br />
在调用存储过程时，我们可以使用SQL92或Oracle PL/SQL，由于使用Oracle PL/SQL并没有什么实际的好处，而且会给以后维护你的应用程序的开发人员带来麻烦，因此，我建议在调用存储过程时使用SQL92。<br />
<br />
9、使用Object SQL将对象模式转移到数据库中<br />
<br />
既然可以将Oracle的数据库作为一种面向对象的数据库来使用，就可以考虑将应用程序中的面向对象模式转到数据库中。目前的方法是创建Java bean作为伪装的数据库对象，将它们的属性映射到关系表中，然后在这些bean中添加方法。尽管这样作在Java中没有什么问题，但由于操作都是在数据 库之外进行的，因此其他访问数据库的应用软件无法利用对象模式。如果利用Oracle的面向对象的技术，可以通过创建一个新的数据库对象类型在数据库中模 仿其数据和操作，然后使用JPublisher等工具生成自己的Java bean类。如果使用这种方式，不但Java应用程序可以使用应用软件的对象模式，其他需要共享你的应用中的数据和操作的应用软件也可以使用应用软件中的 对象模式。<br />
<br />
10、利用SQL完成数据库内的操作<br />
<br />
我要向大家介绍的最重要的经验是充分利用SQL的面向集合的方法来解决数据库处理需求，而不是使用Java等过程化的编程语言。<br />
<br />
如果编程人员要在一个表中查找许多行，结果中的每个行都会查找其他表中的数据，最后，编程人员创建了独立的UPDATE命令来成批地更新第一个表中的数 据。与此类似的任务可以通过在set子句中使用多列子查询而在一个UPDATE命令中完成。当能够在单一的SQL命令中完成任务，何必要让数据在网上流来 流去的？我建议用户认真学习如何最大限度地发挥SQL的功能。 <br />
<br />
<strong>JDBC基础教程之驱动设置</strong> <br />
<font face="Tahoma">1、概述<br />
&nbsp;&nbsp; DriverManager 类是 JDBC 的管理层，作用于用户和驱动程序之间。它跟踪可用的驱动程序，并在数据库和相应驱动程序之间建立连接。另外，DriverManager 类也处理诸如驱动程序登录时间限制及登录和跟踪消息的显示等事务。<br />
&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;<br />
<br />
对 于简单的应用程序，一般程序员需要在此类中直接使用的唯一方法是 DriverManager.getConnection。正如名称所示，该方法将建立与数据库的连接。JDBC 允许用户调用 DriverManager 的方法 getDriver、getDrivers 和 registerDriver 及 Driver 的方法 connect。但多数情况下，让 DriverManager 类管理建立连接的细节为上策。<br />
&nbsp;&nbsp; 1、跟踪可用驱动程序<br />
&nbsp;&nbsp; DriverManager 类包含一列 Driver 类，它们已通过调用方法 DriverManager.registerDriver 对自己进行了注册。所有 Driver 类都必须包含有一个静态部分。它创建该类的实例，然后在加载该实例时 DriverManager 类进行注册。这样，用户正常情况下将不会直接调用 DriverManager.registerDriver；而是在加载驱动程序时由驱动程序自动调用。加载 Driver 类，然后自动在 DriverManager 中注册的方式有两种：<br />
&nbsp;&nbsp; 通过调用方法 Class.forName。这将显式地加载驱动程序类。由于这与外部设置无关，因此推荐使用这种加载驱动程序的方法。以下代码加载类 acme.db.Driver：<br />
class.forname("acme.db.driver"); <br />
<br />
&nbsp;&nbsp; 如果将 acme.db.Driver 编写为加载时创建实例，并调用以该实例为参数的 DriverManager.registerDriver（本该如此），则它在 DriverManager 的驱动程序列表中，并可用于创建连接。<br />
&nbsp;&nbsp; 通 过将驱动程序添加到 java.lang.System 的属性 jdbc.drivers 中。这是一个由 DriverManager 类加载的驱动程序类名的列表，由冒号分隔：初始化 DriverManager 类时，它搜索系统属性 jdbc.drivers，如果用户已输入了一个或多个驱动程序，则 DriverManager 类将试图加载它们。以下代码说明程序员如何在 ~/.hotjava/properties 中输入三个驱动程序类（启动时，HotJava 将把它加载到系统属性列表中）：<br />
&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;<br />
<br />
jdbc.drivers=foo.bah.driver:wombat.sql.driver:bad.test.ourdriver; <br />
<br />
&nbsp;&nbsp; 对 DriverManager 方法的第一次调用将自动加载这些驱动程序类。<br />
&nbsp;&nbsp; 注 意：加载驱动程序的第二种方法需要持久的预设环境。如果对这一点不能保证，则调用方法 Class.forName 显式地加载每个驱动程序就显得更为安全。这也是引入特定驱动程序的方法，因为一旦 DriverManager 类被初始化，它将不再检查 jdbc.drivers 属性列表。<br />
&nbsp;&nbsp; 在以上两种情况中，新加载的 Driver 类都要通过调用 DriverManager.registerDriver 类进行自我注册。如上所述，加载类时将自动执行这一过程。<br />
&nbsp;&nbsp; 由于安全方面的原因，JDBC 管理层将跟踪哪个类加载器提供哪个驱动程序。这样，当 DriverManager 类打开连接时，它仅使用本地文件系统或与发出连接请求的代码相同的类加载器提供的驱动程序。<br />
&nbsp;&nbsp; 2、建立连接<br />
&nbsp;&nbsp; 加 载 Driver 类并在 DriverManager 类中注册后，它们即可用来与数据库建立连接。当调用 DriverManager.getConnection 方法发出连接请求时，DriverManager 将检查每个驱动程序，查看它是否可以建立连接。<br />
&nbsp;&nbsp; 有时可能有多个 JDBC 驱动程序可以与给定的 URL 连接。例如，与给定远程数据库连接时，可以使用 JDBC-ODBC 桥驱动程序、JDBC 到通用网络协议驱动程序或数据库厂商提供的驱动程序。在这种情况下，测试驱动程序的顺序至关重要，因为 DriverManager 将使用它所找到的第一个可以成功连接到给定 URL 的驱动程序。<br />
&nbsp;&nbsp; 首先 DriverManager 试图按注册的顺序使用每个驱动程序（jdbc.drivers 中列出的驱动程序总是先注册）。它将跳过代码不可信任的驱动程序，除非加载它们的源与试图打开连接的代码的源相同。<br />
&nbsp;&nbsp; 它通过轮流在每个驱动程序上调用方法 Driver.connect，并向它们传递用户开始传递给方法 DriverManager.getConnection 的 URL 来对驱动程序进行测试，然后连接第一个认出该 URL 的驱动程序。<br />
&nbsp;&nbsp; 这种方法初看起来效率不高，但由于不可能同时加载数十个驱动程序，因此每次连接实际只需几个过程调用和字符串比较。<br />
&nbsp;&nbsp; 以下代码是通常情况下用驱动程序（例如 JDBC-ODBC 桥驱动程序）建立连接所需所有步骤的示例：<br />
&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //加载驱动程序 <br />
<br />
&nbsp;&nbsp; String url = "jdbc:dbc:fred";<br />
&nbsp;&nbsp; DriverManager.getConnection(url, "userID", "passwd");</font><br />
</div>
<img src ="http://www.blogjava.net/lishen226/aggbug/269349.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-05-07 10:25 <a href="http://www.blogjava.net/lishen226/archive/2009/05/07/269349.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]dom4j实例</title><link>http://www.blogjava.net/lishen226/archive/2009/05/06/269156.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Wed, 06 May 2009 01:30:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/05/06/269156.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/269156.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/05/06/269156.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/269156.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/269156.html</trackback:ping><description><![CDATA[<h3 class="type_reprint" title="转载"><a href="/blog/306572">dom4j实例</a></h3>
<p class="type_reprint" title="转载">http://haiyupeter.javaeye.com/blog/306572</p>
<strong>关键字: dom4j实例</strong>
<div class="blog_content">
<p>&nbsp;国外的dom4j已经很流行了，国内的相关资料相对较少，但普及风暴也即将到来。我们公司（老外开的）解析XML就是用的dom4j。<br />
&nbsp; 今天公司没事做，自己也写一个小例子贴上来，嘻~~<br />
&nbsp;<br />
books.xml:</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Xml代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#"><img alt="复制代码" src="http://www.blogjava.net/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-xml">
    <li><span><span class="tag">&lt;?</span><span class="tag-name">xml</span><span>&nbsp;</span><span class="attribute">version</span><span>=</span><span class="attribute-value">"1.0"</span><span>&nbsp;</span><span class="attribute">encoding</span><span>=</span><span class="attribute-value">"UTF-8"</span><span class="tag">?&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span class="tag">&lt;</span><span class="tag-name">books</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comments">&lt;!--This&nbsp;is&nbsp;a&nbsp;test&nbsp;for&nbsp;dom4j,&nbsp;jakoes,&nbsp;2007.7.19--&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">book</span><span>&nbsp;</span><span class="attribute">show</span><span>=</span><span class="attribute-value">"yes"</span><span>&nbsp;</span><span class="attribute">url</span><span>=</span><span class="attribute-value">"lucene.net"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">title</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">"456"</span><span class="tag">&gt;</span><span>Lucene&nbsp;Studing</span><span class="tag">&lt;/</span><span class="tag-name">title</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">book</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">book</span><span>&nbsp;</span><span class="attribute">show</span><span>=</span><span class="attribute-value">"yes"</span><span>&nbsp;</span><span class="attribute">url</span><span>=</span><span class="attribute-value">"dom4j.com"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">title</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">"123"</span><span class="tag">&gt;</span><span>Dom4j&nbsp;Tutorials</span><span class="tag">&lt;/</span><span class="tag-name">title</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">book</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">book</span><span>&nbsp;</span><span class="attribute">show</span><span>=</span><span class="attribute-value">"no"</span><span>&nbsp;</span><span class="attribute">url</span><span>=</span><span class="attribute-value">"spring.org"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">title</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">"789"</span><span class="tag">&gt;</span><span>Spring&nbsp;in&nbsp;Action</span><span class="tag">&lt;/</span><span class="tag-name">title</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">book</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">owner</span><span class="tag">&gt;</span><span>O'Reilly</span><span class="tag">&lt;/</span><span class="tag-name">owner</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span class="tag">&lt;/</span><span class="tag-name">books</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre style="display: none" class="xml" name="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;books&gt;
&lt;!--This is a test for dom4j, jakoes, 2007.7.19--&gt;
&lt;book show="yes" url="lucene.net"&gt;
&lt;title id="456"&gt;Lucene Studing&lt;/title&gt;
&lt;/book&gt;
&lt;book show="yes" url="dom4j.com"&gt;
&lt;title id="123"&gt;Dom4j Tutorials&lt;/title&gt;
&lt;/book&gt;
&lt;book show="no" url="spring.org"&gt;
&lt;title id="789"&gt;Spring in Action&lt;/title&gt;
&lt;/book&gt;
&lt;owner&gt;O'Reilly&lt;/owner&gt;
&lt;/books&gt;</pre>
&nbsp;
<p><br />
<br />
下面我们使用dom4j的xPath来解析：<br />
<br />
segment of ParseXML.java:<br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#"><img alt="复制代码" src="http://www.blogjava.net/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;parseBooks(){ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;SAXReader&nbsp;reader&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;SAXReader(); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Document&nbsp;doc&nbsp;=&nbsp;reader.read(</span><span class="string">"books.xml"</span><span>); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;root&nbsp;=&nbsp;doc.selectSingleNode(</span><span class="string">"/books"</span><span>); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&nbsp;list&nbsp;=&nbsp;root.selectNodes(</span><span class="string">"book[@url='dom4j.com']"</span><span>); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>(Object&nbsp;o:list){ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Element&nbsp;e&nbsp;=&nbsp;(Element)&nbsp;o; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;show=e.attributeValue(</span><span class="string">"show"</span><span>); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"show&nbsp;=&nbsp;"</span><span>&nbsp;+&nbsp;show); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(Exception&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre style="display: none" class="java" name="code">    public void parseBooks(){
SAXReader reader = new SAXReader();
try {
Document doc = reader.read("books.xml");
Node root = doc.selectSingleNode("/books");
List list = root.selectNodes("book[@url='dom4j.com']");
for(Object o:list){
Element e = (Element) o;
String show=e.attributeValue("show");
System.out.println("show = " + show);
}
} catch (Exception e) {
e.printStackTrace();
}
}
</pre>
&nbsp;
<p><br />
&nbsp; Document doc = reader.read("books.xml");的意思是加载XML文档，此是可以用doc.asXML()来查看，它将打印整个xml文档。<br />
<br />
&nbsp; Node root = doc.selectSingleNode("/books");是读取刚才加载的xml文档内的books节点下的所有内容，对于本例也是整个xml文档。<br />
&nbsp; 当然我们也可以加载/books下的某一个节点，如：book节点<br />
Node root = doc.selectSingleNode("/books/book");<br />
或：Node root = doc.selectSingleNode("/books/*");<br />
注意：如果有多个book节点，它只会读取第一个<br />
root.asXML()将打印：<br />
&lt;book show="yes" url="lucene.net"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;title id="456"&gt;Lucene Studing&lt;/title&gt;<br />
&lt;/book&gt;<br />
<br />
&nbsp; 既然加载了这么多，那我怎么精确的得到我想要的节点呢，别急，看下面：<br />
List list = root.selectNodes("book[@url='dom4j.com']");<br />
它的意思就是读取books节点下的book节点，且book的节点的url属性为dom4j.com<br />
为什么使用list来接收呢，如果有两个book节点，且它们的url属性都为dom4j.com，此时就封闭到list里了。<br />
<br />
&nbsp; 如果想读取books下的所有book节点，可以这样：<br />
List list = root.selectNodes("book");<br />
<br />
&nbsp; 如果想读取books节点下的book节点下的title节点，可以这样：<br />
List list2 = root.selectNodes("book[@url='dom4j.com']/title[@id='123']");<br />
<br />
&nbsp; 注意：selectNodes()参数的格式：<br />
&nbsp; 节点名[@属性名='属性值']，如：book[@url='dom4j.com']<br />
&nbsp; 如果有多个节点，用&#8220;/&#8221;分开，如：book[@url='dom4j.com']/title[@id='123']<br />
<br />
&nbsp; 最近就是读取封闭在List里的内容了，可以用Node来读取，也可以用Element来转换。<br />
attributeValue("属性")是读取该节点的属性值<br />
getText()是读取节点的的内容。</p>
</div>
 <img src ="http://www.blogjava.net/lishen226/aggbug/269156.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-05-06 09:30 <a href="http://www.blogjava.net/lishen226/archive/2009/05/06/269156.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]js中innerHTML与innerText的用法与区别 </title><link>http://www.blogjava.net/lishen226/archive/2009/04/02/263529.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Thu, 02 Apr 2009 06:00:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/04/02/263529.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/263529.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/04/02/263529.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/263529.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/263529.html</trackback:ping><description><![CDATA[<div class="postTitle"><a id="viewpost1_TitleUrl" class="postTitle2" href="http://www.phpweblog.net/kiyone/archive/2007/05/17/1206.html">js中innerHTML与innerText的用法与区别</a> </div>
<div>
<p>用法：<br />
<br />
&lt;div&nbsp;id="test"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;span&nbsp;style="color:red"&gt;test1&lt;/span&gt;&nbsp;test2<br />
&lt;/div&gt;<br />
<br />
在JS中可以使用：<br />
<br />
<strong>test.innerHTML</strong>:</p>
<p>　　也就是从对象的起始位置到终止位置的全部内容,包括Html标签。 </p>
<p>　　上例中的test.innerHTML的值也就是&#8220;&lt;span&nbsp;style="color:red"&gt;test1&lt;/span&gt;&nbsp;test2 &#8221;。<br />
<br />
<strong>test.innerText:</strong>&nbsp;</p>
<p>　　从起始位置到终止位置的内容,&nbsp;但它去除Html标签&nbsp;</p>
<p>　　上例中的text.innerTest的值也就是&#8220;test1&nbsp;test2&#8221;,&nbsp;其中span标签去除了。 </p>
<p><strong>test.outerHTML:</strong></p>
<p><strong>　　</strong>除了包含innerHTML的全部内容外,&nbsp;还包含对象标签本身。</p>
<p>　　上例中的text.outerHTML的值也就是&lt;div&nbsp;id="test"&gt;&lt;span&nbsp;style="color:red"&gt;test1&lt;/span&gt;&nbsp;test2&lt;/div&gt;</p>
<p><strong><br />
完整示例：</strong></p>
<p>&lt;div&nbsp;id="test"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;span&nbsp;style="color:red"&gt;test1&lt;/span&gt;&nbsp;test2<br />
&lt;/div&gt;<br />
<br />
&lt;a href="javascript:alert(test.innerHTML)"&gt;innerHTML内容&lt;/a&gt;<br />
&lt;a href="javascript:alert(test.innerText)"&gt;inerHTML内容&lt;/a&gt;<br />
&lt;a href="javascript:alert(test.outerHTML)"&gt;outerHTML内容&lt;/a&gt;<br />
<br />
<strong>特别说明：</strong></p>
<p><strong>　　</strong>innerHTML是符合W3C标准的属性，而innerText只适用于IE浏览器，因此，尽可能地去使用innerHTML，而少用innerText，如果要输出不含HTML标签的内容，可以使用innerHTML取得包含HTML标签的内容后，再用正则表达式去除HTML标签，下面是一个简单的符合W3C标准的示例：<br />
<br />
&lt;a href="javascript:alert(document.getElementById('test').innerHTML.replace(/&lt;.+?&gt;/gim,''))"&gt;无HTML,符合W3C标准&lt;/a&gt;<br />
<br />
-------------------------------------------------------------------------------------------------------------------------------<br />
<br />
&lt;html&gt;<br />
&lt;head&gt;&lt;/head&gt;<br />
&lt;frameset frameborder="yes" frameborder="1" rows="40%,*"&gt;<br />
&lt;frame name="top" src="1.html"&gt;<br />
&lt;frame name="bottom" src="2.html"&gt;<br />
&lt;/frameset&gt;<br />
&lt;/html&gt;<br />
<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;script language="javascript"&gt;<br />
function init()<br />
{&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; var aaa = parent.window.frames[0].document.body.innerHTML; <br />
&nbsp;&nbsp;&nbsp; alert(aaa);<br />
}<br />
&lt;/script&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;p align="center"&gt;nothing&lt;/p&gt;<br />
&lt;p align="center"&gt;&lt;input type="button" onclick="init()"; value="click"&gt;&lt;/p&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;<br />
<br />
&lt;html&gt;<br />
&lt;center&gt;汽车 房产 女人&lt;/center&gt;<br />
&lt;/html&gt;<br />
</p>
</div>
 <img src ="http://www.blogjava.net/lishen226/aggbug/263529.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-04-02 14:00 <a href="http://www.blogjava.net/lishen226/archive/2009/04/02/263529.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>dwr配置文件dwr.xml祥解</title><link>http://www.blogjava.net/lishen226/archive/2009/03/16/259927.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Mon, 16 Mar 2009 01:13:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/03/16/259927.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/259927.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/03/16/259927.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/259927.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/259927.html</trackback:ping><description><![CDATA[<div class="tit">dwr配置文件dwr.xml祥解</div>
<div class="date">2007-08-10 00:16</div>
<table style="table-layout: fixed">
    <tbody>
        <tr>
            <td>
            <div class="cnt" id="blog_text">
            <p>本人对dwr 中文文档关于dwr.xml做的一个整理,纯粹体力活，有用得着的朋友别忘顶一下，留个联系方式一起交流学习！</p>
            <p>dwr.xml是DWR的配置文件。默认情况下，应该把它放到WEB-INF目录(web.xml的目录)下</p>
            <h2><a name="dwr.xml-%E5%88%9B%E5%BB%BAdwr.xml%E6%96%87%E4%BB%B6"></a>创建dwr.xml文件</h2>
            <p>dwr.xml文件的结构如下:</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-xml">&lt;!DOCTYPE dwr PUBLIC&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-quote">"-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-quote">"http://www.getahead.ltd.uk/dwr/dwr10.dtd"</span>&gt;<span class="code-tag">&lt;dwr&gt;</span>&nbsp;&nbsp;<span class="code-tag"><span class="code-comment">&lt;!-- init is only needed if you are extending DWR --&gt;</span></span>&nbsp;&nbsp;<span class="code-tag">&lt;init&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;creator id=<span class="code-quote">"..."</span> class=<span class="code-quote">"..."</span>/&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;converter id=<span class="code-quote">"..."</span> class=<span class="code-quote">"..."</span>/&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;/init&gt;</span>&nbsp;&nbsp;<span class="code-tag"><span class="code-comment">&lt;!-- without allow, DWR isn't allowed to do anything --&gt;</span></span>&nbsp;&nbsp;<span class="code-tag">&lt;allow&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;create creator=<span class="code-quote">"..."</span> javascript=<span class="code-quote">"..."</span>/&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;convert converter=<span class="code-quote">"..."</span> match=<span class="code-quote">"..."</span>/&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;/allow&gt;</span>&nbsp;&nbsp;<span class="code-tag"><span class="code-comment">&lt;!-- you may need to tell DWR about method signatures --&gt;</span></span>&nbsp;&nbsp;<span class="code-tag">&lt;signatures&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp; ...&nbsp;&nbsp;<span class="code-tag">&lt;/signatures&gt;</span><span class="code-tag">&lt;/dwr&gt;</span></pre>
            </div>
            </div>
            <h2><a name="dwr.xml-%E6%9C%AF%E8%AF%AD"></a>术语</h2>
            <p>这里是一些必须理解的术语 - 参数会被<strong>converted</strong>，远程Bean会被<strong>created</strong>。所以如果你有一个叫A的bean，它有一个方法叫A.blah(B) 那么你需要一个A的<strong>creator</strong>和一个B的<strong>converter</strong>。</p>
            <h2><a name="dwr.xml-%3Callow%3E"></a>一：&lt;allow&gt;</h2>
            <p><em>allow</em>段落里面定义的试DWR可以创建和转换的类。</p>
            <h2><a name="dwr.xml-Creators"></a>二：Creators</h2>
            <p>dwr.xml文件中的create元素的结构如下：</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-xml"><span class="code-tag">&lt;allow&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;create creator=<span class="code-quote">"..."</span> javascript=<span class="code-quote">"..."</span> scope=<span class="code-quote">"..."</span>&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;param name=<span class="code-quote">"..."</span> value=<span class="code-quote">"..."</span>/&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;auth method=<span class="code-quote">"..."</span> role=<span class="code-quote">"..."</span>/&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;exclude method=<span class="code-quote">"..."</span>/&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;include method=<span class="code-quote">"..."</span>/&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;/create&gt;</span>&nbsp;&nbsp; ...<span class="code-tag">&lt;/allow&gt;</span></pre>
            </div>
            </div>
            <p>这里的多数元素都是可选的 - 你真正必须知道的是指定一个creator和一个javascript名字。</p>
            <p><strong>creator属性</strong> 是必须的 - 它用来指定使用那种创造器。</p>
            <p>默认情况下DWR1.1有8种创造器。它们是：</p>
            <ul>
                <li><a href="http://blog.csdn.net/phevose/archive/2007/05/16/1611601.aspx#new">new</a>: 用Java的new关键字创造对象。
                <li><a title="None Creator on Creators" href="http://blog.csdn.net/phevose/archive/2007/05/16/1611601.aspx#none">none</a>: 它不创建对象，看下面的原因。 (v1.1+)
                <li><a title="Scripted Creator" href="http://blog.csdn.net/phevose/archive/2007/05/16/1611601.aspx#scripted">scripted</a>: 通过BSF使用脚本语言创建对象，例如BeanShell或Groovy。
                <li><a title="Spring Integration" href="http://blog.csdn.net/phevose/archive/2007/05/16/1611601.aspx#spring">spring</a>: 通过Spring框架访问Bean。
                <li><a title="JSF Integration" href="http://blog.csdn.net/phevose/archive/2007/05/16/1611601.aspx#JSF">jsf</a>: 使用JSF的Bean。 (v1.1+)
                <li><a title="Struts Integration" href="http://blog.csdn.net/phevose/archive/2007/05/16/1611601.aspx#Struts">struts</a>: 使用Struts的FormBean。 (v1.1+)
                <li><a title="Beehive Integration" href="http://blog.csdn.net/phevose/archive/2007/05/16/1611601.aspx#pageflow">pageflow</a>: 访问Beehive或Weblogic的PageFlow。 (v1.1+) </li>
            </ul>
            <p>&nbsp;</p>
            <p>如果你需要写自己的创造器，你必须在init部分注册它。</p>
            <p><strong>javascript属性</strong> 用于指定浏览器中这个被创造出来的对象的名字。你不能使用Javascript的关键字。</p>
            <p><strong>scope属性</strong> 非常类似servlet规范中的scope。 它允许你指定这个bean在什么生命范围。选项有"application", "session", "request" 和"page"。这些值对于Servlet和JSP开发者来说应该相当熟悉了。</p>
            <p>scope属性是可选的。默认是"page"。如果要使用"session"需要cookies。当前的DWR不支持ULR重写。</p>
            <p><strong>param元素</strong> 被用来指定创造器的其他参数，每种构造器各有不同。例如，"new"创造器需要知道要创建的对象类型是什么。每一个创造器的参数在各自的文档中能找到。请查看上面的链接。</p>
            <p><strong>include和exclude元素</strong> 允许创造器来限制类中方法的访问。一个创造器必须指定include列表或exclude列表之一。如果是include列表则暗示默认的访问策略是"拒绝"；如果是exclude列表则暗示默认的访问策略是"允许"。</p>
            <p>例如要拒绝防范除了<em>setWibble()</em>以外的所有方法，你应该把如下内容添加到dwr.xml中。</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-xml"><span class="code-tag">&lt;create creator=<span class="code-quote">"new"</span> javascript=<span class="code-quote">"Fred"</span>&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;param name=<span class="code-quote">"class"</span> value=<span class="code-quote">"com.example.Fred"</span>/&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;include method=<span class="code-quote">"setWibble"</span>/&gt;</span><span class="code-tag">&lt;/create&gt;</span></pre>
            </div>
            </div>
            <p>对于加入到create元素中的类的所有方法都是默认可见的。</p>
            <p><strong>auth元素</strong> 允许你指定一个J2EE的角色作为将来的访问控制检查:</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-xml"><span class="code-tag">&lt;create creator=<span class="code-quote">"new"</span> javascript=<span class="code-quote">"Fred"</span>&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;param name=<span class="code-quote">"class"</span> value=<span class="code-quote">"com.example.Fred"</span>/&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;auth method=<span class="code-quote">"setWibble"</span> role=<span class="code-quote">"admin"</span>/&gt;</span><span class="code-tag">&lt;/create&gt;</span></pre>
            </div>
            </div>
            <hr />
            <p>&nbsp;</p>
            <p><a name="new"></a><strong><font size="3">new</font></strong>创造器在DWR中已经默认声明了：<strong>&lt;creator id="new" class="uk.ltd.getahead.dwr.create.NewCreator"/&gt;</strong> 。你不需要在dwr.xml文件中添加这段话，它已经存在于DWR的内部dwr.xml文件中了。</p>
            <p>这个创造器通过类默认的够早函数创造对象实例。用new创造器有一些好处：</p>
            <ul>
                <li>安全:DWR创造的对象生存的事件越短，多次调用中间的值不一致的错误机会越少。
                <li>内存消耗低： 如果你的站点用户量非常大，这个创造器可以减少VM的内存溢出。 </li>
            </ul>
            <p>你可以通过下面的方式使用new创造器来创造远程调用Bean：</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-xml"><span class="code-tag">&lt;allow&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;create creator=<span class="code-quote">"new"</span> javascript=<span class="code-quote">"Blah"</span>&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;param name=<span class="code-quote">"class"</span> value=<span class="code-quote">"java.util.Date"</span>/&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;/create&gt;</span>&nbsp;&nbsp; ... <span class="code-tag">&lt;/allow&gt;</span></pre>
            </div>
            </div>
            <p>这些代码把 <strong>java.util.Date</strong> 映射成Javascript，并且命名为Blah，所以在Javascript中当你调用Blah.toString(reply) 那么一个新的 <strong>java.util.Date</strong> 就会通过默认的构造函数创造出来， 然后 <strong>toString()</strong> 方法被调用， 然后结果数据返回给reply方法(在这个例子中date是字符串格式)。</p>
            <p>&nbsp;</p>
            <hr />
            <p>&nbsp;</p>
            <p><font size="3"><strong><a name="none"></a>none</strong></font>'创造器不创建任何对象 - 它会假设你不需要创建对象。这有可能是对的，有两个原因。</p>
            <p>你可能在使用的scope不是"page"(看上面)，并在在前面已经把这个对象创建到这个scope中了，这时你就不需要再创建对象了。</p>
            <p>还有一种情况是要调用的方法是静态的，这时也不需要创建对象。DWR会在调用创建器之前先检查一下这个方法是不是静态的。</p>
            <p>对于上诉两种情况，你仍然需要class参数，用来告诉DWR它是在操作的对象类型是什么。</p>
            <p>&nbsp;</p>
            <hr />
            <p>&nbsp;</p>
            <p><font size="3"><strong><a name="scripted"></a>scripted</strong></font><font size="2">创造器在DWR中已经默认声明了：&lt;creator id="script" class="uk.ltd.getahead.dwr.create.ScriptedCreator"/&gt;</font></p>
            <p>这个创造器用BSF来执行脚本得到Bean，例如：</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-xml"><span class="code-tag">&lt;allow&gt;</span>&nbsp;&nbsp; ...&nbsp;&nbsp;<span class="code-tag">&lt;create creator=<span class="code-quote">"script"</span> javascript=<span class="code-quote">"EmailValidator"</span>&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;param name=<span class="code-quote">"language"</span> value=<span class="code-quote">"beanshell"</span>/&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;param name=<span class="code-quote">"script"</span>&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; import org.apache.commons.validator.EmailValidator;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return EmailValidator.getInstance();&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-tag">&lt;/param&gt;</span>&nbsp;&nbsp;<span class="code-tag">&lt;/create&gt;</span>&nbsp;&nbsp; ...<span class="code-tag">&lt;/allow&gt;</span></pre>
            </div>
            </div>
            <p>script创造器有如下参数：</p>
            <p>
            <table class="confluenceTable">
                <tbody>
                    <tr>
                        <th class="confluenceTh">参数</th>
                        <th class="confluenceTh">DWR版本</th>
                        <th class="confluenceTh">描述</th>
                    </tr>
                    <tr>
                        <td class="confluenceTd">language</td>
                        <td class="confluenceTd">1.0</td>
                        <td class="confluenceTd">脚本语言，字符串，例如'beanshell'. (必需)</td>
                    </tr>
                    <tr>
                        <td class="confluenceTd">script</td>
                        <td class="confluenceTd">1.0</td>
                        <td class="confluenceTd">要执行的脚本。 (必需，除非scriptPath参数存在)</td>
                    </tr>
                    <tr>
                        <td class="confluenceTd">scriptPath</td>
                        <td class="confluenceTd">1.1</td>
                        <td class="confluenceTd">脚本文件路径。 (必需，除非script参数存在)</td>
                    </tr>
                    <tr>
                        <td class="confluenceTd">reloadable</td>
                        <td class="confluenceTd">1.1</td>
                        <td class="confluenceTd">是否检测脚本文件的改动，以重新加载 (可选, 默认true)</td>
                    </tr>
                    <tr>
                        <td class="confluenceTd">class</td>
                        <td class="confluenceTd">1.0</td>
                        <td class="confluenceTd">创造出对象的类型(可选). 如果没有DWR通过创造器得到类型。</td>
                    </tr>
                </tbody>
            </table>
            </p>
            <h1><a name="ScriptedCreator-%E9%9C%80%E8%A6%81%E4%BA%86%E8%A7%A3%E7%9A%84%E4%B8%BB%E9%A2%98"></a><font size="2">需要了解的主题</font></h1>
            <p>要使用这个创造器，你需要把一些辅助库放到WEB-INF/lib文件夹下：<span class="nobr"><a title="Visit page outside Confluence" href="http://jakarta.apache.org/site/downloads/downloads_bsf.html" rel="nofollow">BSF的jar包<sup><img class="rendericon" height="7" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0"  alt="" /></sup></a></span>，你要用的<span class="nobr"><a title="Visit page outside Confluence" href="http://jakarta.apache.org/bsf/projects.html" rel="nofollow">脚本语言的jar包<sup><img class="rendericon" height="7" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0"  alt="" /></sup></a></span>。</p>
            <p>当一个类是用script创造出来的，并且scope是session或application，如果你的脚本改变，session中的类和script中的类就不一致了。这样会出现错误。虽然web容器不用重启，但是用户需要先登出(或以某种方式清空session)，然后再登录。</p>
            <p>当clazz参数不为空，并且用来创造新实例，DWR简单的调用 <em>class.newInstance()</em> 方法。这种方法是没问题的，除非脚本正在用某个参数创建一个类，或者调用某个函数来配置这个类。 不幸的是，每次请求都要重新运行script并造成上面的问题。</p>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/lishen226/aggbug/259927.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-03-16 09:13 <a href="http://www.blogjava.net/lishen226/archive/2009/03/16/259927.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>dwr.xml中的签名(Signatures) DWR中文文档</title><link>http://www.blogjava.net/lishen226/archive/2009/03/16/259920.html</link><dc:creator>锋行</dc:creator><author>锋行</author><pubDate>Mon, 16 Mar 2009 00:52:00 GMT</pubDate><guid>http://www.blogjava.net/lishen226/archive/2009/03/16/259920.html</guid><wfw:comment>http://www.blogjava.net/lishen226/comments/259920.html</wfw:comment><comments>http://www.blogjava.net/lishen226/archive/2009/03/16/259920.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lishen226/comments/commentRss/259920.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lishen226/services/trackbacks/259920.html</trackback:ping><description><![CDATA[<div class="tit">【转】dwr.xml中的签名(Signatures) DWR中文文档 from http://wiki.javascud.org</div>
<div class="date">2007-12-28 14:10</div>
<table style="table-layout: fixed">
    <tbody>
        <tr>
            <td>
            <div class="cnt" id="blog_text">
            <h1><a name="Signatures-dwr.xml%E4%B8%AD%E7%9A%84%E7%AD%BE%E5%90%8D%28Signatures%29"></a>dwr.xml中的签名(Signatures)</h1>
            <p>signatures段使DWR能确定集合中存放的数据类型。例如下面的定义中我们无法知道list中存放的是什么类型。</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-java"><span class="code-keyword">public</span> class Check
            {
            <span class="code-keyword">public</span> void setLotteryResults(List nos)
            {
            ...
            }
            }</pre>
            </div>
            </div>
            <p>signatures段允许我们暗示DWR应该用什么类型去处理。格式对以了解JDK5的泛型的人来说很容易理解。</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-xml"><span class="code-tag">&lt;signatures&gt;</span>
            &lt;![CDATA[
            import java.util.List;
            import com.example.Check;
            Check.setLotteryResults(List<span class="code-tag">&lt;Integer&gt;</span> nos);
            ]]&gt;
            <span class="code-tag">&lt;/signatures&gt;</span></pre>
            </div>
            </div>
            <p>DWR中又一个解析器专门来做这件事，所以即便你的环境时JDK1.3 DWR也能正常工作。</p>
            <p>解析规则基本上会和你预想规则的一样(有两个例外)，所以java.lang下面的类型会被默认import。</p>
            <p>第一个是DWR1.0中解析器的bug，某些环境下不能返回正确类型。所以你也不用管它了。</p>
            <p>第二个是这个解析器时"阳光(sunny day)"解析器。就是说它非常宽松，不想编译器那样严格的保证你一定正确。所以有时它也会允许你丢失import：</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-xml"><span class="code-tag">&lt;signatures&gt;</span>
            &lt;![CDATA[
            import java.util.List;
            Check.setLotteryResults(List<span class="code-tag">&lt;Integer&gt;</span>);
            ]]&gt;
            <span class="code-tag">&lt;/signatures&gt;</span></pre>
            </div>
            </div>
            <p>将来的DWR版本会使用一个更正式的解析器，这个编译器会基于官方Java定义，所以你最好不要使用太多这个不严格的东西。</p>
            <p>signatures段只是用来确定泛型参数中的类型参数。DWR会自己使用反射机制或者运行时类型确定类型，或者假设它是一个String类型。所以：</p>
            <p>不需要signatures - 没有泛型参数：</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-java"><span class="code-keyword">public</span> void method(<span class="code-object">String</span> p);
            <span class="code-keyword">public</span> void method(<span class="code-object">String</span>[] p);</pre>
            </div>
            </div>
            <p>需要signatures - DWR不能通过反射确定：</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-java"><span class="code-keyword">public</span> void method(List&lt;Date&gt; p);
            <span class="code-keyword">public</span> void method(Map&lt;<span class="code-object">String</span>, WibbleBean&gt; p);</pre>
            </div>
            </div>
            <p>不需要signatures - DWR能正确的猜出:</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-java"><span class="code-keyword">public</span> void method(List&lt;<span class="code-object">String</span>&gt; p);
            <span class="code-keyword">public</span> void method(Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; p);</pre>
            </div>
            </div>
            <p>不需要signatures - DWR可以通过运行时类型确定：</p>
            <div class="code">
            <div class="codeContent">
            <pre class="code-java"><span class="code-keyword">public</span> List&lt;Date&gt; method(<span class="code-object">String</span> p);</pre>
            </div>
            </div>
            <p>没有必要让Javascript中的所有对象的key都是String类型 - 你可以使用其他类型作为key。但是他们在使用之前会被转换成String类型。DWR1.x用Javascript的特性把key转换成String。DWR2.0可能会用toString()方法，在服务段进行这一转换。</p>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/lishen226/aggbug/259920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lishen226/" target="_blank">锋行</a> 2009-03-16 08:52 <a href="http://www.blogjava.net/lishen226/archive/2009/03/16/259920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>