在绘制矩形和徒手绘制之间切换

时间:2014-11-04 08:59:02

标签: java swing java-2d custom-painting

我的Java绘图程序存在一些问题。

我有JComboBox我可以选择绘制矩形或徒手绘制。对象将添加到ArrayList。我希望能够在绘制矩形和空手之间切换,然后再绘制一个矩形,然后用空手......等等。

如果我这样做,因为代码看起来像现在,它首先绘制矩形很好,然后当我切换到空闲手时它绘制线条很好,但是当我切换回矩形时它仍然绘制线条(或者有时与线条一起绘制线条)怪异的长方形)。我越切换它所得到的怪物。

任何人都可以看到代码有什么问题,因为我不能

public abstract class Draw  {
    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);       

    public int getX() {
        return startX;
    }

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

    public int getY() {
        return startY;
    }

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

    public int getWidth() {
        return width;
    }

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

    public int getHeight() {
        return height;
    }

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

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



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) {
        g2.drawRect(getX(), getY(), getWidth(), getHeight());
    }  
}

public class FreeHand extends Draw {

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

    @Override
    public void draw(Graphics2D g2) {            
        g2.drawLine(getX(), getY(), getWidth(), getHeight());
    }
}

public class PaintProgram 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 leftPanel;
    private JPanel rightPanel;
    private JComboBox comboBox;
    private final String[] boxOptions = new String[] {"Rectangle", "Freehand"};   
    Container cp = getContentPane();
    private int count = 0;


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


    private void initComponents() {

        cp.setBackground(Color.WHITE);

        comboBox = new JComboBox(boxOptions);
        topPanel = new JPanel();     
        bottomPanel = new JPanel(new GridLayout(1,2));  
        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));                       
        bottomPanel.setBackground(Color.LIGHT_GRAY);        

        topPanel.add(comboBox);
        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;

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

        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g2.setStroke(new BasicStroke(1));

        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(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();                       
                        addCoordinate(startX, startY);
                    }
                });

                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();                         
                    }
                });    
            }
        }
    }                 

    public static void main(String args[]) {
        new PaintProgram("Paint");
    }
}

2 个答案:

答案 0 :(得分:2)

您添加MouseListeners但不删除它们。每次在组合框中选择一些东西时,都会添加一个新的监听器。因此,当你绘制一些东西时,每个听众都会被应用,并且会发生奇怪的事情。

您应该在添加新的MouseListener之前删除它。您可能必须在实例变量中记住它。

或者,您可以在开始时添加所有侦听器,但检查侦听器内组合框的值。如果该值与侦听器的值不对应,则它应该不执行任何操作。

编辑:以下是删除所有侦听器的方法

    for (MouseListener listener : this.getMouseListeners()) {
        this.removeMouseListener(listener);
    }
    for (MouseMotionListener listener : this.getMouseMotionListeners()) {
        this.removeMouseMotionListener(listener);
    }

在actionPerformed()方法

中添加新侦听器之前,请输入此代码

答案 1 :(得分:2)

如前所述herehere,请勿在{{1​​}}中添加MouseListener,而是创建一个ActionListener并确定您的身份想要根据当前选择的项目进行。

基本上,每次调用MosueListener时都会不断添加新的MouseListener ......他们正在累积...

解决方案是使用单个actionPerformed和某种工厂......

首先定义工厂界面......

MouseListener

为您要绘制的每种类型的形状创建工厂实现...

public interface DrawFactory {

    public Draw createDrawing(int x, int y, int width, int height, Color color);
    public void addPoint(Draw draw, int x, int y);

}

接下来,创建一个从public class RectangleFactory implements DrawFactory { @Override public Draw createDrawing(int x, int y, int width, int height, Color color) { return new Rectangle(x, y, width, height); } @Override public void addPoint(Draw draw, int x, int y) { // Does nothing... } @Override public boolean isMutable() { return false; } @Override public String getName() { return "Rectangle"; } @Override public String toString() { return getName(); } } public class FreeHandFactory implements DrawFactory { @Override public Draw createDrawing(int x, int y, int width, int height, Color color) { return new FreeHand(x, y, width, height); } @Override public void addPoint(Draw draw, int x, int y) { if (draw instanceof FreeHand) { FreeHand fh = (FreeHand)draw; //fh.addPoint(x, y); } } @Override public boolean isMutable() { return true; } @Override public String getName() { return "Free Hand"; } @Override public String toString() { return getName(); } } 扩展的自定义组件,它将作为主要绘图表面,这将是可以监视JPanel和绘制MouseLstener实例的代表,就像提到here

Draw

接下来,将您的public class DrawSurface extends JPanel { private DrawFactory factory; private Draw currentDraw; private List<Draw> shapeList = new ArrayList<>(); private Color drawColor; public DrawSurface() { shapeList = new ArrayList<>(25); MouseAdapter ma = new MouseAdapter() { private Point pressPoint; @Override public void mousePressed(MouseEvent e) { pressPoint = e.getPoint(); } @Override public void mouseReleased(MouseEvent e) { DrawFactory factory = getDrawFactory(); if (factory != null) { Point p = e.getPoint(); if (factory.isMutable() && currentDraw != null) { factory.addPoint(currentDraw, p.x, p.y); } else { int x = Math.min(p.x, pressPoint.x); int y = Math.min(p.y, pressPoint.y); int width = Math.abs(p.x - pressPoint.x); int height = Math.abs(p.y - pressPoint.y); Draw draw = factory.createDrawing(x, y, width, height, getDrawColor()); shapeList.add(draw); if (factory.isMutable()) { currentDraw = draw; } } } } }; } public DrawFactory getDrawFactory() { return factory; } public void setDrawFactory(DrawFactory factory) { this.factory = factory; currentDraw = null; } public Color getDrawColor() { return drawColor; } public void setDrawColor(Color drawColor) { this.drawColor = drawColor; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); for (Draw draw : shapeList) { draw.draw(g2d); } g2d.dispose(); } public Dimension getPreferredSize() { return new Dimension(200, 200); } } boxOptions更改为String,这样可以更轻松地确定您应该使用哪个工厂。不要忘记添加对DrawFactory

的引用
DrawSurface

private final DrawFactory[] boxOptions = new DrawFactory[]{new RectangleFactory(), new FreeHandFactory()}; private DrawSurface drawSurface; 创建initComponents的新实例并将其添加到您的框架中...

DrawSurface

将您的private void initComponents() { //... drawSurface = new DrawSurface(); this.add(drawSurface); } 方法更改为......

actionPerformed

由于示例代码不完整,不确定如何确定当前颜色,但基本上,您希望同样设置@Override public void actionPerformed(ActionEvent e) { count++; drawSurface.setDrawFactory((DrawFactory)comboBox.getSelectedItem()); } 的{​​{1}}。

摆脱drawColor中的DrawSurface方法,因为您不应该覆盖顶级容器的paint方法,至少一次被告知,如果不是两次。

所有这一切都很简单,当你想添加一个新的“绘图形状”时,你为它创建一个PaintProgrampaint并将工厂添加到组合框中......完成工作......