简体   繁体   English

在Jpanel上绘制多个形状时的Ambiquity

[英]Ambiquity while drawing multiple shapes on Jpanel

Th code below has few problems : 下面的代码几乎没有问题:

1) The polygon joins last and first point itself, should not do itself but user should draw it. 1)多边形连接最后和第一个点本身,不应该自己做,但用户应该绘制它。

2) The polygons lines disappeared after clicking on other shapes. 2)点击其他形状后,多边形线消失。

package Circles;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;

import javax.swing.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;

//////////////////////////////////////////////////////////////PaintDemo
class PaintDemo2 {
 //============================================================= main
 public static void main(String[] args) {
     PaintWindow2 window = new PaintWindow2();
     window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     window.setVisible(true);
 }//end main
}//endclass PaintDemo


@SuppressWarnings("serial")
////////////////////////////////////////////////////////////PaintWindow
class PaintWindow2 extends JFrame {
 PaintPanel2 canvas = new PaintPanel2();
 //====================================================== constructor
 public PaintWindow2() {
     //--- create the buttons
     JButton circleButton = new JButton("Circle");
     circleButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
             canvas.setShape(PaintPanel2.CIRCLE);
         }});
     JButton rectangleButton = new JButton("Rectangle");
     rectangleButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
             canvas.setShape(PaintPanel2.Ellipse);
         }});

     JButton polyButton = new JButton("Polygon");
     polyButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
             canvas.setShape(PaintPanel2.POLY);
         }});

     //--- layout the buttons
     JPanel buttonPanel = new JPanel();
     buttonPanel.setLayout(new GridLayout(2, 1));
     buttonPanel.add(circleButton);
     buttonPanel.add(rectangleButton);
     buttonPanel.add(polyButton);

     //--- layout the window
     Container content = this.getContentPane();
     content.setLayout(new BorderLayout());
     content.add(buttonPanel, BorderLayout.WEST);
     content.add(canvas     , BorderLayout.CENTER);
     this.setTitle("Paint Demo");
     this.pack();
 }//end constructor
}//endclass PaintWindow


///////////////////////////////////////////////////////////// PaintPanel2
@SuppressWarnings("serial")
class PaintPanel2 extends JPanel implements MouseListener, 
                                        MouseMotionListener {
 //--- Public constants used to specify shape being drawn.          
 public static final int NONE      = 0;
 public static final int LINE      = 1;
 public static final int Ellipse = 2;
 public static final int CIRCLE    = 3;
 public static final int POLY    = 4;

 //--- Variables to store the current figure info
 private int _shape = NONE;
 public int getShape() {
    return _shape;
}

 private int _currentStartX = 0;  // where mouse first pressed
 private int _currentStartY = 0;
 private int _currentEndX   = 0;  // where dragged to or released
 private int _currentEndY   = 0;

 //--- BufferedImage to store the underlying saved painting.
 //    Will be initialized first time paintComponent is called.
 private BufferedImage _bufImage = null;
 private boolean polygonIsNowComplete = false;

 //--- Private constant for size of paint area.
 private static final int SIZE = 600; // size of paint area

 private final Point trackPoint = new Point();
 private Path2D currentShape;
 private ArrayList<Path2D> lstPloys  = new ArrayList<Path2D>();;
 private Point lastPoint;
 private Point currentPoint;
 @SuppressWarnings("rawtypes")
private ArrayList points = new ArrayList();


 //====================================================== constructor
 public PaintPanel2() {
     setPreferredSize(new Dimension(SIZE, SIZE));
     setBackground(Color.white);
     //--- Add the mouse listeners.
     this.addMouseListener(this); 
     this.addMouseMotionListener(this);
 }//endconstructor


 //========================================================= setShape
 public void setShape(int shape) {
     //--- Provided so users can set the shape.
     _shape = shape;
 }//end setShape


 //=================================================== paintComponent
 public void paintComponent(Graphics g) {
     super.paintComponent(g);

     Graphics2D g2 = (Graphics2D)g;  // downcast to Graphics2D
     if (_bufImage == null) {
         //--- This is the first time, initialize _bufImage
         int w = this.getWidth();
         int h = this.getHeight();
         _bufImage = (BufferedImage)this.createImage(w, h);
         Graphics2D gc = _bufImage.createGraphics();
         gc.setColor(Color.white);
         gc.fillRect(0, 0, w, h); // fill in background
     }
     g2.drawImage(_bufImage, null, 0, 0);  // draw previous shapes

     drawCurrentShape(g2);
 }//end paintComponent


 //================================================= drawCurrentShape
 private void drawCurrentShape(Graphics2D g2) {
     //--- Draws current shape on a graphics context, either
     //    on the context passed to paintComponent, or the
     //    context for the BufferedImage.
     switch (_shape) {
         case NONE  :
                  break;

         case CIRCLE:
                  g2.drawOval(_currentStartX, _currentStartY,
                              _currentEndX - _currentStartX, 
                              _currentEndY - _currentStartY);
                  break;

         case Ellipse:
                  g2.draw(new Ellipse2D.Double(_currentStartX, _currentStartY,
                          _currentEndX - _currentStartX, 
                          _currentEndY - _currentStartY));
                  break;

         case POLY:

                drawPolyGon(g2);
                break;

         default:  // should never happen
                  g2.drawString("Huh?", 10, 20);
                  break;
     }
 }//end paintComponent



private void drawPolyGon(Graphics2D g2) {

    g2.create();
    if (lastPoint != null) {
         g2.setColor(Color.RED);
         g2.fillOval(lastPoint.x - 2, lastPoint.y - 2, 4, 4);
    }
    if (currentShape != null) {
         g2.setColor(Color.RED);
         g2.draw(currentShape);
         if (lastPoint != null && currentPoint != null) {
              g2.setColor(new Color(255, 0, 0, 64));
              g2.draw(new Line2D.Float(lastPoint, currentPoint));

         }
    }
    g2.setColor(Color.BLACK);
    for (Path2D shape : lstPloys) {
         g2.draw(shape);
    }
    g2.dispose();

    // TODO Auto-generated method stub

}


//===================================================== mousePressed
 public void mousePressed(MouseEvent e) {
    _currentStartX = e.getX(); // save x coordinate of the click
    _currentStartY = e.getY(); // save y
    _currentEndX   = _currentStartX;   // set end to same pixel
    _currentEndY   = _currentStartY;
 }//end mousePressed

 //===================================================== mouseDragged
 public void mouseDragged(MouseEvent e) {

  _currentEndX = e.getX();   // save new x and y coordinates
    _currentEndY = e.getY();
     this.repaint(); 
     // show new shape
 }//end mouseDragged

 //==================================================== mouseReleased
 public void mouseReleased(MouseEvent e) {
     // This will save the shape that has been dragged by
     // drawing it onto the bufferedImage where all shapes
     // are written.
    _currentEndX = e.getX(); // save ending coordinates
     _currentEndY = e.getY();

     //--- Draw the current shape onto the buffered image.
     Graphics2D grafarea = _bufImage.createGraphics();
     drawCurrentShape(grafarea);

     this.repaint();
 }//end mouseReleased


 public void mouseMoved   (MouseEvent e) {

     if (currentShape != null) {
          currentPoint = e.getPoint();
          repaint();
     } else {
          currentPoint = null;
     }


 }
 public void mouseEntered (MouseEvent e) {}
 public void mouseExited  (MouseEvent e) {}
public void mouseClicked (MouseEvent e) {
     if (e.getButton() == MouseEvent.BUTTON1) {
         if (e.getClickCount() == 1) {
              Point p = e.getPoint();
              lastPoint = p;
              if (currentShape == null) {
                   currentShape = new Path2D.Float();
                   currentShape.moveTo(p.x, p.y);
              } else {
                   currentShape.lineTo(p.x, p.y);
              }
              repaint();
         } else if (e.getClickCount() == 2) {
              currentShape.closePath();
              lstPloys.add(currentShape);
              currentShape = null;
              lastPoint = null;
              repaint();
         }
    }


 }
}

