JXMultiSplitPane causes repaint during slider adju

2019-07-16 19:21发布

问题:

I seem to be getting frequent repaint requests during adjustment of the splitter in JXMultiSplitPane. (see program below)

Why?

I have setContinuousLayout(false).


Just to clarify: I understand the repaint should occur after the split-panes are resized. But during splitter adjustment, nothing is being resized; the splitter is moving around on the screen.


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jdesktop.swingx.JXMultiSplitPane;
import org.jdesktop.swingx.MultiSplitLayout;

public class MultiVerticalPane<T extends Component> extends JPanel
{
    final private List<T> components;
    public MultiVerticalPane(List<? extends T> components,
            List<Double> weights)
    {
        this.components = new ArrayList<T>(components);
        final int n = this.components.size();
        if (weights != null && weights.size() != n)
            throw new IllegalArgumentException(
                    "weights and components should have same length");

        JXMultiSplitPane msp = new JXMultiSplitPane();
        msp.setContinuousLayout(false);
        msp.getMultiSplitLayout().setModel(createSplitModel(weights));
        int i = 0;
        for (T component : components)
        {
            msp.add(component, nodeTitle(i++));
        }

        setLayout(new BorderLayout());
        add(msp, BorderLayout.CENTER);
    }
    private MultiSplitLayout.Split createSplitModel(
            List<Double> weights) 
    {
        LinkedList<MultiSplitLayout.Node> nodes = 
            new LinkedList<MultiSplitLayout.Node>();
        int i = 0;
        double wtot = 0;
        for (double w : weights)
        {
            wtot += w;
        }
        for (double w : weights)
        {           
            if (i > 0)
                nodes.addFirst(new MultiSplitLayout.Divider());
            MultiSplitLayout.Leaf leaf = 
                new MultiSplitLayout.Leaf(nodeTitle(i++));
            leaf.setWeight(w/wtot);
            nodes.addFirst(leaf);
        }
        MultiSplitLayout.Split split = 
            new MultiSplitLayout.Split();
        split.setRowLayout(false);
        split.setChildren(nodes);
        return split;
    }
    private String nodeTitle(int i) {
        return String.format("%02d", i);
    }

    /************ test methods *************/

    private interface Painter
    {
        public void paint(Graphics g, Rectangle bounds);
    }

    static private class RelativeGraphics
    {
        final private Graphics g;
        final private double xofs;
        final private double yofs;
        final private double xscale;
        final private double yscale;
        private double cx;
        private double cy;

        public RelativeGraphics(Graphics g, Rectangle bounds)
        {
            this.g = g;
            this.cx = 0;
            this.cy = 0;
            this.xofs = bounds.getMinX();
            this.yofs = bounds.getMaxY();
            this.xscale = bounds.getWidth();
            this.yscale = -bounds.getHeight();
        }
        public void moveTo(double x, double y)
        {
            this.cx = x;
            this.cy = y;
        }
        public void lineTo(double x, double y)
        {
            this.g.drawLine(
                (int)(this.cx*this.xscale+this.xofs),
                (int)(this.cy*this.yscale+this.yofs),
                (int)(x*this.xscale+this.xofs),
                (int)(y*this.yscale+this.yofs)
            );
            moveTo(x,y);
        }           
        public void rmoveTo(double dx, double dy)
        {
            moveTo(this.cx+dx, this.cy+dy);
        }           
        public void rlineTo(double dx, double dy)
        {
            lineTo(this.cx+dx, this.cy+dy);
        }           
    }

    // adapted from http://en.wikipedia.org/wiki/Hilbert_curve#Java
    static private class HilbertCurve
    {
        final private RelativeGraphics rg;
        final private double d;
        public HilbertCurve(RelativeGraphics rg, int level)
        {
            this.rg = rg;
            double d0 = 1.0;
            for (int i = level; i > 0; i--)
                d0 /= 2;
            this.d = d0;
            rg.rmoveTo(d0/2, d0/2);
            drawCurveUp(level);
        }
        private void drawCurveUp(int n) 
        {           
            if (n > 0) {
                drawCurveLeft(n-1);    this.rg.rlineTo(0, this.d);
                drawCurveUp(n-1);      this.rg.rlineTo(this.d, 0);
                drawCurveUp(n-1);      this.rg.rlineTo(0, -this.d);
                drawCurveRight(n-1);
            }
        }

