2014-10-22 3 views
0

그래서 선을 클릭하고 드래그하려고합니다. 나는 거의 다 왔지만 사용자가 드래그하는 위치와 관련하여 선의 위치를 ​​계산하는 데 문제가 있다고 생각합니다. 클릭하고 끌면 으로 이동합니다. 이 코드에 문제가 있다고 생각합니다.JPanel에서 Line2D를 드래그하여 끌기

어떻게 작동시킬 수 있습니까? 드래그에 대한

MCVE

import java.awt.BasicStroke; 
import java.awt.Color; 
import java.awt.Cursor; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Panel; 
import java.awt.Point; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.geom.Line2D; 
import java.awt.geom.Point2D; 
import java.awt.geom.Rectangle2D; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Editor { 

    public static void main(String[] args) { 
     new Editor(); 
    } 

    public Editor() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager 
          .getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException 
         | IllegalAccessException 
         | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new UMLWindow2(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setBounds(30, 30, 1000, 700); 
       frame.getContentPane().setBackground(Color.white); 
       frame.setVisible(true); 
       frame.setLocationRelativeTo(null); 
      } 
     }); 
    } 

    public static class UMLWindow2 extends JFrame { 

     Shapes shapeList = new Shapes(); 
     Panel panel; 

     private static final long serialVersionUID = 1L; 

     public UMLWindow2() { 
      addMenus(); 
      panel = new Panel(); 
     } 

     public void addMenus() { 

      getContentPane().add(shapeList); 

      setSize(300, 200); 
      setLocationRelativeTo(null); 
      setDefaultCloseOperation(EXIT_ON_CLOSE); 

      shapeList.addLine(); 
     } 
    } 

    // Shapes class, used to draw the shapes on the panel 
    // as well as implements the MouseListener for dragging 
    public static class Shapes extends JPanel { 

     private static final long serialVersionUID = 1L; 

     private List<Line2D.Double> lines = new ArrayList<Line2D.Double>(); 
     private Line2D.Double linePath; 

     double phi = Math.toRadians(40); 
     int barb = 20; 

     Boolean hovering = false; 
     Boolean resizing = false; 

     public Shapes() { 
      MyMouseAdapter myMouseAdapter = new MyMouseAdapter(); 
      addMouseListener(myMouseAdapter); 
      addMouseMotionListener(myMouseAdapter); 
     } 

     public void addLine() { 
      linePath = new Line2D.Double(300, 300, 500, 500); 
      lines.add(linePath); 
      repaint(); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 

      Graphics2D g2 = (Graphics2D) g; 
      g2.setStroke(new BasicStroke(2)); 
      for (Line2D line : lines) { 
       g2.setColor(Color.BLACK); 
       Point sw = new Point((int) line.getX1(), (int) line.getY1()); 
       Point ne = new Point((int) line.getX2(), (int) line.getY2()); 
       g2.draw(line); 
       drawArrowHead(g2, ne, sw, Color.BLACK); 
      } 
     } 

     private void drawArrowHead(Graphics2D g2, Point tip, Point tail, 
       Color color) { 
      g2.setPaint(color); 
      double dy = tip.y - tail.y; 
      double dx = tip.x - tail.x; 
      double theta = Math.atan2(dy, dx); 
      double x, y, rho = theta + phi; 
      for (int j = 0; j < 2; j++) { 
       x = tip.x - barb * Math.cos(rho); 
       y = tip.y - barb * Math.sin(rho); 
       g2.draw(new Line2D.Double(tip.x, tip.y, x, y)); 
       rho = theta - phi; 
      } 
     } 

     class MyMouseAdapter extends MouseAdapter { 
      int currentIndex; 
      Point2D.Double startPoint = new Point2D.Double(); 
      Point2D.Double endPoint = new Point2D.Double(); 

      @Override 
      public void mousePressed(MouseEvent e) { 
       Point p = e.getPoint(); 
       if (hovering) { 
        System.out.println("Starting to resize"); 
        startPoint.x = p.x; 
        startPoint.y = p.y; 
        resizing = true; 
       } 
      } 

      @Override 
      public void mouseDragged(MouseEvent e) { 
       Point p = e.getPoint(); 
       if (resizing) { 
        endPoint.x = p.x; 
        endPoint.y = p.y; 
        double offsetX = endPoint.x - startPoint.x; 
        double offsetY = endPoint.y - startPoint.y; 
        System.out.println("Point 1: " 
          + lines.get(currentIndex).getX1() + ", " 
          + lines.get(currentIndex).getY1() + " Point 2: " 
          + lines.get(currentIndex).getX2() + ", " 
          + lines.get(currentIndex).getY2()); 
        int newX1 = (int) (lines.get(currentIndex).getX1() + offsetX); 
        int newX2 = (int) (lines.get(currentIndex).getX2() + offsetX); 
        int newY1 = (int) (lines.get(currentIndex).getY1() + offsetY); 
        int newY2 = (int) (lines.get(currentIndex).getY2() + offsetY); 

        lines.get(currentIndex).setLine(newX1, newY1, newX2, newY2); 

        repaint(); 
       } 
      } 

      @Override 
      public void mouseReleased(MouseEvent e) { 
       if (resizing) { 
        System.out.println("Done resizing"); 
        resizing = false; 
       } 
      } 

      @Override 
      public void mouseMoved(MouseEvent e) { 
       Point p = e.getPoint(); 
       Rectangle2D.Double rect = new Rectangle2D.Double(p.x - 1, 
         p.y - 1, 3, 3); 
       for (int i = 0; i < lines.size(); i++) { 
        Line2D line = lines.get(i); 
        if (line.intersects(rect)) { 
         setCursor(new Cursor(Cursor.HAND_CURSOR)); 
         currentIndex = i; 
         hovering = true; 
        } else { 
         setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 
         hovering = false; 
        } 
       } 
      } 

     } 

    } 
} 

