why is paintComponent() never called by repaint()?

北战南征 提交于 2020-01-25 05:57:44

问题


I've been working on an program that draws custom JComponents onto a JLayeredPane however all calls to repaint() on the components seem to do nothing yet the paintComponent method is invoked automatically when the window is re-sized.

I have been following some of the advice given here: Why is paint()/paintComponent() never called?

But none of the solutions seem to fix my problem, update swing components on the EDT, setting component size manually before calling repaint(), calling super.paintComponent(g) in the overridden paintComponent() and calling revalidate() on the frame after adding new components (although this is clearly no the issue in this case)

Any ideas what could be stopping the call? Thanks in advance :)

Here is the code for the View and the SVGElementContainer, view.setFile() is the entry-point as it is invoked when a new document needs to be displayed.

public class View extends JLayeredPane implements SVGViewport {

    private SVGDocument document;
    //Array list of the SVGElementContainer components
    private ArrayList<SVGElementContainer> elemContainers;
    private SVGFrame frame;
    private int elemCount;
    private Border viewBorder;
    private int borderWidth = 1;

    //panels displayed on the JLayeredPane
    private JPanel backgroundPanel;

    /** Creates a new view */
    public View(SVGFrame frame) {
        super();
        this.frame = frame;
        elemCount = 0;

        elemContainers = new ArrayList<SVGElementContainer>();
        viewBorder = BorderFactory.createLineBorder(Color.BLACK, borderWidth);
    }

    public float getViewportWidth() {
        return getWidth();
    }

    public float getViewportHeight() {
        return getHeight();
    }

    // paints all elements and adds them to the JLayeredPane
    public void paintAllElements(){

        System.out.println("Painting all elements");

        // Paint document
        for (SVGElement elem : document) {
            //only paint stylable (rect, line, circle) elements
            if (elem instanceof SVGStylable){
                //create a new SVGElementContainer
                SVGElementContainer newElemCont = new SVGElementContainer();

                //add component to JLayeredPane
                elemCount++;
                this.add(newElemCont, new Integer(elemCount + 1));

                //set the current element within its container and calls repaint() on the component
                System.out.println("Painting element #" + elemCount);
                newElemCont.setElement(elem);
                newElemCont.repaint();
            }
            else {
                System.out.println("Skip painting group element!");
            }
        }
    }

    /** Gets the document currently being displayed by the view. */
    public SVGDocument getDocument() {
        return document;
    }

    /** Sets the document that the view should display.
     *
     * @param document the document to set
     */
    public void setDocument(SVGDocument document) {
        this.document = document;
        //paintBackground();
        paintAllElements();
        revalidate();
    }

    public void revalidate(){
        //calls validate() on the frame in order to display newly added components
        frame.getContentPane().validate();
    }
}

public class SVGElementContainer extends JPanel{

    private SVGElement elem;

    public SVGElementContainer(){
        super();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        System.out.println("PAINT METHOD CALLED!");
        paint2D((Graphics2D) g);
    }

    //paint the element onto this JComponent
    public void paint2D(Graphics2D g){
        if (!(elem instanceof SVGStylable)){
            System.out.println("Skipping non-stylable element!");
            return;
        }

        setOpaque(false);

        Shape shape = elem.createShape();

        // get fill stroke and width properties
        SVGStylable style = (SVGStylable) elem;
        SVGPaint fillPaint = style.getFill();
        SVGPaint strokePaint = style.getStroke();
        SVGLength strokeWidth = style.getStrokeWidth();

        // Fill the interior of the shape
        if (fillPaint.getPaintType() == SVGPaint.SVG_PAINTTYPE_RGBCOLOR) {
            g.setPaint(fillPaint.getRGBColor());
            g.fill(shape);
        }

        // Stroke the outline of the shape
        if (strokePaint.getPaintType() == SVGPaint.SVG_PAINTTYPE_RGBCOLOR) {
            Stroke stroke = new BasicStroke(strokeWidth.getValue());
            g.setStroke(stroke);
            g.setColor(strokePaint.getRGBColor());
            g.draw(shape);
        }
    }

    public void setElement(SVGElement elem){
        this.elem = elem;
        setComponentSize();
    }

    private void setComponentSize(){

        //this.setPreferredSize(new Dimension(
        //  (int)elem.getDocument().getWidth().getValue(),
        //  (int)elem.getDocument().getHeight().getValue()));

        this.setSize(new Dimension(
                (int)elem.getDocument().getWidth().getValue(),
                (int)elem.getDocument().getHeight().getValue()));
    }

}

回答1:


I see that you're calling setOpaque(false). From the setOpaque javadoc, emphasis mine:

If true the component paints every pixel within its bounds. Otherwise, the component may not paint some or all of its pixels, allowing the underlying pixels to show through.

That "may" be the cause of paintComponent() not being called after the first time during a repaint() call. Swing can decide that the component has not "changed", and thus does not need repainting.




回答2:


setting component size manually before calling repaint(), calling super.paintComponent(g) in the overridden paintComponent() and calling revalidate() on the frame after adding new components

Your code is wrong on these concepts.

a) never invoke the setSize() method. That is the job of the layout manager. You should be providing hints to the layout manager by overriding methods like getPreferredSize() to return the preferred size of your component

b) don't override the revalidate() method. The point of that tip is to use code like:

panel.add( .... );
panel.revalidate();
panel.repaint();

But I don't really know what all your code is supposed to do so I can't tell for sure if your code makes sense. I also find it strange that you are extending a JLayeredPane.




回答3:


I can see extending JPanel to get the buffering and UI delegate, but the opacity is L&F dependent. Instead, you should probably start with JComponent and implement the EventListenerList plumbing for your (hypothetical) SVGEvent.



来源:https://stackoverflow.com/questions/5902974/why-is-paintcomponent-never-called-by-repaint

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!