`
netbaixc_gmail_com
  • 浏览: 55536 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JAVA Painting-Swing实现纪要四

阅读更多
JAVA Painting-Swing实现纪要四
前三节大概描述了swing的绘制实现,现在补充一下Swing里十分重要的一个绘制概念:revalidate。
按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中具体的实现:
Public class JComponent{
public void revalidate() {
        if (getParent() == null) {
            return;
        }
        if (SwingUtilities.isEventDispatchThread()) {
            invalidate();//使该组件布局失效
            RepaintManager.currentManager(this).addInvalidComponent(this);//向RM请求一次重布局
        }
        else {//如果不是在EDT中调用需要调整到EDT中。
            // To avoid a flood of Runnables when constructing GUIs off
            // the EDT, a flag is maintained as to whether or not
            // a Runnable has been scheduled.
            synchronized(this) {
                if (getFlag(REVALIDATE_RUNNABLE_SCHEDULED)) {
                    return;
                }
                setFlag(REVALIDATE_RUNNABLE_SCHEDULED, true);
            }
            Runnable callRevalidate = new Runnable() {
                public void run() {
                    synchronized(JComponent.this) {
                        setFlag(REVALIDATE_RUNNABLE_SCHEDULED, false);
                    }
                    revalidate();
                }
            };
            SwingUtilities.invokeLater(callRevalidate);
        }
}


Public Class Container{
public void invalidate() {
        LayoutManager layoutMgr = this.layoutMgr;
        if (layoutMgr instanceof LayoutManager2) {
            LayoutManager2 lm = (LayoutManager2) layoutMgr;
            lm.invalidateLayout(this);//通知LayoutManager应该丢弃可能缓存的当前布局计算结果信息
        }
        super.invalidate();
    }
}
Public Class Component{
public void invalidate() {
        synchronized (getTreeLock()) {
            valid = false;//每个组件都有这么一个域,记录着当前布局信息是否有效
            if (!isPreferredSizeSet()) {//直接清空prefSize
                prefSize = null;
            }
            if (!isMinimumSizeSet()) {//直接清空minSize
                minSize = null;
            }
            if (!isMaximumSizeSet()) {//直接清空maxSize
                maxSize = null;
            }
            if (parent != null && parent.valid) {//递归向上
                parent.invalidate();
            }
        }
    }

}

Public Class RepaintManager{
public synchronized void addInvalidComponent(JComponent invalidComponent)
    {
        Component validateRoot = null;

        /* Find the first JComponent ancestor of this component whose
         * isValidateRoot() method returns true.
         */
// isValidateRoot标志着该组件可以作为展开布局计算的根组件。
        for(Component c = invalidComponent; c != null; c = c.getParent()) {
            if ((c instanceof CellRendererPane) || (c.getPeer() == null)) {
                return;//对于这两种特殊情况将撤销本次重新计算布局的请求
            }
            if ((c instanceof JComponent) && (((JComponent)c).isValidateRoot())) {//JRootPane isValidateRoot
                validateRoot = c;
                break;
            }
        }

        /* There's no validateRoot to apply validate to, so we're done.
         */
        if (validateRoot == null) {//一直没有找到ValidateRoot则撤销请求
            return;
        }

        /* If the validateRoot and all of its ancestors aren't visible
         * then we don't do anything.  While we're walking up the tree
         * we find the root Window or Applet.
         */
//如果validateRoot及之上的祖宗无peer或不可见则撤销请求
        Component root = null;

        for(Component c = validateRoot; c != null; c = c.getParent()) {
            if (!c.isVisible() || (c.getPeer() == null)) {
                return;
            }
            if ((c instanceof Window) || (c instanceof Applet)) {//找到对应的顶层窗口
                root = c;
                break;
            }
        }

        if (root == null) {//一直没有找到顶层窗口则请求无效
            return;
        }

        /* Lazily create the invalidateComponents vector and add the
         * validateRoot if it's not there already.  If this validateRoot
         * is already in the vector, we're done.
         */
        if (invalidComponents == null) {//延迟创建该单例
            invalidComponents = new ArrayList<Component>();
        }
        else {
            int n = invalidComponents.size();
            for(int i = 0; i < n; i++) {
                if(validateRoot == invalidComponents.get(i)) {//如果当前要开展布局计算的validateRoot已经注册在记录列表中则忽略本次请求---请求合并。
                    return;
                }
            }
        }
        invalidComponents.add(validateRoot);//加入该请求

        // Queue a Runnable to invoke paintDirtyRegions and
        // validateInvalidComponents.
        scheduleProcessingRunnable();//将导致进行布局计算的调度,该方法在前面的分节已分析过。
    }
//前面纪要分析中未分析的ProcessingRunnable.run中将执行的方法,这次revalidate可能加入的//invalidComponents将被validate
public void validateInvalidComponents() {
        java.util.List<Component> ic;
        synchronized(this) {//并发的合理交换
            if(invalidComponents == null) {
                return;
            }
            ic = invalidComponents;
            invalidComponents = null;
        }
        int n = ic.size();
        for(int i = 0; i < n; i++) {//对每一个validateRoot进行validate
            ic.get(i).validate();
        }
}
}

Public Class Container{
public void validate() {
        /* Avoid grabbing lock unless really necessary. */
        if (!valid) {//如果本组件valid==false
            boolean updateCur = false;
            synchronized (getTreeLock()) {
                if (!valid && peer != null) {
                    ContainerPeer p = null;
                    if (peer instanceof ContainerPeer) {
                        p = (ContainerPeer) peer;
                    }
                    if (p != null) {
                    System.out.println("Window show>>p.beginValidate");
                        p.beginValidate();//通知开始validate—轻量级peer不做任何操作
                    }
                    validateTree();//实际布局计算处理过程入口
                    valid = true;//置为有效
                    if (p != null) {
                        p.endValidate();//通知结束validate—轻量级peer不做任何操作
                        System.out.println("Window show>>p.endValidate");
                        updateCur = isVisible();//如果是可视状态,更新Cursor
                    }
                }
            }
            if (updateCur) {
            System.out.println("Window show>>updateCur");
                updateCursorImmediately();//更新Cursor
            }
        }
    }
protected void validateTree() {
        if (!valid) {//如果本组件valid==false
            if (peer instanceof ContainerPeer) {
                ((ContainerPeer)peer).beginLayout();
            }
            doLayout();//实际布局计算处理过程入口
            Component component[] = this.component;
            for (int i = 0 ; i < ncomponents ; ++i) {//往下对valid==false的子组件遍历validate
                Component comp = component[i];
                if (   (comp instanceof Container)//如果是非窗口的容器,且valid==false,直接进行validateTree处理
                    && !(comp instanceof Window)
                    && !comp.valid) {
                    ((Container)comp).validateTree();
                } else {//否则需要进入validate递归处理
                    comp.validate();
                }
            }
            if (peer instanceof ContainerPeer) {
                ((ContainerPeer)peer).endLayout();
            }
        }
        valid = true;
    }
public void doLayout() {
        layout();//实际布局计算处理过程入口
    }

    /**
     * @deprecated As of JDK version 1.1,
     * replaced by <code>doLayout()</code>.
     */
    @Deprecated
    public void layout() {
        LayoutManager layoutMgr = this.layoutMgr;
        if (layoutMgr != null) {
            layoutMgr.layoutContainer(this); // LayoutManager负责进行布局计算
        }
    }
//现在以BorderLayoutManager(五位图布局)为例
public class BorderLayout
public void layoutContainer(Container target) {
      synchronized (target.getTreeLock()) {
        Insets insets = target.getInsets();
        int top = insets.top;
        int bottom = target.height - insets.bottom;
        int left = insets.left;
        int right = target.width - insets.right;

        boolean ltr = target.getComponentOrientation().isLeftToRight();
        Component c = null;

        if ((c=getChild(NORTH,ltr)) != null) {
            c.setSize(right - left, c.height);//对子组件重新设置大小
            Dimension d = c.getPreferredSize();
            c.setBounds(left, top, right - left, d.height); //对子组件重新设置边界
            top += d.height + vgap;
        }//调整大小和边界将引起repaint
        if ((c=getChild(SOUTH,ltr)) != null) {
            c.setSize(right - left, c.height);
            Dimension d = c.getPreferredSize();
            c.setBounds(left, bottom - d.height, right - left, d.height);
            bottom -= d.height + vgap;
        }
        if ((c=getChild(EAST,ltr)) != null) {
            c.setSize(c.width, bottom - top);
            Dimension d = c.getPreferredSize();
            c.setBounds(right - d.width, top, d.width, bottom - top);
            right -= d.width + hgap;
        }
        if ((c=getChild(WEST,ltr)) != null) {
            c.setSize(c.width, bottom - top);
            Dimension d = c.getPreferredSize();
            c.setBounds(left, top, d.width, bottom - top);
            left += d.width + hgap;
        }
        if ((c=getChild(CENTER,ltr)) != null) {
            c.setBounds(left, top, right - left, bottom - top);
        }
      }
}
//子组件信息是在加入容器是被加入到BorderLayoutManager中去的



Public Class Container{

protected void addImpl(Component comp, Object constraints, int index) {//追加子组件
~~~
if (layoutMgr != null) {//如果容器具有LayoutManager
                if (layoutMgr instanceof LayoutManager2) {//BorderLayoutManager是
                    ((LayoutManager2)layoutMgr).addLayoutComponent(comp, constraints);// BorderLayoutManager会在此通知中加入子组件
                } else if (constraints instanceof String) {
                    layoutMgr.addLayoutComponent((String)constraints, comp);
                }
            }
}
Swing的revalidate简单说就是首先置为自身及所有祖宗无效,然后登记计算布局请求,该请求可能因上一次提交的同样的validateRoot相同而被合并;处理请求将从validateRoot开始用布局管理器计算布局,计算结果体现在对子组件的大小范围等信息的调整,这些调整将引起repaint提交绘制请求,然后再次递归往下对所有标记无效的子组件处理。
2
0
分享到:
评论

相关推荐

    Painting-With-Music-源码.rar

    从给出的文件名 "Painting-With-Music-源码.rar" 和 "Painting-With-Music-源码.zip" 来看,这很可能是该项目的源代码文件,包含了实现这一功能的所有编程代码。 在这个项目中,我们可以深入探讨以下几个关键知识点...

    微信小程序:涂鸦wx-app-painting-master.zip

    在这个名为“涂鸦wx-app-painting-master.zip”的压缩包中,我们可能找到了一个专门用于在微信小程序上实现涂鸦功能的项目。下面将详细探讨微信小程序的基础知识、涂鸦功能的实现以及可能包含的文件结构。 首先,...

    This is a painting-tool. You can choose several drawing opti

    This is a painting-tool. You can choose several drawing options from a toolbar and you can apply much filters and effects to the pic. Pls. give feedback!

    ai-painting-interface绘画API接口

    绘画是一种创造性和想象力的艺术形式,许多人通过绘画表达自己的情感和思想。但传统绘画需要大量时间和精力,对许多人来说是困难的。...用户可以轻松进行各种绘画操作,实现自己的创意和想象,帮助广大绘画爱好者。

    Painting-Pro-Estimator:轻松创建详细的估算和发票-开源

    4. **自定义发票模板**:除了基本的发票格式,Painting-Pro-Estimator还允许用户自定义设计,添加公司标志,调整字体和颜色,使您的发票更具专业感,提升品牌形象。 5. **数据同步与备份**:软件可能支持云同步,使...

    Painting-With-Music

    通过监听音乐的音频数据,项目将音乐的节奏、频率等元素转化为视觉效果,实现了音乐与绘画的实时互动。 在"Painting-With-Music-master"这个压缩包中,包含了项目的所有源代码和资源文件。开发者可能通过分析这些...

    Chinese-Landscape-Painting-Dataset:WACV 2021论文使用的数据集

    中国传统山水画数据集 文章标题:“利用生成的对抗网络进行端到端的中国山水画创作” ArXiv: : 抽象的:当前基于GAN的艺术生成方法由于依赖条件输入而产生非原创的艺术作品。在这里,我们提出GAN(SAPGAN),这是...

    wash-painting-ui:一种粗暴的水墨风UI

    总的来说,"wash-painting-ui"项目是将传统艺术与现代技术完美融合的典范,通过Vue3和Vite的技术支持,实现了富有创意的水墨风格UI设计。每个组件都精心设计,力求在用户体验与艺术美感之间找到最佳平衡。这种大胆的...

    painting-project

    在这个"painting-project"中,`&lt;canvas&gt;`元素是关键,它提供了一个画布,JavaScript通常会与之配合,通过Canvas API来实现动态绘图。Canvas API允许开发者在网页上进行像素级别的操作,绘制线条、形状、图像,甚至...

    light-painting-wand:轻涂棒硬件软件

    "light-painting-wand"项目是一个创新的科技艺术工具,专为光绘摄影爱好者和艺术家设计。光绘,又称光涂鸦,是一种摄影技术,通过在黑暗中移动光源来创造艺术图像。这个项目旨在提供一个名为“轻涂棒”的硬件设备,...

    painting-algorithms

    这个"painting-algorithms"项目显然集中于使用编程语言,特别是Python,来实现各种绘画算法。让我们深入探讨一下这个主题。 首先,绘画算法的核心是将几何数据转化为屏幕上的像素颜色。这些算法可以分为基本和复杂...

    java 画图软件_java_

    总之,"java 画图软件_java_" 提供了一个用Java实现的简单图形绘制工具的例子,展示了如何利用Java的GUI库来创建具有图形绘制能力的桌面应用程序。通过深入学习和理解这个项目,开发者可以进一步提升他们的Java GUI...

    dot-painting-challenge:这是一个使用彩色圆点创建图像的程序。 它使用乌龟和颜色图库来做到这一点

    "dot-painting-challenge"项目就是一个很好的例子,它利用编程语言的力量,借助乌龟图形库和颜色图库,以彩色圆点的形式创作出各种图像。本文将深入探讨这一挑战背后的技术细节。 首先,乌龟图形库(Turtle ...

    Painting-Cube

    从标题来看,它很可能涉及到计算机图形学中的3D建模和绘制技术,特别是在C#环境中实现的。下面我们将深入探讨与这个项目相关的C#编程和3D图形处理的知识点。 首先,C#是一种多范式编程语言,由微软开发,广泛用于...

    java-界面组件案例大全(内含139个完整Demo)

    5. **绘图(painting)**:在"painting"目录中,你将看到如何利用Java的Graphics2D API进行图形绘制。这包括在组件上绘制线条、形状、图像甚至动画,提供了自定义组件外观的强大能力。 通过深入学习这些示例,你...

    pooled-cell-painting-profiling-recipe:配方存储库,用于基于图像的池化细胞绘画实验分析

    合并单元格绘画-基于图像的分析管道配方 :...目前,这两种数据成分的测量都是由CellProfiler软件进行的(使用定制的Pooled Cell Painting插件)。 配方步骤 所有食谱还包括针对每个食谱的特定说明或步骤。 我们的食谱

    creative-painting-application:一个有趣且有创意的绘画应用

    4. **事件监听器**:JavaScript会监听用户的鼠标或触屏动作,将这些输入转化为绘画指令,比如改变颜色、选择画笔粗细、擦除等。 5. **颜色和工具选择**:应用可能提供了丰富的颜色选择器和不同类型的绘画工具,比如...

    njb-painting-website:NJB绘画网站建设

    在这个项目中,开发者运用了JavaScript作为主要的编程语言,这表明网站的交互性和动态功能主要通过JavaScript实现。 React是一个由Facebook维护的开源JavaScript库,专门用于构建用户界面,特别是单页应用程序(SPA...

    Light-Painting-with-a-Robot-

    用机器人进行轻涂 宜居人士: 进位代码=&gt;进位代码(保存功能)=&gt;进销存基本代码=&gt;进阶照片和视频 模拟=&gt;辅助Excel图:评估价格的相关系数对应的比例系数和偏差系数(校正器不能有效地使用puisqu'il n'y a a pas d'...

    MFC-painting-(Kaleidoscope).rar_界面编程_Visual_C++_

    在本项目中,"MFC-painting-(Kaleidoscope).rar"是一个使用Microsoft Foundation Class (MFC)库开发的Visual C++应用,主要目的是实现一个动态的万花筒效果。MFC是微软提供的一套面向对象的C++类库,它封装了Windows...

Global site tag (gtag.js) - Google Analytics