Java JPanel的背景是原来的两倍,但小组工作正常

Java JPanel的背景是原来的两倍,但小组工作正常,java,swing,jpanel,border,border-layout,Java,Swing,Jpanel,Border,Border Layout,关于代码:两个面板,一个用于绘图,另一个用于在颜色之间切换。我决定将切换器添加到框架的顶部。但是它的背景移到了底部,我可以在上面画画,因此它的背景超出了边界。若我将为中央JPanel设置一个边框,它的面板用于绘图,边框的顶部将加倍 我想将Jpanel添加到顶部,以便在绘图时在颜色之间切换。但顶级Jpanel背景是双倍的。但是如果我用通用面板替换Jpanel颜色,程序就会正常工作。我不知道为什么?请帮忙!如果您不明白,请尝试运行我用translater编写的这个问题的代码 JPanel背景加倍 进

关于代码:两个面板,一个用于绘图,另一个用于在颜色之间切换。我决定将切换器添加到框架的顶部。但是它的背景移到了底部,我可以在上面画画,因此它的背景超出了边界。若我将为中央JPanel设置一个边框,它的面板用于绘图,边框的顶部将加倍 我想将Jpanel添加到顶部,以便在绘图时在颜色之间切换。但顶级Jpanel背景是双倍的。但是如果我用通用面板替换Jpanel颜色,程序就会正常工作。我不知道为什么?请帮忙!如果您不明白,请尝试运行我用translater编写的这个问题的代码

JPanel背景加倍

进行自定义绘制时,方法中的第一条语句应为:

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;
    }
}
若要清除背景,则可以使用绘画瑕疵,这就是为什么会看到两条蓝线

当然,当您添加super.paintcomponent时,由于背景已清除,因此绘画将消失

有两种解决方案:

保留要绘制的对象的ArrayList,并在paintComponent方法中迭代ArrayList以绘制所有对象 绘制缓冲区图像,然后只绘制整个图像。 我认为,在这种情况下,选择2可能是最好的


查看每种方法的更多信息和示例。

听这个家伙说。他是一个百分之百的秋千专家。不是很多人喜欢他。实际上我建议不要选择第二种。如果你不自己处理,你会失去dpi的伸缩性。使用选项2,我可以实现撤销和恢复rendo@ErnarJack,我不知道有什么有效的方法可以撤消/重做。在示例代码中,addRectangle。。。。方法,然后在BuffereImage上绘制矩形。因此,如果希望能够撤消,则需要在每次更新图像之前保留BuffereImage的副本。如果对绘制的每个椭圆都执行此操作,这将导致大量内存需求,因为您需要保留BuffereImage的多个副本。因此,如果您关心的是撤消/重做,那么方法1就是一条出路。
super.paintComponent(g);