        private void drawCurveLeft(int n)
        {
            if (n > 0) {
                drawCurveUp(n-1);      this.rg.rlineTo(this.d, 0);
                drawCurveLeft(n-1);    this.rg.rlineTo(0, this.d);
                drawCurveLeft(n-1);    this.rg.rlineTo(-this.d, 0);
                drawCurveDown(n-1);
            }
        }

        private void drawCurveRight(int n)
        {
            if (n > 0) {
                drawCurveDown(n-1);     this.rg.rlineTo(-this.d, 0);
                drawCurveRight(n-1);    this.rg.rlineTo(0, -this.d);
                drawCurveRight(n-1);    this.rg.rlineTo(this.d, 0);
                drawCurveUp(n-1);
            }
        }

        private void drawCurveDown(int n)
        {
            if (n > 0) {
                drawCurveRight(n-1);    this.rg.rlineTo(0, -this.d);
                drawCurveDown(n-1);     this.rg.rlineTo(-this.d, 0);
                drawCurveDown(n-1);     this.rg.rlineTo(0, this.d);
                drawCurveLeft(n-1);
            }
        }
    }

    static private class HilbertPainter implements Painter
    {
        final private int level;
        public HilbertPainter(int level) { this.level = level; }
        @Override public void paint(Graphics g, Rectangle bounds) {
            new HilbertCurve(
                new RelativeGraphics(g,
                    new Rectangle(new Point(0,0),bounds.getSize())),
                this.level);
        }
    }

    static private class PainterPanel extends JPanel
    {
        final private Painter painter;

        public PainterPanel(Painter painter)
        {
            this.painter = painter;
            setBackground(Color.WHITE);
            setForeground(Color.RED);
        }
        @Override public void paintComponent(Graphics g) 
        {
            super.paintComponent(g);
            this.painter.paint(g, getBounds());
        }
    }

    public static void main(String[] args) { test(); }
    private static void test() 
    {
        JFrame frame = new JFrame("MultiVerticalPane test");
        List<JPanel> panels = new ArrayList<JPanel>();
        List<Double> weights = Arrays.asList(1.0,1.0,2.0,4.0,8.0);

        for (int i = 0; i < 5; ++i)
        {
            panels.add(new PainterPanel(new HilbertPainter(i+4)
                {
                    int count = 0;
                    @Override public void paint(Graphics g, 
                            Rectangle bounds)
                    {
                        super.paint(g, 
                            new Rectangle(bounds.getLocation(),
                                new Dimension(bounds.width, 
                                    bounds.height-10)));
                        g.drawString(String.format("%d", this.count++),
                                0, bounds.height);
                    }
                }
            ));
        }       
        MultiVerticalPane<Component> mvp = 
            new MultiVerticalPane<Component>(panels, weights);
        mvp.setPreferredSize(new Dimension(360,720));
        frame.setContentPane(mvp);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

回答1:

It looks like setContinuousLayout() affects revalidate(), not repaint().



回答2:

Its not a 'direct' answer. I just put it here since I run out of space in a comment.

I do not think it is too frequent? Why would you think that did you compare it with any other component?

What I think is that every resize a component detects it calls repaint. On top of it goes how a layout manager handles resizing. Please observe that when, for example, you resize the top most panel and are dragging it down it is very rarely repainted, which you cannot say about his neighbour. The situation is reversed when you drag the slider up.

BTW: Might I ask why would you worry about how often and which part of the split pane is repainted?

Please bear in mind that I am not an expert on the internals of the repaint mechanism of this component but I would doubt that SwingX guys would step away from the defaults in this regards.