Paint cycles are stateless, that is, the contents of the graphics are not passed from one cycle to another. 绘制周期是无状态的,也就是说,图形的内容不会从一个周期传递到另一个周期。

You are required to re-paint the entire contents of component on each paint cycles. 您需要在每个喷涂周期上重新绘制组件的全部内容。

You've attempt to implement a double buffer solution, but instead of passing the graphs context of the buffer, you've passed the graphics contents supplied to you by the paint system. 您已尝试实现双缓冲区解决方案,但您没有传递缓冲区的图形上下文,而是传递了绘制系统提供给您的图形内容。 If you passed the graphs context of the buffer to the drawCurrentShape method, it might solve your problem (and eliminate the need to cache all the shapes) 如果您将缓冲区的图形上下文传递给drawCurrentShape方法,它可能会解决您的问题(并且无需缓存所有形状)

UPDATED 更新

So, in your paintComponent method of your PaintPanel2 component, you are creating a BufferedImage , but you are not painting the components to it... 因此,在PaintPanel2组件的paintComponent方法中,您正在创建一个BufferedImage ,但是您没有将组件绘制到它...

public void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2 = (Graphics2D)g;  // downcast to Graphics2D
    if (_bufImage == null) {
        //--- This is the first time, initialize _bufImage
        int w = this.getWidth();
        int h = this.getHeight();
        _bufImage = (BufferedImage)this.createImage(w, h);
        Graphics2D gc = _bufImage.createGraphics();
        gc.setColor(Color.white);
        gc.fillRect(0, 0, w, h); // fill in background
    }
    g2.drawImage(_bufImage, null, 0, 0);  // draw previous shapes

    drawCurrentShape(g2);
}//end paintComponent

Instead, you should use the graphics context from the buffered image to drawCurrentShape 相反,您应该使用缓冲图像中的图形上下文来drawCurrentShape

public void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2 = (Graphics2D)g;  // downcast to Graphics2D
    Graphics2D gc = null;
    if (_bufImage == null) {
        //--- This is the first time, initialize _bufImage
        int w = this.getWidth();
        int h = this.getHeight();
        _bufImage = (BufferedImage)this.createImage(w, h);
        gc = _bufImage.createGraphics();
        gc.setColor(Color.white);
        gc.fillRect(0, 0, w, h); // fill in background
    } else {
        gc = _bufImage.createGraphics();
    }
    drawCurrentShape(g2);
    gc.dispose();

    g2.drawImage(_bufImage, null, 0, 0);  // draw previous shapes
}//end paintComponent

It should be noted that this might create some other issues, but the concept is sound. 应该指出的是,这可能会产生一些其他问题,但这个概念是合理的。

Personally, I prefer to keep a List of all the shapes and repaint them. 就个人而言,我更喜欢保留所有形状的List并重新绘制它们。 This gives you the ability to select, move, delete, re-order and change all the shapes within the program, as well as provide a type of history ;) 这使您能够选择,移动,删除,重新排序和更改程序中的所有形状,并提供一种历史记录;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM