在JPanel上绘制可移动线 [英] Drawing a movable line on a JPanel

查看:159
本文介绍了在JPanel上绘制可移动线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm writing a program which should allow the user to create a floor plan of a room - this means they can draw lines to represent walls etc. I am using a JPanel with Graphics 2D to do all the drawing stuff and currently I have a grid set as the background for the JPanel and I can draw lines based on the mouse movement(I have an enum for the mousestate with two states - DRAGGING and IDLE). However I want to add control points to the lines so that they can be moved around the JPanel once they are drawn and I can't figure out how to this. I know that I need rectangles to represent the points but I don't know how to link them to the lines so that if the points are moved, the lines are moved too. I would appreciate any help with this.

以下是JPanel类的代码:

Here is the code for the JPanel class:

 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) 
{

}
}


推荐答案

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

Why not create an ArrayList of your control points, or perhaps even better, Ellipse2D objects centered on the control points? Then you can test if the mouse is pressed in an Ellipse to determine what its behavior should be, and you could use the List of Ellipse2D objects to obtain the line end points when drawing in the paintComponent(...) method.

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

Note that your code does not compile nor run for us, and so makes it difficult for us to fully analyze, test, and modify it. For better more specific help, consider condensing your code to the smallest possible code that still compiles, runs and is able to reproduce your problem, an 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方法更改:

edit: mousePressed method change:

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

这篇关于在JPanel上绘制可移动线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