Clear window from drawing objects

2019-05-31 17:56发布

问题:

I have 4 classes:

Draw, Rectangle (extends Draw), FreeHand (extends Draw) and a test class.

I add rectangles and lines drawn by free hand to an arrayList.

I have a menubar with choices Back and Clear. Back removes the last drawn object. It is done by removing the last object in the arraylist. Clear clears the windows. It is done by clear the arraylist from all items.

Now to my problem: The window does not clear. I don't know how to write the code to make it repaint properly so that the items removes from the window. Can you please help me with how the code for this would look like, and where I put it. I appreciate it, thank you.

My problem no 2: After I have removed the last item in the arraylist I need to draw all the items in the arrayList. I have tried

 for (Draw d : shapeList) {
        d.draw(g2);
    } 

But it does not work. Any suggestions? Class Draw:

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

public abstract class Draw extends JPanel {

    public int startX, startY, endX, endY, width, height, w, h;
    public String color = "Black";

    public Draw(int startX, int startY, int width, int height) {
        this.startX = startX;
        this.startY = startY;
        this.width = width;
        this.height = height;
    }

    public abstract void draw(Graphics2D g);


    @Override
    public int getX() {
        return startX;
    }

    public void setX(int startX) {
        this.startX = startX;
    }

    @Override
    public int getY() {
        return startY;
    }

    public void setY(int startY) {
        this.startY = startY;
    }

    @Override
    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    @Override
    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

Class Rectangle:

import java.awt.Color;
import java.awt.Graphics2D;

public class Rectangle extends Draw {

    public Rectangle(int x, int y, int width, int height) {
        super(x, y, width, height);
    }

    @Override
    public void draw(Graphics2D g2) {
        switch (color) {
            case "Red":
                g2.setColor(Color.RED);
                break;
            case "Green":
                g2.setColor(Color.GREEN);
                break;
            case "Blue":
                g2.setColor(Color.BLUE);
                break;
            case "Yellow":
                g2.setColor(Color.YELLOW);
                break;
            case "Orange":
                g2.setColor(Color.ORANGE);
                break;
            case "Black":
                g2.setColor(Color.BLACK);
                break;
            }

        g2.drawRect(getX(), getY(), getWidth(), getHeight());
    }  
}

Class FreeHand:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;

public class FreeHand extends Draw {

     public FreeHand(int x, int y, int width, int height) {
        super(x, y, width, height);
    }

   /* public FreeHand() {
        super();
    }*/


    @Override
    public void draw(Graphics2D g2) {
        //Graphics2D g2 = (Graphics2D) g;          
        g2.setStroke(new BasicStroke(3));    
            switch (color) {
            case "Red":
                g2.setColor(Color.RED);
                break;
            case "Green":
                g2.setColor(Color.GREEN);
                break;
            case "Blue":
                g2.setColor(Color.BLUE);
                break;
            case "Yellow":
                g2.setColor(Color.YELLOW);
                break;
            case "Orange":
                g2.setColor(Color.ORANGE);
                break;
            case "Black":
                g2.setColor(Color.BLACK);
                break;
            }
        g2.drawLine(getX(), getY(), getWidth(), getHeight());
    }
}

Testclass:

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

public class JavaApplication30 extends JFrame implements ActionListener {

    public ArrayList<Draw> shapeList = new ArrayList<>();   
    int startX, startY, endX, endY, w, h;
    private JPanel topPanel;   
    private JPanel bottomPanel;
    private JPanel orangePanel;
    private JPanel greenPanel;
    private JPanel bluePanel;
    private JPanel blackPanel;
    private JPanel redPanel;
    private JPanel yellowPanel;
    private JPanel leftPanel;
    private JPanel rightPanel;
    private JPanel colorPanel;   
    private JMenuBar menuBar;
    private JMenu menu;
    private JMenuItem menuItem1;
    private JMenuItem menuItem2;
    private JMenuItem menuItem3;
    private JComboBox comboBox;
    private JLabel leftLabel;        
    private JLabel commaLabel;
    private JLabel colorLabel;
    private static JLabel xLabel;
    private static JLabel yLabel;
    private final String labelText = "Coordinates: ";
    private final String comma = ",";
    private final String color = "Color: ";    
    private final String[] boxOptions = new String[] {"Rectangle", "Freehand"};   
    private String pickedColor = "Black";
    private String x = "";
    private String y = "";     
    Container cp = getContentPane();
    private int count = 0;