답변

2
이 도움이 또는 혼동한다면 나도 몰라

,하지만 한 가지 방법은 모든 구성 요소를 드래그 할 수있는 사용자 정의 클래스를 만드는 것입니다. 다음 문제는 다른 모양의 구성 요소를 만드는 것입니다.

당신은 체크 아웃으로 시작할 수 있습니다

  1. Playing With Shapes입니다. 이 클래스를 사용하면 Shape의 맞춤 구성 요소를 만들 수 있습니다. 구형 경계는 아니고, Shape의 실제 경계는 구성 요소에 의해 존중되어 마우스 이벤트를 처리하기 쉽습니다.

  2. Component Mover. 이 클래스를 사용하면 구성 요소를 ComponentMover에 등록하기 만하면 구성 요소를 드래그 할 수 있습니다.

다음 예제 코드는이 두 클래스를 보여줍니다. 동봉 된 모양 (원형, 사각형, 별)을 만드는 것은 상대적으로 쉽습니다. 화살촉을 만드는 것은 더욱 어렵습니다. 나는 그것을 두 가지 방법으로 시도했다.

처음에는 GeneralPath을 사용했습니다. 코드는 쉽지만 GeneralPath가 시작점/끝점을 닫아서 삼각형을 만드는 것처럼 보이기 때문에 Shape.contains (...) 메서드가 예상대로 작동하지 않았습니다. 페인팅은 괜찮지 만 삼각형의 아무 곳이나 클릭하면 화살표가 움직이기 때문에 움직이지 않는 것이 좋습니다.

두 번째 시도는 약간 다른 크기의 두 개의 다른 삼각형을 만든 다음 더 큰 삼각형의 영역을 빼서 화살표의 윤곽을 남기고 더 복잡한 모양을 만드는 것입니다. 이 경우 Shape.contains (..) 메서드가 예상대로 작동하므로 끌기도 예상대로 작동합니다.

코드와 재미 유무 :

import java.awt.*; 
import java.awt.event.*; 
import java.awt.geom.*; 
import javax.swing.*; 
import javax.swing.border.*; 

public class ShapeComponentTest 
{ 
    private static void createAndShowUI() 
    { 
     Border line = new LineBorder(Color.BLUE, 5); 

     Polygon outer = new Polygon(); 
     outer.addPoint(0, 50); 
     outer.addPoint(50, 25); 
     outer.addPoint(0, 0); 
     Polygon inner = new Polygon(); 
     inner.addPoint(0, 45); 
     inner.addPoint(43, 25); 
     inner.addPoint(0, 5); 

     Area arrow = new Area(outer); 
     arrow.subtract(new Area(inner)); 

     GeneralPath part1 = new GeneralPath(); 
     part1.moveTo(0, 50); 
     part1.lineTo(50, 25); 
     part1.lineTo(0, 0); 

     ShapeComponent ball = new ShapeComponent(arrow); // drags correctly 
//  OutlineComponent ball = new OutlineComponent(part1, 3); // drags incorrectly 
     ball.setForeground(Color.ORANGE); 
     ball.setBorder(line); 
     ball.setSize(ball.getPreferredSize()); 

     OutlineComponent square = new OutlineComponent(new Rectangle(30, 30)); 
     square.setForeground(Color.ORANGE); 
     square.setLocation(50, 50); 
     square.setBorder(line); 
     square.setSize(square.getPreferredSize()); 

     OutlineComponent star = new OutlineComponent(ShapeUtils.radiusShape(16, 20, 8)); 

     star.setForeground(Color.ORANGE); 
     star.setLocation(100, 100); 
     star.setBorder(line); 
     star.setSize(star.getPreferredSize()); 

     ComponentMover cm = new ComponentMover(); 
     cm.registerComponent(star); 
     cm.registerComponent(ball); 
     cm.registerComponent(square); 

     JPanel panel = new JPanel(); 
     panel.setLayout(null); 
     panel.add(ball); 
     panel.add(square); 
     panel.add(star); 

     JFrame frame = new JFrame(); frame.add(panel); 
     frame.setSize(200, 200); frame.setVisible(true); 

     MouseListener ml = new MouseAdapter() 
     { 
      public void mouseClicked(MouseEvent e) 
      { 
       System.out.println("clicked "); 
      } 
     }; 

     ball.addMouseListener(ml); 
     square.addMouseListener(ml); 
     star.addMouseListener(ml); 
    } 

    public static void main(String[] args) 
    { 
     EventQueue.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 
+0

실제로 이미 둘러싸인 도형을 드래그 구현 방법이있다. 하지만 선에 문제가 있습니다. 그럼에도 불구하고 코드를 확인하고 내가 사용할 수있는 것을 확인하겠습니다. 대답을 많이 주셔서 고맙습니다. – Harry

+0

@Harry, '클릭하고 끌면 아무 것도 끌 수없는 방식으로 움직입니다.' 두 줄의 교차 부분에 마우스를 가져 가면 커서가 "손"으로 바뀌는 것을 볼 수 있지만 아무 것도 움직일 수 없습니다. 게시 된 코드가 컴파일되지 않았습니다. 'new Editor()'를'new EditorDrag()'로 변경해야했습니다. – camickr

+0

그건 내가 바보 같아서 잘못된 코드를 게시했기 때문입니다. 그것을 지적 주셔서 감사합니다. 업데이트 된 코드를 확인하면 올바르게 드래그되지 않는 것을 볼 수 있습니다 (그러나 드래그 앤 컴파일 ... lol) – Harry