2013-04-05 2 views
3

마우스 클릭 후 나타나는 draggable cross가있는 JPanel을 만들려고합니다. 모든 것은 잘 작동하지만 JPanel의 크기를 조정할 때 십자가가 사라집니다. 내 JPanel의 paintComponent 메소드를 오버라이드하려고 시도했지만 모든 십자 기호는 좌표 (0,0)에있다. 어떻게 해결할 수 있습니까?JPanel 크기를 조정하면 구성 요소가 사라집니다.

import java.awt.*; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.event.MouseMotionAdapter; 
import java.util.ArrayList; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class CrossPanel extends JPanel implements MouseListener { 

private int orderOfCross = 0; 
private ArrayList<Cross> crosses; 
private int defaultSizeOfCrosses = 10; 

CrossPanel() { 
    setOpaque(false); 
    addMouseListener(this); 
    crosses = new ArrayList<Cross>(); 
} 

@Override 
public void mouseClicked(MouseEvent e) { 
    int x = e.getX(); 
    int y = e.getY(); 
    Cross cross = new Cross(orderOfCross++, defaultSizeOfCrosses); 
    crosses.add(cross); 
    cross.setLocation(x - defaultSizeOfCrosses, y - defaultSizeOfCrosses); 
    add(cross); 
    repaint(); 
} 

@Override 
public void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    //  for (int i = 0; i < crosses.size(); i++) { 
    //   crosses.get(i).paint(g); 
    //  } 
} 

@Override 
public void mousePressed(MouseEvent e) {} 

@Override 
public void mouseReleased(MouseEvent e) {} 

@Override 
public void mouseEntered(MouseEvent e) {} 

@Override 
public void mouseExited(MouseEvent e) {} 

public static void main(String[] args) { 
    JFrame f = new JFrame(); 
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    CrossPanel crossPane = new CrossPanel(); 
    f.getContentPane().add(crossPane); 
    f.setSize(600, 500); 
    f.setLocation(200, 200); 
    f.setVisible(true); 
} 
} 

class Cross extends JComponent { 

private int order; 
protected Cursor draggingCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); 
private volatile int draggedAtX, draggedAtY; 
int size; 

public Cross(int order, int size) { 
    this.order = order; 
    this.size = size; 
    this.setBounds(0, 0, 4 * size, 3 * size + 10); 
    addDragListeners(); 
    setCursor(draggingCursor); 
} 

@Override 
protected void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    Graphics2D g2 = (Graphics2D) g; 
    g2.setColor(Color.red); 
    g2.setStroke(new BasicStroke(3)); 
    g2.drawLine(0, size, size + size, size); 
    g2.drawLine(size, 0, size, size + size); 
    Font f = new Font("Monospaced", Font.BOLD, size + 10); 
    g2.setFont(f); 
    g2.drawString(String.valueOf(order), size - size/2, 3 * size + 10); 
} 

private void addDragListeners() { 
    addMouseListener(new MouseAdapter() { 
     @Override 
     public void mousePressed(MouseEvent e) { 
      draggedAtX = e.getX(); 
      draggedAtY = e.getY(); 
     } 
    }); 
    addMouseMotionListener(new MouseMotionAdapter() { 
     @Override 
     public void mouseDragged(MouseEvent e) { 
      Point newLocation = new Point(e.getX() - draggedAtX + getLocation().x, e.getY() - draggedAtY + getLocation().y); 
      setLocation(newLocation); 
     } 
    }); 
} 
} 

답변

6

나는 매우 거의 모든 인식 혜택에 대한 null 레이아웃의 사용을 볼 수 없습니다 많은 무승부 뒤 단순히있다.

전체 Swing API는 레이아웃 관리자를 사용하도록 설계되었으므로 미쳐서 (IMHO) 간단하게 모든 문제를 해결할 수 있습니다.

사용 가능한 레이아웃 관리자가 원하는대로하지 않는 위치에 있으면 자신을 쓰는 것이 더 가치가있을 수 있습니다.

여기서, PropertionalLayoutManager은 부모 구성 요소의 너비/높이의 백분율을 기준으로 컨테이너에 구성 요소를 배치하는 레이아웃 기능을 제공하기위한 것입니다. 즉, 부모 구성 요소의 크기가 조정됨에 따라 하위 구성 요소의 크기가 부모 크기의 비율로 변경됩니다.

enter image description hereenter image description here 몇 가지 측면 노트에

import java.awt.BasicStroke; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.Container; 
import java.awt.Cursor; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.FontMetrics; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.LayoutManager2; 
import java.awt.Point; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.event.MouseMotionAdapter; 
import java.text.NumberFormat; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Map; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class CrossPanel extends JPanel implements MouseListener { 

    private int orderOfCross = 0; 
    private ArrayList<Cross> crosses; 
    private int defaultSizeOfCrosses = 10; 

    CrossPanel() { 
     setOpaque(false); 
     addMouseListener(this); 
     crosses = new ArrayList<Cross>(); 
     setLayout(new PropertionalLayoutManager()); 
    } 

    @Override 
    public void mouseClicked(MouseEvent e) { 
     int x = e.getX(); 
     int y = e.getY(); 
     Cross cross = new Cross(orderOfCross++, defaultSizeOfCrosses); 

     float xPos = (float)x/(float)getWidth(); 
     float yPos = (float)y/(float)getHeight(); 

     crosses.add(cross); 

     add(cross, new PropertionalConstraints(xPos, yPos)); 
     revalidate(); 
    } 

    public static String format(float value) { 
     return NumberFormat.getNumberInstance().format(value); 
    } 

    @Override 
    public void mousePressed(MouseEvent e) { 
    } 

    @Override 
    public void mouseReleased(MouseEvent e) { 
    } 

    @Override 
    public void mouseEntered(MouseEvent e) { 
    } 

    @Override 
    public void mouseExited(MouseEvent e) { 
    } 

    public static void main(String[] args) { 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     CrossPanel crossPane = new CrossPanel(); 
     f.getContentPane().add(crossPane); 
     f.setSize(600, 500); 
     f.setLocation(200, 200); 
     f.setVisible(true); 
    } 

    public class Cross extends JComponent { 

     private int order; 
     protected Cursor draggingCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); 
     private volatile int draggedAtX, draggedAtY; 
     int size; 

     public Cross(int order, int size) { 
      this.order = order; 
      this.size = size; 
//   this.setBounds(0, 0, 4 * size, 3 * size + 10); 
      addDragListeners(); 
      setCursor(draggingCursor); 
      Font f = new Font("Monospaced", Font.BOLD, size + 10); 
      setFont(f); 

     } 

     @Override 
     public Dimension getPreferredSize() { 
      // This is dangrous, you are making assumptions about platforms 
      // that you have no eviednce to support. 
      FontMetrics fm = getFontMetrics(getFont()); 
      return new Dimension(Math.max(fm.stringWidth(String.valueOf(order)), size), size + fm.getHeight()); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2 = (Graphics2D) g; 
      g2.setColor(Color.red); 
      g2.setStroke(new BasicStroke(3)); 

      FontMetrics fm = g2.getFontMetrics(); 

      int width = getWidth() - 1; 
      int height = getHeight() - 1; 

      int x = (width - fm.stringWidth(String.valueOf(order)))/2; 
      int y = fm.getAscent(); 
      g2.drawString(String.valueOf(order), x, y); 

      int crossSize = Math.min(width, height - fm.getHeight()); 
      x = (width - crossSize)/2; 
      y = fm.getHeight(); 
      g2.drawLine(x, y, x + crossSize, y + crossSize); 
      g2.drawLine(x + crossSize, y, x, y + crossSize); 
     } 

     private void addDragListeners() { 
      addMouseListener(new MouseAdapter() { 
       @Override 
       public void mousePressed(MouseEvent e) { 
        draggedAtX = e.getX(); 
        draggedAtY = e.getY(); 
       } 

      }); 
      addMouseMotionListener(new MouseMotionAdapter() { 
       @Override 
       public void mouseDragged(MouseEvent e) { 
        Point newLocation = new Point(e.getX() - draggedAtX + getLocation().x, e.getY() - draggedAtY + getLocation().y); 
        setLocation(newLocation); 
       } 

      }); 
     } 

    } 

    public class PropertionalConstraints { 

     private float x; 
     private float y; 

     public PropertionalConstraints(float x, float y) { 
      this.x = x; 
      this.y = y; 
     } 

     public float getX() { 
      return x; 
     } 

     public float getY() { 
      return y; 
     } 

     public void setX(float x) { 
      if (x > 1f) { 
       x = 1f; 
      } else if (x < -0f) { 
       x = 0f; 
      } 
      this.x = x; 
     } 

     public void setY(float y) { 
      if (y > 1f) { 
       y = 1f; 
      } else if (y < -0f) { 
       y = 0f; 
      } 
      this.y = y; 
     } 

    } 

    public class PropertionalLayoutManager implements LayoutManager2 { 

     private Map<Component, PropertionalConstraints> mapConstraints; 

     public PropertionalLayoutManager() { 
      mapConstraints = new HashMap<>(25); 
     } 

     public PropertionalConstraints getConstraintsFor(Component comp) { 
      return mapConstraints.get(comp); 
     } 

     public void setConstraintsFor(Component comp, PropertionalConstraints pc) { 
      mapConstraints.put(comp, pc); 
     } 

     @Override 
     public void addLayoutComponent(Component comp, Object constraints) { 
      if (constraints instanceof PropertionalConstraints) { 
       mapConstraints.put(comp, (PropertionalConstraints) constraints); 
      } else { 
       throw new IllegalArgumentException("Constraints must be PropertionalConstraints"); 
      } 
     } 

     @Override 
     public Dimension maximumLayoutSize(Container target) { 
      return preferredLayoutSize(target); 
     } 

     @Override 
     public float getLayoutAlignmentX(Container target) { 
      return 0.5f; 
     } 

     @Override 
     public float getLayoutAlignmentY(Container target) { 
      return 0.5f; 
     } 

     @Override 
     public void invalidateLayout(Container target) { 

     } 

     @Override 
     public void addLayoutComponent(String name, Component comp) { 

     } 

     @Override 
     public void removeLayoutComponent(Component comp) { 
      mapConstraints.remove(comp); 
     } 

     @Override 
     public Dimension preferredLayoutSize(Container parent) { 
      return parent.getSize(); 
     } 

     @Override 
     public Dimension minimumLayoutSize(Container parent) { 
      return preferredLayoutSize(parent); 
     } 

     @Override 
     public void layoutContainer(Container parent) { 
      int width = parent.getWidth(); 
      int height = parent.getHeight(); 
      for (Component comp : parent.getComponents()) { 
       PropertionalConstraints con = mapConstraints.get(comp); 
       if (con != null) { 
        int x = (int)(width * con.getX()); 
        int y = (int)(height * con.getY()); 
        comp.setSize(comp.getPreferredSize()); 
        comp.setLocation(x, y); 
       } else { 
        comp.setBounds(0, 0, 0, 0); 
       } 
      } 
     } 

    } 

} 

, 당신은 크기를 결정하는 "매직"번호를 사용하여 특정 요소의 위치를 ​​렌더링합니다. 이것은 매우 나쁜 생각입니다. 특히 페인팅이나 인쇄 할 때는 이러한 모든 값을 경험적 가치에 근거해야합니다.

이 예에서는 다양한 요소의 크기와 위치를보다 정확하게 계산하는 데 필요한 정보를 제공하기 위해 FontMertrics을 사용했습니다. 모든 플랫폼에서 모든 글꼴이 동일하게 렌더링되지는 않으므로 더 나은 크로스 플랫폼 지원이 가능합니다.)

+0

정확히 내가 필요한 것. 개선에 감사드립니다. – cernover

+0

+1 자신 만의'LayoutManager'를 만드십시오. 이 대답을 위해 일하는 모든 것을 했습니까? – syb0rg

+3

@ syb0rg 네, 그건 내가 널 레이아웃을 싫어하는 정도입니다;) – MadProgrammer

관련 문제