在JPanel上绘制可移动线

时间:2013-01-29 14:53:28

标签: java swing jpanel line graphics2d

我正在编写一个程序,允许用户创建房间的平面图 - 这意味着他们可以绘制线条来代表墙壁等。我正在使用带有Graphics 2D的JPanel来完成所有绘图工作,目前我有一个网格设置作为JPanel的背景,我可以根据鼠标移动绘制线条(我有一个枚举鼠标状态有两种状态 - DRAGGING和IDLE)。但是我想在线上添加控制点,这样一旦它们被绘制就可以在JPanel周围移动它们,我无法弄清楚如何做到这一点。我知道我需要矩形来表示点,但我不知道如何将它们链接到线上,这样如果移动点,线也会移动。我很感激任何帮助。

以下是JPanel类的代码:

 package floorplan;

 /**
 *
 * @author xodkx
 */

 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.awt.image.BufferedImage;
 import java.awt.event.MouseListener;

 public class Floor extends JPanel implements MouseListener, MouseMotionListener
 {


 private static final int WIDTH = Integer.parseInt(JOptionPane.showInputDialog("Please 
                                  enter the width of your room"));
 private static final int LENGTH = Integer.parseInt(JOptionPane.showInputDialog("Please       
                                  enter the width of your room"));
 private static final Color BACKGROUND = Color.WHITE;
 private static final Color INITIAL_COLOUR = Color.BLACK;
 private static final Framework INITIAL_FRAMEWORK = Framework.WALL;  

 private MouseState state = MouseState.IDLE;
 private Framework frameworkType = INITIAL_FRAMEWORK; 
 private Color colour = INITIAL_COLOUR;


 private Point start = null;
 private Point end = null;
 private Rectangle startpt = new Rectangle(0, 0, 8, 8);// Start control point
 private Rectangle endpt = new Rectangle(0, 0, 8, 8);// End control point

 private BufferedImage bufImage = null;


 public Floor()
  {
      setPreferredSize(new Dimension(LENGTH,WIDTH));
      setBackground(Color.white);
      setBorder(BorderFactory.createLineBorder (Color.black, 5));

      this.addMouseListener(this);
      this.addMouseMotionListener(this);

  }

    public void setColor(Color color)
  {
      colour = color;

  }  

   public void setFramework(Framework framework)
  {
      frameworkType = framework;
  }  

@Override
 public void paintComponent(Graphics g)
  {
     super.paintComponent(g);
     Graphics2D g2 = (Graphics2D)g;
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                          RenderingHints.VALUE_ANTIALIAS_ON);

      if(bufImage == null)
      {
          int h = this.getHeight();
          int w = this.getWidth();
          bufImage = (BufferedImage)this.createImage(h,w);
          Graphics2D gc = bufImage.createGraphics(); 
          gc.setColor(BACKGROUND);   
          gc.fillRect(0, 0, w, h);
      }


      g2.drawImage(bufImage,null,0,0);

      drawGrid(g2);

      if(state == MouseState.DRAGGING)
      {
          createComponent(g2);
      }
  }

public void drawGrid(Graphics g2)// sets a grid as the background of the JPanel
{
     int gridDivisions = 20;
     int divisionSize = WIDTH/gridDivisions;
     int grid = WIDTH*LENGTH;

     g2.setColor(Color.lightGray);

     for(int i=1; i<grid; i++)
    {
        int x = i * divisionSize;
        g2.drawLine(x,0,x,getSize().height);
    }

     for(int i=1; i<grid; i++)
    {  
       int y = i*divisionSize;
       g2.drawLine(0,y,getSize().width,y);
    }
}


  public void createComponent(Graphics2D g2)// method that draws the lines for various  
                                                components of the room
  {
      g2.setColor(colour);

      switch (frameworkType)
      { 
          case WALL:
            g2.setStroke(new BasicStroke(5));
            g2.drawLine(start.x, start.y, end.x,end.y);
            break;

          case DOOR:
            g2.setStroke(new BasicStroke(5));
            g2.drawLine(start.x, start.y, end.x,end.y);
            break;

          case WINDOW:
            g2.setStroke(new BasicStroke(5));
            g2.drawLine(start.x, start.y, end.x,end.y);
            break;


          default:
          g2.drawString("test", 10, 20);
          break;   
      }        
  }


@Override
public void mousePressed(MouseEvent e) 
{
     state = MouseState.DRAGGING;
     start = e.getPoint();
     end = start;
}

@Override

public void mouseDragged(MouseEvent e) 
{

    state = MouseState.DRAGGING;
    end = e.getPoint();
    this.repaint();

}

@Override
public void mouseReleased(MouseEvent e) 
{
    end = e.getPoint();
    if(state == MouseState.DRAGGING)
    {
       state = MouseState.IDLE;
       createComponent(bufImage.createGraphics());
       this.repaint();
    } 
}


 @Override
public void mouseClicked(MouseEvent e) 
{

}

@Override
public void mouseEntered(MouseEvent e) 
{

}

@Override
public void mouseExited(MouseEvent e) 
{

}



@Override
public void mouseMoved(MouseEvent e) 
{

}
}

1 个答案:

答案 0 :(得分:11)

为什么不创建控制点的ArrayList,或者更好的是,Ellipse2D对象以控制点为中心?然后,您可以测试是否在椭圆中按下鼠标以确定其行为应该是什么,并且您可以使用List of Ellipse2D对象在使用paintComponent(...)方法绘制时获取行结束点。

请注意,您的代码不会为我们编译或运行,因此我们很难对其进行全面分析,测试和修改。要获得更具体的帮助,请考虑将代码压缩到仍然编译,运行并能够重现问题的最小代码sscce

例如:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;

@SuppressWarnings("serial")
public class Floor2 extends JPanel {
   private static final Color BACKGROUND = new Color(0, 0, 0, 0);
   private static final Color INITIAL_COLOUR = Color.BLACK;
   private static final int BORDER_WIDTH = 5;
   private static final Color LINE_DRAWING_COLOR = new Color(200, 200, 255);
   private static final Color LINE_COLOR = Color.blue;
   private static final Stroke DRAWING_LINE_STROKE = new BasicStroke((float)BORDER_WIDTH);
   public static final int ELLIPSE_DIAMETER = 10;
   private MouseState mouseState = MouseState.IDLE;
   private BufferedImage bufImage = null;
   private int width;
   private int height;
   private int gridDivisions;
   private List<List<Ellipse2D>> ellipseList = new ArrayList<List<Ellipse2D>>();
   private Line2D drawingLine = null;

   public enum MouseState {
      IDLE, DRAGGING
   }

   public Floor2(int width, int height, int gridDivisions) {
      this.width = width;
      this.height = height;
      this.gridDivisions = gridDivisions;
      setBackground(Color.white);
      setBorder(BorderFactory.createLineBorder(Color.black, BORDER_WIDTH));

      MyMouseAdapter mouseAdapter = new MyMouseAdapter();
      addMouseListener(mouseAdapter);
      addMouseMotionListener(mouseAdapter);
   }

   private static void createAndShowGui() {
      int w = 600;
      int h = w;
      int gridDiv = 20;
      Floor2 mainPanel = new Floor2(w, h, gridDiv);

      JFrame frame = new JFrame("Floor2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(width, height);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (bufImage == null) {
         bufImage = createGridImage();
      }

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

      Stroke initStroke = g2.getStroke();
      g2.setStroke(DRAWING_LINE_STROKE);
      if (mouseState == MouseState.DRAGGING && drawingLine != null) {
         g2.setColor(LINE_DRAWING_COLOR);
         g2.draw(drawingLine);
      }

      g2.setColor(LINE_COLOR);
      for (List<Ellipse2D> ellipses : ellipseList) {
         Point2D p2d1 = new Point2D.Double(ellipses.get(0).getCenterX(), ellipses.get(0).getCenterY());
         Point2D p2d2 = new Point2D.Double(ellipses.get(1).getCenterX(), ellipses.get(1).getCenterY());
         Line2D line = new Line2D.Double(p2d1, p2d2);
         g2.draw(line);
      }

      g.drawImage(bufImage, 0, 0, this);
      g2.setStroke(initStroke);
   }

   private BufferedImage createGridImage() {
      BufferedImage gridImage = new BufferedImage(width, height,
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = gridImage.createGraphics();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setBackground(BACKGROUND);
      g2.clearRect(0, 0, width, height);

      int divisionSize = width / gridDivisions;
      int grid = width * height;
      g2.setColor(Color.lightGray);
      for (int i = 1; i < grid; i++) {
         int x = i * divisionSize;
         g2.drawLine(x, 0, x, getSize().height);
      }
      for (int i = 1; i < grid; i++) {
         int y = i * divisionSize;
         g2.drawLine(0, y, getSize().width, y);
      }

      g2.dispose();
      return gridImage;
   }

   private class MyMouseAdapter extends MouseAdapter {
      private Point p1;

      @Override
      public void mousePressed(MouseEvent e) {
         if (e.getButton() != MouseEvent.BUTTON1) {
            return;
         }

         for (List<Ellipse2D> endPts : ellipseList) {
            // check if one of the ellipses has been selected
            // if so, remove it from elipseList
            // set drawingLine == to end points
            // setdragging = true
            // repaint
            // return
         }
         mouseState = MouseState.DRAGGING;
         p1 = e.getPoint();
      }

      @Override
      public void mouseDragged(MouseEvent e) {
         if (mouseState != MouseState.DRAGGING) {
            return;
         }
         drawingLine = new Line2D.Double(p1, e.getPoint());
         repaint();
      }

      @Override
      public void mouseReleased(MouseEvent e) {
         if (drawingLine != null) {
            List<Ellipse2D> newEndPoints = new ArrayList<Ellipse2D>();

            double x1 = drawingLine.getX1() - ELLIPSE_DIAMETER / 2;
            double y1 = drawingLine.getY1() - ELLIPSE_DIAMETER / 2;
            Ellipse2D ellipse1 = new Ellipse2D.Double(x1, y1, ELLIPSE_DIAMETER, ELLIPSE_DIAMETER);
            x1 = drawingLine.getX2() - ELLIPSE_DIAMETER / 2;
            y1 = drawingLine.getY2() - ELLIPSE_DIAMETER / 2;
            Ellipse2D ellipse2 = new Ellipse2D.Double(x1, y1, ELLIPSE_DIAMETER, ELLIPSE_DIAMETER);
            newEndPoints.add(ellipse1);
            newEndPoints.add(ellipse2);
            ellipseList.add(newEndPoints);
            repaint();
         }

         mouseState = MouseState.IDLE;
         drawingLine = null;
      }
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

编辑:mousePressed方法更改:

private class MyMouseAdapter extends MouseAdapter {
  private Point2D p1;

  @Override
  public void mousePressed(MouseEvent e) {
     if (e.getButton() != MouseEvent.BUTTON1) {
        return;
     }

     for (List<Ellipse2D> endPts : ellipseList) {
        for (int i = 0; i < endPts.size(); i++) {
           Ellipse2D endPt = endPts.get(i);
           if (endPt.contains(e.getPoint())) {
              Ellipse2D endPt2 = endPts.get(Math.abs(i - 1));
              ellipseList.remove(endPts);

              Point2D p2 = new Point2D.Double(endPt.getCenterX(), endPt.getCenterY());
              p1 = new Point2D.Double(endPt2.getCenterX(), endPt2.getCenterY());
              drawingLine = new Line2D.Double(p1, p2);
              mouseState = MouseState.DRAGGING;
              repaint();
              return;
           }
        }
     }
     mouseState = MouseState.DRAGGING;
     p1 = e.getPoint();
  }

  @Override
  public void mouseDragged(MouseEvent e) {
     if (mouseState != MouseState.DRAGGING) {
        return;
     }
     drawingLine = new Line2D.Double(p1, e.getPoint());
     repaint();
  }

  @Override
  public void mouseReleased(MouseEvent e) {
     if (drawingLine != null) {
        List<Ellipse2D> newEndPoints = new ArrayList<Ellipse2D>();

        double x1 = drawingLine.getX1() - ELLIPSE_DIAMETER / 2;
        double y1 = drawingLine.getY1() - ELLIPSE_DIAMETER / 2;
        Ellipse2D ellipse1 = new Ellipse2D.Double(x1, y1, ELLIPSE_DIAMETER, ELLIPSE_DIAMETER);
        x1 = drawingLine.getX2() - ELLIPSE_DIAMETER / 2;
        y1 = drawingLine.getY2() - ELLIPSE_DIAMETER / 2;
        Ellipse2D ellipse2 = new Ellipse2D.Double(x1, y1, ELLIPSE_DIAMETER, ELLIPSE_DIAMETER);
        newEndPoints.add(ellipse1);
        newEndPoints.add(ellipse2);
        ellipseList.add(newEndPoints);
        repaint();
     }

     mouseState = MouseState.IDLE;
     drawingLine = null;
  }
}