有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在不重新验证的情况下调整面板大小

我有一个JPanel我在其中画线来创造铅笔的错觉。此面板位于ScrollPane

当我调整面板大小时,对revalidate()方法的一个调用将自动放置,并且我在此面板中绘制的所有线条都将消失。有没有办法让我的画线保持在面板上的新尺寸

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
 *
 * @author Sanjeev
 */
public class WorkArea extends JFrame implements ActionListener, MouseListener, MouseMotionListener 
{
 private final int  PEN_OP         = 1;
 private final int  ERASER_OP      = 2;
 private final int  SCROLL_OP      = 3;
 private int mousex                = 0;
 private int mousey                = 0;
 private int prevx                 = 0;
 private int prevy                 = 0;
 private boolean initialPen        = true;
 private boolean initialEraser     = true;
 private int  eraserLength         = 5;
 private int    opStatus           = PEN_OP;
 private Color  mainColor          = new Color(0,0,0);
 private int drawPanelHeight       =1000;

    public WorkArea()
    {
        initComponents();
        setLocationRelativeTo(null);
        pencilButton.addActionListener(this);
        eraserButton.addActionListener(this);
        drawPanel.addMouseMotionListener(this);
        drawPanel.addMouseListener(this);
        drawPanel.add(new TestPane());
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
    }

