0

So in the past few days I've tried to implement an easier version of a graph plotter. One big problem I was confronted with was a bug that occured on repainting. Basically I've designed my program in one class which is responsible for drawing the whole coordinate system and the given function after clicking a JButton in an other class. The other class contains the JButton which is pressed. After pressing the JButton it calls a function in the coordinate system class which repaints the picture. Both of those classes are extending JPanel.

The bug was that when I was doing the repainting on pressing the button, the button was drawn on the coordinate System and not in its original place, so in other words on the other JPanel even though I didn't change a thing about placements and stuff. Both classes were added to a JFrame which use a GridLayout.

Can anyone tell me why super.paintComponent(g); solved that bug?

Edit: Added Code

Window class

public class main {

public static void main(String[] args) throws SemanticFailureException {

    int x = 800;
    int y = 600;


    JFrame frame = new JFrame();
    frame.setLayout(new GridLayout());
    frame.setTitle("Function plotter");
    frame.setSize(2*x, 2*y);

    Surface test = new Surface(x, y, 10);
    CommandDraw test1 = new CommandDraw(x/2,y,test);


    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.add(test);
    frame.add(test1);


    frame.setVisible(true);

}
}

Coordinate System class: (changed drawing the coordinate system to a rectangle for simplicity, the bug still occures with only drawing a rectangle)

public class Surface extends JPanel {

/**
 * 
 */
private static final long serialVersionUID = 1L;
boolean drawFunct;

public Surface(int x1, int y1, int coordLength) {
    setSize(x1,y1);
    drawFunct = false;

}

public void paintComponent(Graphics g) {
    super.paintComponent(g); // without this the jbutton occures on the left

    // create Graphics object to get more functions
    Graphics2D g2 = (Graphics2D) g;
    // draw Plotter
    drawFunction(g2);

    if (drawFunct)
        g2.drawLine(0, 0, 80, 80);
}

public void drawFunction(Graphics2D g) {
    g.drawRect(40, 40, 30, 30);
}

public void redraw() {
    drawFunct = true;
    repaint();
}
}

The Class with the JButton:

public class CommandDraw extends JPanel {
/**
 * 
 */
private static final long serialVersionUID = 1L;
JButton makeDraw;
JTextField inputPoly;
Surface surf;

public CommandDraw(int x, int y, Surface surf) {
    this.surf = surf;
    setSize(x,y);
    setLayout(new FlowLayout());


    makeDraw = new JButton("draw Function");
    makeDraw.setBackground(Color.LIGHT_GRAY);
    makeDraw.setFocusable(false);

    makeDraw.addActionListener( new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            surf.redraw();

        }

    });

    add(makeDraw);


    inputPoly = new JTextField("Input polynomial");
    inputPoly.setHorizontalAlignment(JTextField.CENTER);
    add(inputPoly);


}
}
Pgrav
  • 11
  • 2
  • It is very difficult to understand what exactly you were doing wrong without seeing your code. There could be any number of reasons for your graphical glitches. There is plenty of opportunity for human errors when doing custom painting in swing. – DudeDoesThings Oct 18 '18 at 21:15
  • @DudeDoesThings no, not in his case. This "behaviour" is totally expected. – davidbuzatto Oct 18 '18 at 21:16

1 Answers1

0

Can anyone tell me why super.paintComponent(g); solved that bug?

Because the call to paintComponent(g) of the superclass (JPanel) will guarantee that panel will be rendered as expected before you do your paint operations. You need to make sure that your JPanel will behave, in the Graphics perspective, like any other JPanel.

A template for a customized JPanel to draw should be something like:

import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;

public class MyDrawPanel extends JPanel {

    @Override
    protected void paintComponent( Graphics g ) {

        super.paintComponent( g );

        // create a new graphics context based on the original one
        Graphics2D g2d = (Graphics2D) g.create();

        // draw whatever you want...


        g2d.dispose();

    }

}

EDIT

You need to call super.paintComponent(g) to tell that the JPanel paintComponent(Graphics) version should be execute before you start doind your customized things. It's something like to ask the JPanel to prepare its paint capabilities to be used. A good starting point to these kind of doubts is the documentation: https://docs.oracle.com/javase/10/docs/api/javax/swing/JComponent.html#paintComponent(java.awt.Graphics)

The dispose() method is being called in the copy of the original Graphics. If you dispose the Graphics that is passed to the method, you may have some issues too. You could use the original Graphics to perform you painting operations, but you shouldn't, so a better practice is to make a copy of the original Graphics and dispose it after using.

Take a look here too: How does paintComponent work?

davidbuzatto
  • 9,207
  • 1
  • 43
  • 50
  • Can you explain a little bit further why it'd behave in such a different and strange way? How is the jpanel which should have nothing to do with the other jpanel able to draw the jbutton there? If this gets too complex I'd really appreciate a link or something where I could read more. Thanks a lot though! I didn't even know I should be using .dispose() but Im going to read on that too! – Pgrav Oct 18 '18 at 21:41
  • @Pgrav I complemented my answer. Take a look. If my anser solves you question, please, consider marking it as solved. – davidbuzatto Oct 22 '18 at 17:26