JPane "paintComponent" can't be called without JLabel

151 views Asked by At

My problem that I am having is that in this code, the line will not draw at all if I get rid of the JLabel from it. I tested it out and without the JLabel stuff with in it, the paintComponent(Graphics g) won't run at all. I want to know why this is and why JLabel effects the JPanel like this.

I have read online that sometime the paintComponent(Graphics g) might not run if it is in a infinite loop but i still don't understand how the JLabel would effect this trait.

I would guess that it might have to do something with the layout but i don't really understand how layout effects things like this

MouseAction Class

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;



public class MouseAction extends JFrame{
    private JPanel mousePanel;
    private JLabel statusBar;
    private GraphicsPanel g;
    private int xS;
    private int yS;

    public MouseAction (){
        super("Mouse example");
        mousePanel = new JPanel();
        statusBar = new JLabel("Deafault");

        g = new GraphicsPanel(0,0,0,0);


        add(mousePanel, BorderLayout.CENTER);

        add(statusBar, BorderLayout.SOUTH);

        MouseExploits handler = new MouseExploits();

        mousePanel.addMouseListener(handler);
        mousePanel.addMouseMotionListener(handler);



    }

    private class MouseExploits extends MouseAdapter{
        public void mousePressed(MouseEvent mouse){
            if(mouse.isMetaDown()){
                xS= mouse.getX();
                yS= mouse.getY();
            }
        }
        public void mouseDragged(MouseEvent mouse){
            if(!(mouse.isMetaDown() || mouse.isAltDown())){

                g.updateCoordinates(mouse.getX(),mouse.getY(), xS,yS);
                add(g);
                System.out.printf("%d,%d\n",mouse.getX(),mouse.getY());
                statusBar.setText(String.format("%d,%d",mouse.getX(),mouse.getY()));
            }
        }
    }
}

GraphicsPanel class

import java.awt.*;
import javax.swing.*;


public class GraphicsPanel extends JPanel{
    private int x;
    private int y;
    private int xS;
    private int yS;
    private Graphics dB;
    private Image dBImage;

    public graphics(int mouseX, int mouseY, int xSm, int ySm){
        x = mouseX;
        y = mouseY;
        xS=xSm;
        yS=ySm;
        //System.out.println("Breaks2");

    }

    public void updateCoordinates(int mouseX, int mouseY, int xSm, int ySm){
        x = mouseX;
        y = mouseY;
        xS=xSm;
        yS=ySm;
        //repaint();
    }

    public void paint(Graphics g){
        dBImage = createImage(getWidth(),getHeight());
        dB = dBImage.getGraphics();
        paintComponent(dB);
        g.drawImage(dBImage,0,0,this);
    }

    public void paintComponent(Graphics g){
        //super.paintComponent(g);
        System.out.println("Breaks3");
        g.drawLine(xS,yS,x,y);
        repaint();
    }
}

MainProg class

import javax.swing.JFrame;

public class MainProg {
    public static void main(String args[]){
        MouseAction frameObj= new MouseAction ();
        frameObj.setSize(300,230);

        frameObj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frameObj.setVisible(true);
    }
}

EDIT: Code now contains double buffering and been revamped so the GraphicsPanel doesn't instantiate multiple of time how ever the issue of not be able to remove JLabel without breaking the program continues.

EDIT 2: after some messing around with the window after removing the JLabel, It seems to only work when i dragged on the screen,resized the window and then drag on the screen again. So it would seem there is some jpanel layout error which some how gets fixed by the jlabel being there.

1

There are 1 answers

7
Jean-Baptiste Yunès On BEST ANSWER

First problem with your code is that you instanciate graphics at each mouseDragged event. This is weird and bad. You must only handle each mouseDragged, store the coordinates and call repaint on the single graphics instance created and added to the interface at the beginning. This will cause a refresh.

Second, the paintComponent should just make the drawings so you must use some kind of (1) double buffering (create a off-line BufferedImage and its associated Graphics, draw into it and use it in the refresh), (2) collection of Point caught in mouseDragged and use them to drawPolyline in the paintComponent method.


Third don't call repaint() inside paintComponent. This will unnecessarily triggers calls to paintComponent in a kind of never ending loop.

Fourthly don't create a double buffer each time paint is called. At each refresh you will create a new Image. Create it once, draw in it in your mouseDraggedmethod and trigger from it a repaint(), then make a drawImage in paintComponent.