    private void initComponents() {

        headerPanel = new javax.swing.JPanel();
        backButton = new javax.swing.JLabel();
        headerImage = new javax.swing.JLabel();
        controlPanel = new javax.swing.JPanel();
        scrollButton = new javax.swing.JButton();
        pencilButton = new javax.swing.JButton();
        eraserButton = new javax.swing.JButton();
        drawingPanel = new javax.swing.JPanel();
        drawingScrollPane = new javax.swing.JScrollPane();
        drawPanel = new javax.swing.JPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("v0.1");
        setBackground(new java.awt.Color(237, 254, 255));
        setBounds(new java.awt.Rectangle(0, 0, 513, 693));
        setResizable(false);

        headerPanel.setBackground(new java.awt.Color(237, 254, 255));
        headerPanel.setPreferredSize(new java.awt.Dimension(513, 25));
        headerPanel.setLayout(null);

        backButton.setBackground(new java.awt.Color(237, 254, 255));
        backButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        backButton.setForeground(new java.awt.Color(255, 255, 255));
        backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/back-arrow.png"))); // NOI18N
        backButton.setText("Back");
        backButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        backButton.setPreferredSize(new java.awt.Dimension(40, 20));
        headerPanel.add(backButton);
        backButton.setBounds(0, 3, 40, 20);

        headerImage.setBackground(new java.awt.Color(237, 254, 255));
        headerImage.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
        headerImage.setForeground(new java.awt.Color(255, 255, 255));
        headerImage.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/topbar_ipad_wide.png"))); // NOI18N
        headerImage.setText("Work Area");
        headerImage.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        headerImage.setPreferredSize(new java.awt.Dimension(513, 25));
        headerPanel.add(headerImage);
        headerImage.setBounds(0, 0, 513, 25);

        controlPanel.setBackground(new java.awt.Color(237, 254, 255));
        controlPanel.setPreferredSize(new java.awt.Dimension(90, 670));
        controlPanel.setLayout(null);

        scrollButton.setBackground(new java.awt.Color(237, 254, 255));
        scrollButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/up_down_ipad.png"))); // NOI18N
        scrollButton.setPreferredSize(new java.awt.Dimension(60, 60));
        scrollButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                scrollButtonMouseClicked(evt);
            }
        });
        controlPanel.add(scrollButton);
        scrollButton.setBounds(20, 570, 60, 60);

        pencilButton.setBackground(new java.awt.Color(237, 254, 255));
        pencilButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/pencil_ipad.png"))); // NOI18N
        pencilButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                pencilButtonMouseClicked(evt);
            }
        });
        controlPanel.add(pencilButton);
        pencilButton.setBounds(20, 450, 60, 60);

        eraserButton.setBackground(new java.awt.Color(237, 254, 255));
        eraserButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/eraser_ipad.png"))); // NOI18N
        eraserButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                eraserButtonMouseClicked(evt);
            }
        });
        controlPanel.add(eraserButton);
        eraserButton.setBounds(20, 510, 60, 60);

        drawingPanel.setBackground(new java.awt.Color(237, 254, 255));
        drawingPanel.setPreferredSize(new java.awt.Dimension(420, 670));
        drawingPanel.setLayout(null);

        drawingScrollPane.setBorder(null);
        drawingScrollPane.setPreferredSize(new java.awt.Dimension(423, 1000));

        drawPanel.setBackground(new java.awt.Color(237, 254, 255));
        drawPanel.setPreferredSize(new java.awt.Dimension(400, 1000));
        drawPanel.setLayout(null);
        drawingScrollPane.setViewportView(drawPanel);

        drawingPanel.add(drawingScrollPane);
        drawingScrollPane.setBounds(0, 0, 424, 670);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 513, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(headerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 513, javax.swing.GroupLayout.PREFERRED_SIZE))
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(0, 423, Short.MAX_VALUE)))
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                    .addGap(0, 93, Short.MAX_VALUE)
                    .addComponent(drawingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 420, javax.swing.GroupLayout.PREFERRED_SIZE)))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 693, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(headerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(0, 668, Short.MAX_VALUE)))
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                    .addGap(0, 23, Short.MAX_VALUE)
                    .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 670, javax.swing.GroupLayout.PREFERRED_SIZE)))
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                    .addGap(0, 23, Short.MAX_VALUE)
                    .addComponent(drawingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 670, javax.swing.GroupLayout.PREFERRED_SIZE)))
        );

        pack();
    }                      

    @Override
    public void actionPerformed(ActionEvent e) 
    {
       if (e.getActionCommand() == "Pen")
       opStatus = PEN_OP;

       if (e.getActionCommand() == "Eraser")
       opStatus = ERASER_OP;

       if(e.getActionCommand() == "Scroll")
       opStatus = SCROLL_OP;
    }

    private void pencilButtonMouseClickedTest(java.awt.event.MouseEvent evt) 
    {                                         
        opStatus = PEN_OP;
        Graphics g  = drawPanel.getGraphics();

      if (initialPen)
      {  
       setGraphicalDefaults(evt);
       initialPen = false;
       g.drawLine(prevx,prevy,mousex,mousey);
      }
      if (mouseHasMoved(evt))
      {  
       mousex = evt.getX();
       mousey = evt.getY();
       g.drawLine(prevx,prevy,mousex,mousey);
       prevx = mousex;
       prevy = mousey;
      }
    } 

    private void eraserButtonMouseClickedTest(java.awt.event.MouseEvent evt)
    {
       opStatus = ERASER_OP;
       Graphics g  = drawPanel.getGraphics();

      if (initialEraser)
      {  
       setGraphicalDefaults(evt);
       initialEraser = false;
       mousex = evt.getX();
       mousey = evt.getY();
       System.out.println("Initial Eraser ::::::::x's value is : "+prevx+" , "+mousey+" and y's value is : "+mousex+" , "+mousey);
       g.setColor(new java.awt.Color(237,254,255));
       g.fillRect(mousex-eraserLength, mousey-eraserLength,eraserLength*2,eraserLength*2);
       //g.setColor(Color.black); //Eraser Border
       g.drawRect(mousex-eraserLength,mousey-eraserLength,eraserLength*2,eraserLength*2);
       prevx = mousex;
       prevy = mousey;
      }

      if (mouseHasMoved(evt))
      {
       System.out.println("Eraser ::::::::x's value is : "+prevx+" , "+mousey+" and y's value is : "+mousex+" , "+mousey);
       g.setColor(new java.awt.Color(237,254,255));
       g.drawRect(prevx-eraserLength, prevy-eraserLength,eraserLength*2,eraserLength*2);

       mousex  = evt.getX();
       mousey  = evt.getY();

       /* Draw eraser block to panel */
       g.setColor(new java.awt.Color(237,254,255));
       g.fillRect(mousex-eraserLength, mousey-eraserLength,eraserLength*2,eraserLength*2);
       g.setColor(Color.black);//Eraser Border
       g.drawRect(mousex-eraserLength,mousey-eraserLength,eraserLength*2,eraserLength*2);
       prevx = mousex;
       prevy = mousey;
      }
    }


    private void scrollButtonMouseClicked(java.awt.event.MouseEvent evt) {                                          
      opStatus = SCROLL_OP;
      drawingScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {

      @Override
      public void adjustmentValueChanged(AdjustmentEvent e) 
      {
        int extent,curValue;
        extent = drawingScrollPane.getVerticalScrollBar().getModel().getExtent();
        curValue = drawingScrollPane.getVerticalScrollBar().getValue()+extent;
        if(curValue==drawPanel.getHeight())
        {
        System.out.println("value of scroll equals to Max value....");
        drawPanel.setPreferredSize(new Dimension(423,drawPanelHeight*4));       
        }
        System.out.println("Value: " + curValue + " Max: " + drawingScrollPane.getVerticalScrollBar().getMaximum());
      }
      });
    }                                         

    private void eraserButtonMouseClicked(java.awt.event.MouseEvent evt) {                                          
       eraserButtonMouseClickedTest(evt);
       updateMouseCoordinates(evt);
    }                                         

    private void pencilButtonMouseClicked(java.awt.event.MouseEvent evt) {                                          
       opStatus = PEN_OP;

    }                                         




  public boolean mouseHasMoved(MouseEvent e)
   {
    return (mousex != e.getX() || mousey != e.getY());
   }

 public void setGraphicalDefaults(MouseEvent e)
 {
    mousex   = e.getX();
    mousey   = e.getY();
    prevx    = e.getX();
    prevy    = e.getY();
 }

 @Override
    public void mouseDragged(MouseEvent e)
    {
        updateMouseCoordinates(e);

       switch (opStatus)
       {
          case PEN_OP   : pencilButtonMouseClickedTest(e);
                          break;
          case ERASER_OP: eraserButtonMouseClicked(e);
                          break;
          case SCROLL_OP: scrollButtonMouseClicked(e);
                          break;
       }
    }

    public void mouseReleased(MouseEvent e)
    {  
        updateMouseCoordinates(e);

       switch (opStatus)
       {
          case PEN_OP    : releasedPen();
                           break;
          case ERASER_OP : releasedEraser();
                           break;
       }
    }

   public void mouseEntered(MouseEvent e)
   {
    updateMouseCoordinates(e);
   }

   public void releasedPen()
   {
    initialPen = true;
   }

    public void releasedEraser()
    {
    initialEraser = true;
    Graphics g  = drawPanel.getGraphics();
    g.setColor(mainColor.white);
    g.drawRect(mousex-eraserLength,mousey-eraserLength,eraserLength*2,eraserLength*2);
    }

    public void updateMouseCoordinates(MouseEvent e)
    {
    String xCoor ="";
    String yCoor ="";

    if (e.getX() < 0) xCoor = "0";
    else
    {
       xCoor = String.valueOf(e.getX());
    }

    if (e.getY() < 0) xCoor = "0";
    else
    {
       yCoor = String.valueOf(e.getY());
    }
   }

    public static void main(String args[]) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(WorkArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(WorkArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(WorkArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(WorkArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }

        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new WorkArea().setVisible(true);
            }
        });
    }                   
    private javax.swing.JLabel backButton;
    private javax.swing.JPanel controlPanel;
    private javax.swing.JPanel drawPanel;
    private javax.swing.JPanel drawingPanel;
    private javax.swing.JScrollPane drawingScrollPane;
    private javax.swing.JButton eraserButton;
    private javax.swing.JLabel headerImage;
    private javax.swing.JPanel headerPanel;
    private javax.swing.JButton pencilButton;
    private javax.swing.JButton scrollButton;             

    @Override
    public void mouseClicked(MouseEvent e) {

    }

     @Override
    public void mouseExited(MouseEvent e) {
        updateMouseCoordinates(e);
    }

     @Override
    public void mouseMoved(MouseEvent e) {
        updateMouseCoordinates(e);
    }

    @Override
    public void mousePressed(MouseEvent e) {
        updateMouseCoordinates(e);
    }
}