    public JavaApplication30(String title) {
        super(title);
        this.setLayout(new BorderLayout());
        this.setLocationRelativeTo(null);        
        this.setSize(840, 500);     
        this.initComponents();
        this.initMenu();
        this.setVisible(true);
    }


    private void initComponents() {
        cp.setBackground(Color.WHITE);

        comboBox = new JComboBox(boxOptions);
        topPanel = new JPanel(new GridLayout(1,7));     
        bottomPanel = new JPanel(new GridLayout(1,2)); 
        orangePanel = new JPanel();
        greenPanel = new JPanel();
        bluePanel= new JPanel();
        blackPanel = new JPanel();
        redPanel = new JPanel();
        yellowPanel = new JPanel();
        colorPanel = new JPanel();
        rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        leftPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));

        comboBox.setSelectedIndex(0);          
        comboBox.addActionListener(this); 

        topPanel.setPreferredSize(new Dimension(0,40));        
        bottomPanel.setPreferredSize(new Dimension(0,30));
        colorPanel.setPreferredSize(new Dimension(60,20)); 

        leftLabel = new JLabel(labelText);
        commaLabel = new JLabel(comma);
        colorLabel = new JLabel(color);  

        bottomPanel.setBackground(Color.LIGHT_GRAY);        
        orangePanel.setBackground(Color.ORANGE);       
        greenPanel.setBackground(Color.GREEN);
        bluePanel.setBackground(Color.BLUE);        
        blackPanel.setBackground(Color.BLACK);        
        redPanel.setBackground(Color.RED);      
        yellowPanel.setBackground(Color.YELLOW);  
        colorPanel.setBackground(Color.BLACK);

        topPanel.add(orangePanel);
        topPanel.add(greenPanel);                               
        topPanel.add(bluePanel);                                
        topPanel.add(blackPanel);
        topPanel.add(redPanel);
        topPanel.add(yellowPanel);
        topPanel.add(comboBox);
        rightPanel.add(colorLabel);
        rightPanel.add(colorPanel);
        bottomPanel.add(leftPanel);        
        bottomPanel.add(rightPanel);

