Swing实现的目标
按Swing实现的目标,将开发java界面的开发人员分为两类:首先是开发独立的组件,这些组件与具体应用无关,Swing自身也提供了一套,开发者也可以开发自己的组件,这些人是组件开发者角色;然后是为某应用程序构建GUI,则是使用那些组件类建立组件实例,并且通过建立容器关系来实现界面需求,这些是GUI开发者角色。从这个清晰的划分出发可以体会Swing面向OO开发的精神。组件开发者开发的每一个组件面向所有应用,是一个高度抽象,打包封装好的类,因此高度复用;而GUI开发者的开发过程则是根据需要继续 OO---,首先整个应用界面职责被封装成一个类,该类的实例的生命周期就代表了整个应用界面的生命周期,再从应用领域角度进行界面职责划分,利用容器概念,快速通过聚合,定制组件实例打造出承担各个细分应用领域界面交互职责的“面板类/页面类”,***应用界面类实例将在整个生命周期内不断耦合托付各类“ 面板类/页面类”实例(一般通过“页面接口”实现动态性)来完成全部界面交互职责。
反过来说,Swing也正是为了这样的oo实践需要而诞生的。在以上描述的gui构建中,最频繁的就是通过容器组装出特定面板组件来。那么如何定制子组件在容器面板上的分布呢?
Swing实现的目标是Container中可以setLayout(LayoutManager mgr),该mgr给出了一种布局方式,比如按五位图布局还是表格布局;而子组件加入容器时可以给出针对此容器布局方式的各自的布局信息, Container.add(Component comp, Object constraints);***当绘制该容器的子组件时根据这些布局信息计算出各组件合适的大小位置等信息进行绘制即可。不过在Swing中,为了提高性能,不是每次绘制时都重新根据布局信息计算该如何绘制子组件,而是将在一次处理过程中把根据布局信息计算的绘制要求存储在子组件和容器中,比如调整后的子组件的位置,容器的合适大小等,以后绘制时直接绘制;除非此后发生布局变化,比如容器remove掉一个子组件,将要导致一次重新计算布局信息的处理过程;由于Swing中的组件关系是一层包一层,某一层的变化可能导致整个树都需要重新计算,这就和repaint的场景类似了,也因此,Swing将采取类似repaint的提交请求等待处理的模式,就是传说中的revalidate。下面看jre1.7中具体的实现:
- PublicclassJComponent{
- publicvoidrevalidate(){
- if(getParent()==null){
- return;
- }
- if(SwingUtilities.isEventDispatchThread()){
- invalidate();//使该组件布局失效
- RepaintManager.currentManager(this).addInvalidComponent(this);//向RM请求一次重布局
- }
- else{//如果不是在EDT中调用需要调整到EDT中。
- //ToavoidafloodofRunnableswhenconstructingGUIsoff
- //theEDT,aflagismaintainedastowhetherornot
- //aRunnablehasbeenscheduled.
- synchronized(this){
- if(getFlag(REVALIDATE_RUNNABLE_SCHEDULED)){
- return;
- }
- setFlag(REVALIDATE_RUNNABLE_SCHEDULED,true);
- }
- RunnablecallRevalidate=newRunnable(){
- publicvoidrun(){
- synchronized(JComponent.this){
- setFlag(REVALIDATE_RUNNABLE_SCHEDULED,false);
- }
- revalidate();
- }
- };
- SwingUtilities.invokeLater(callRevalidate);
- }
- }
【编辑推荐】