javaswingjpanelborderborder-layout

JPanel background is doubled , but Panel is working expected


package com.company;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayDeque;
import java.util.Random;

public class REcom {
    REcom() {
        JFrame jfm = new JFrame("Paint");
        jfm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        BorderLayout border = new BorderLayout();
        border.setVgap(10);

        jfm.setLayout(border);


        DrawPanel dw = new DrawPanel();

        dw.addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                dw.setXY(e.getX() , e.getY());
                dw.repaint();
            }

            @Override
            public void mouseMoved(MouseEvent e) {
                dw.previosPosition = new Position(e.getX() , e.getY());

            }
        });


        jfm.add(dw  ,BorderLayout.CENTER);
        jfm.setBackground(Color.white);
        jfm.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
        jfm.setSize(500 ,500);

        JPanel color = new JPanel(new FlowLayout(FlowLayout.LEFT));
        //that Jpanel background is doubled
       // color.setBounds(new Rectangle(0 ,0 , 100 , jfm.getHeight()));

        Button blue = new Button();
        blue.setBackground(Color.blue);
        blue.setSize(500 ,200);
        blue.addActionListener(e -> {
            dw.color = Color.blue;
        });
        color.add(blue);

        Button white = new Button();
        white.setBackground(Color.white);
        white.setSize(200 ,200);
        white.addActionListener(e -> {
            dw.color = Color.white;
        });

        color.add(white);

        jfm.add(color , BorderLayout.NORTH);
        jfm.setPreferredSize(new Dimension(500 ,500));
        jfm.pack();
        color.setBackground(Color.blue);
        jfm.setVisible(true);

    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(REcom::new);
    }

}
class DrawPanel extends JPanel {
    ArrayDeque<Position> ad = new ArrayDeque<>();
    Position previosPosition = null;
    Color color = Color.yellow;
    void setXY(int x , int y) {
        ad.push(new Position(x , y));
    }
    @Override
    protected void paintComponent(Graphics g) {


        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(color);

        g2.setStroke(new BasicStroke(12f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
        Position d = ad.pollLast();

        if(d != null) {

            if(previosPosition == null)
                g2.fillOval(d.x, d.y -10 , d.x , d.y-10);
            else{

                g2.drawLine(previosPosition.x -5 , previosPosition.y -10 , d.x-5 , d.y-10);
            }

            previosPosition = d;
        }


    }

}
class Position {
    int x, y;
    Position(int x, int y) {
        this.x=  x;
        this.y = y;
    }
    void setXY(int x , int y) {
        this.x = x;
        this.y = y;
    }
}

about code: two panels, one intended for drawing, another for the switch between colors. I decided to add the switcher to the top in frame. But its background move to the bottom and I can draw on it.(therefore its background out of border). and if I will set a border for central JPanel its panel (for drawing), top of the border is doubled
I wanted to add Jpanel to the top for switch between colors (background is doubled after drawing anything )for drawing. But the top Jpanel background is doubled. But if I will replace Jpanel (color) by the common panel, the program work normally. I don't know why? Please help! if you don't understand please try run code (this question I wrote with translater)


Solution

  • JPanel background is doubled

    When you do custom painting, the first statement in your method should be:

    super.paintComponent(g);
    

    to clear the background otherwise you can have painting artifacts, which is why you see the two blue lines.

    Of course when you do add the super.paintComponent(g) the painting disappears because the background is cleared.

    The are two solutions to the problem:

    1. keep an ArrayList of object to paint and the iterate through the ArrayList in the paintComponent() method to paint all the objects
    2. paint to a BufferedImage, then just draw the entire image.

    I would suggest that option 2 might be the best in this case.

    Check out Custom Painting Approaches for more information and examples of each approach.