2013-04-05 30 views
3

我正嘗試創建具有可拖動的十字架的鼠標單擊後出現的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都是圍繞着佈局管理器的使用而設計的,所以你會發瘋(恕我直言)把所有的工作都扔掉。

如果您發現自己處於可用佈局經理似乎沒有達到自己想要的目標的位置,那麼編寫您自己的版本可能更值得。

在這裏,我介紹了一個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 2013-04-05 23:19:13

+0

用於創建自己的'LayoutManager'。你做這一切工作只是爲了這個答案嗎? – syb0rg 2013-04-06 01:47:33

+3

@ syb0rg是的,這是多少我不喜歡空佈局;) – MadProgrammer 2013-04-06 02:00:23