共 (1) 个答案

  1. # 1 楼答案

    我假设你是通过使用getGraphics()来绘制JPanel并将输出呈现给它

    你现在已经明白为什么不应该这样做了。重新绘制组件时,之前绘制的任何内容都会被擦拭干净,您需要重新绘制内容

    首先重写paintComponent并更新此方法中的所有行(不要忘记调用super.paintComponent

    详见Performing Custom PaintingPainting in AWT and Swing

    例如

    用示例更新

    这是对MouseEvent is not registering a release when I release the mouse button答案的修改版本,其中包括一个滚动窗格

    enter image description here

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Point;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.UIManager;
    
    public class MouseDraggedTest {
    
        public static void main(String[] args) {
            new MouseDraggedTest();
        }
    
        public MouseDraggedTest() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (Exception ex) {
                    }
    
                    JFrame frame = new JFrame("Test");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new JScrollPane(new TestPane()));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private Map<Point, List<Point>> mapPoints;
            private Point currentPoint;
    
            public TestPane() {
                mapPoints = new HashMap<>(25);
                MouseAdapter mouseListener = new MouseAdapter() {
                    @Override
                    public void mousePressed(MouseEvent e) {
                        currentPoint = e.getPoint();
                        mapPoints.put(currentPoint, new ArrayList<Point>(25));
                    }
    
                    @Override
                    public void mouseReleased(MouseEvent e) {
                        List<Point> points = mapPoints.get(currentPoint);
                        if (points.isEmpty()) {
                            mapPoints.remove(currentPoint);
                        }
                        currentPoint = null;
                    }
    
                    @Override
                    public void mouseDragged(MouseEvent me) {
                        List<Point> points = mapPoints.get(currentPoint);
                        points.add(me.getPoint());
                        repaint();
                    }
                };
                addMouseListener(mouseListener);
                addMouseMotionListener(mouseListener);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 800);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
    
                for (Point startPoint : mapPoints.keySet()) {
                    List<Point> points = mapPoints.get(startPoint);
                    for (Point p : points) {
                        if (startPoint != null) {
                            g.drawLine(startPoint.x, startPoint.y, p.x, p.y);
                        }
                        startPoint = p;
                    }
                }
            }
        }
    }
    

    更新了一个BuffereImage示例

    因为您需要提供更多的操作,而不仅仅是绘图,所以您可能会发现使用BufferedImage作为主要绘图面并将其渲染到DrawingPanel

    enter image description here

    import java.awt.BasicStroke;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Point;
    import java.awt.Shape;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.geom.Ellipse2D;
    import java.awt.geom.Line2D;
    import java.awt.image.BufferedImage;
    import javax.swing.ButtonGroup;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JToggleButton;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class MyPicture {
    
        public static void main(String[] args) {
            new MyPicture();
        }
    
        public MyPicture() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public enum DrawOperation {
    
            Draw,
            Erase
    
        }
    
        public class TestPane extends JPanel {
    
            private DrawOperation op;
    
            private JToggleButton pencil;
            private JToggleButton eraser;
    
            private DrawPane drawPane;
    
            public TestPane() {
                setLayout(new BorderLayout());
    
                drawPane = new DrawPane();
    
                MouseAdapter adapter = new MouseAdapter() {
    
                    private Point startPoint;
    
                    @Override
                    public void mouseEntered(MouseEvent e) {
                        drawPane.updateDrawCursor(e.getPoint(), op);
                    }
    
                    @Override
                    public void mouseExited(MouseEvent e) {
                        drawPane.removeDrawCursor();
                    }
    
                    @Override
                    public void mousePressed(MouseEvent e) {
                        startPoint = e.getPoint();
                    }
    
                    @Override
                    public void mouseReleased(MouseEvent e) {
                        startPoint = null;
                    }
    
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        drawPane.applyOperation(startPoint, e.getPoint(), op);
                        drawPane.updateDrawCursor(e.getPoint(), op);
                        startPoint = e.getPoint();
                    }
    
                    @Override
                    public void mouseMoved(MouseEvent e) {
                        drawPane.updateDrawCursor(e.getPoint(), op);
                    }
    
                };
    
                drawPane.addMouseListener(adapter);
                drawPane.addMouseMotionListener(adapter);
    
                JPanel operations = new JPanel(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
    
                pencil = new JToggleButton("Draw");
                eraser = new JToggleButton("Erase");
    
                ButtonGroup bgOps = new ButtonGroup();
                bgOps.add(pencil);
                bgOps.add(eraser);
    
                operations.add(pencil, gbc);
                operations.add(eraser, gbc);
    
                pencil.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        op = DrawOperation.Draw;
                    }
                });
    
                eraser.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        op = DrawOperation.Erase;
                    }
                });
    
                add(operations, BorderLayout.WEST);
                add(new JScrollPane(drawPane));
            }
    
        }
    
        public class DrawPane extends JPanel {
    
            private BufferedImage image;
            private Shape drawCursor;
            private Point cursorPoint;
    
            private int eraseSize = 20;
    
            public DrawPane() {
                image = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB);
                Graphics2D g2d = image.createGraphics();
                g2d.setBackground(Color.WHITE);
                g2d.fillRect(0, 0, 400, 400);
                g2d.dispose();
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 400);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                if (image != null) {
                    g2d.drawImage(image, 0, 0, this);
                }
                if (drawCursor != null && cursorPoint != null) {
                    int x = (cursorPoint.x - (drawCursor.getBounds().width) / 2);
                    int y = (cursorPoint.y - (drawCursor.getBounds().height) / 2);
                    g2d.translate(x, y);
                    g2d.draw(drawCursor);
                    g2d.translate(-x, -y);
                }
                g2d.dispose();
            }
    
            public void updateDrawCursor(Point point, DrawOperation op) {
                cursorPoint = point;
                if (op != null) {
                    switch (op) {
                        case Draw:
                            drawCursor = new Ellipse2D.Float(0, 0, 4, 4);
                            break;
                        case Erase:
                            drawCursor = new Ellipse2D.Float(0, 0, eraseSize, eraseSize);
                            break;
                    }
                } else {
                    drawCursor = null;
                }
                repaint();
            }
    
            protected void removeDrawCursor() {
                drawCursor = null;
                repaint();
            }
    
            protected void applyOperation(Point fromPoint, Point toPoint, DrawOperation op) {
                if (image != null) {
    
                    if (op != null) {
                        Graphics2D g2d = image.createGraphics();
                        switch (op) {
                            case Draw:
                                g2d.setColor(Color.BLACK);
                                g2d.draw(new Line2D.Float(fromPoint, toPoint));
                                break;
                            case Erase:
                                g2d.setColor(Color.WHITE);
                                g2d.setStroke(new BasicStroke(eraseSize));
                                g2d.draw(new Line2D.Float(fromPoint, toPoint));
                                break;
                        }
                        g2d.dispose();
                    }
    
                }
                repaint();
            }
        }
    }