        this.add(topPanel, BorderLayout.PAGE_START);          
        this.add(bottomPanel, BorderLayout.PAGE_END);

    }


    @Override
    public void paint(Graphics g) {
        if(count == 0) {
            cp.repaint();
        }

        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g2.setStroke(new BasicStroke(1));

        for (Draw d : shapeList) {
            d.draw(g2);
        }


        if (startX != 0 && startY != 0 && endX != 0 && endY != 0) {

            int width = Math.abs(startX - endX);
            int height = Math.abs(startY - endY);

            int minX = Math.min(startX, endX);
            int minY = Math.min(startY, endY);               

            Rectangle r = new Rectangle(minX, minY, width, height);

            g2.setPaint(Color.WHITE);
            g2.fillRect(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 
            r.setColor(pickedColor);

            r.draw(g2);
        }
    }



    @Override
    public void actionPerformed(ActionEvent e) {
        count++;
        if (e.getSource().equals(menuItem1)) {            
            shapeList.clear();

            //Code to clear window

        }
        if (e.getSource().equals(menuItem2)) {
            shapeList.remove(shapeList.size() - 1);

            //Code to clear window

            Graphics g = getGraphics();    
            Graphics2D g2 = (Graphics2D) g;
            for (Draw d : shapeList) {
                d.draw(g2);
            }      
        }


        if (e.getSource().equals(menuItem3)) {
            //Exit
        }



        if (e.getSource().equals(comboBox)) {    

            JComboBox cb = (JComboBox)e.getSource();

            if (cb.getSelectedItem().equals("Rectangle")) {

                this.addMouseListener(new MouseAdapter() {    

                    @Override
                    public void mousePressed(MouseEvent e) {                   
                        startX = e.getX();     
                        startY = e.getY(); 

                        endX = startX;  
                        endY = startY;  
                        repaint();                                             

                    }

                    @Override
                    public void mouseReleased(MouseEvent e) {
                        endX = e.getX();
                        endY = e.getY();

                        int width = Math.abs(startX - endX);
                        int height = Math.abs(startY - endY);

                        int minX = Math.min(startX, endX);
                        int minY = Math.min(startY, endY);               

                        Rectangle r =  new Rectangle(minX, minY, width, height);
                        shapeList.add(r);
                        r.setColor(pickedColor);

                        startX = 0;
                        startY = 0;
                        endX = 0;
                        endY = 0;
                        repaint();
                    }
                });    

                this.addMouseMotionListener(new MouseMotionAdapter() {
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        endX = e.getX();
                        endY = e.getY();
                        repaint();
                    }
                });
            }            


            else if (cb.getSelectedItem().equals("Freehand")) {

                this.addMouseListener(new MouseAdapter() {                   
                    @Override
                    public void mousePressed(MouseEvent e) {                   
                        startX = e.getX();
                        startY = e.getY();             
                    }
                });

                this.addMouseMotionListener(new MouseMotionAdapter() {
                    @Override
                    public void mouseDragged(MouseEvent e) {                
                        Graphics g = getGraphics();    
                        Graphics2D g2 = (Graphics2D) g;          

                        FreeHand fh =  new FreeHand(startX, startY, e.getX(), e.getY());
                        shapeList.add(fh);
                        fh.setColor(pickedColor);
                        fh.draw(g2);                    
                        startX = e.getX();
                        startY = e.getY();                         
                    }
                });    
            }
        }
    }





     private void initMenu() {

        menuBar = new JMenuBar();
        menu = new JMenu("File");
        menuBar.add(menu);


        menuItem1 = new JMenuItem("Clear");
        menuItem2 = new JMenuItem("Back");
        menuItem3 = new JMenuItem("Exit");
        menu.add(menuItem1);
        menu.add(menuItem2);
        menu.addSeparator();
        menu.add(menuItem3);

        menu.setMnemonic(KeyEvent.VK_A);                                              
        KeyStroke ks1 = KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK);  //Crtl+n
        KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.CTRL_MASK);  //Ctrl+i
        KeyStroke ks3 = KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK);  //Ctrl+e      
        menuItem1.setAccelerator(ks1);
        menuItem2.setAccelerator(ks2);
        menuItem3.setAccelerator(ks3);

      menuItem1.addActionListener(this);      
    menuItem2.addActionListener(this);
    menuItem3.addActionListener(this);

        setJMenuBar(menuBar);               
    }




    public static void main(String args[]) {
        new JavaApplication30("Draw");
    }
}

回答1:

Your problem looks to be that your paint method is not calling the super's paint method since this will have the component clean itself of all "dirty" image bits. But having said that, you shouldn't draw directly in the JFrame. Instead draw in the paintComponent method of a JComponent or JPanel, and in that method be sure to call the super's paintComponent method:

public class MyDrawingPanel extends JPanel {

    @Override
    proteced void paintComponent(Graphics g) {
        super.paintComponent(g); // don't forget this!

        // do your drawing here
    }
}

Also, why does your Draw class, and thus all classes that derive from it, extend JPanel when it is not being used as a JPanel? You are giving a lot of unnecessary overhead to these classes this way.


Edit
You ask:

So you mean I should move Everything in the paint-method to the paintComponent-method in Draw? Why protected?

No. I mean that Draw should not extend JPanel, but instead should be a logical class, not a Swing component-derived class. I think that you should create a new class, say called MyDrawingPanel where you do all of your drawing. Please see my code snippet above. Also paintComponent is declared in JComponent to be protected, not public, and I see no advantage to making it public when overriding it, so I recommend leaving it protected.

Please read the Swing Info Links to see the Swing graphics tutorials and give them a read.


Edit 2
You're also using a getGraphics() call on a component to get your Graphics object, not good as this will return an unstable Graphics object. Instead do all drawing in the paintComponent method or on a BufferedImage (that again is drawn in paintComponent).


Edit 3

Some of my code examples:

  • Minimal way to make a cleanable drawing area
  • Changing JPanel Graphics g color drawing line
  • Graphics in repaint draws random lines