2015-02-12 53 views
0

我想在两个JLabel的中心之间画一条线,当用户点击一个标签时,在另一个标签上拖动和释放。无论窗户的大小是多少,都应该能够工作。Java绘制组件中心之间的一条线

但行不是中心,我该如何解决它?

以下示例正在工作,但行似乎被JFrame的边界偏移,因此它们不是中心。

我不想尝试从点计算中删除JFrame边框,因为真实接口比给出的示例更复杂,并且JFrame中包含更多组件。

我认为点计算是相对于我使用的JPanel,所以我不会遇到JFrame边界问题,但似乎并非如此。

非常感谢您的帮助。

import java.awt.Color; 
import java.awt.Component; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 

import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 

public class test extends JFrame implements MouseListener { 

    private static JPanel panel = new JPanel(); 
    private static test window = new test(); 

    public test() { 
     panel.setLayout(new GridLayout(2, 2)); 

     JLabel l1 = new JLabel(); 
     JLabel l2 = new JLabel(); 
     JLabel l3 = new JLabel(); 
     JLabel l4 = new JLabel(); 

     l1.setOpaque(true); 
     l2.setOpaque(true); 
     l3.setOpaque(true); 
     l4.setOpaque(true); 

     l1.setBackground(Color.RED); 
     l2.setBackground(Color.BLUE); 
     l3.setBackground(Color.GREEN); 
     l4.setBackground(Color.ORANGE); 

     l1.setName("l1"); 
     l2.setName("l2"); 
     l3.setName("l3"); 
     l4.setName("l4"); 

     panel.add(l1); 
     panel.add(l2); 
     panel.add(l3); 
     panel.add(l4); 

     panel.addMouseListener(this); 

     this.add(panel);  
    } 

    public static void drawArcs(int x1, int y1, int x2, int y2) { 
     Graphics g = window.getGraphics(); 
     Graphics2D g2 = (Graphics2D) g; 
     g2.drawLine(x1, y1, x2, y2); 
    } 

    private static int x1 = 0; 
    private static int y1 = 0; 
    public void mousePressed(MouseEvent e) { 
     Component square1 = panel.getComponentAt(new Point(e.getX(), e.getY())); 
     System.out.println(square1.getName());  
     x1 = square1.getX() + square1.getWidth()/2; 
     y1 = square1.getY() + square1.getHeight()/2; 
    } 

    public void mouseReleased(MouseEvent e) { 
     Component square2 = panel.getComponentAt(new Point(e.getX(), e.getY())); 
     System.out.println(square2.getName());  
     int x2 = square2.getX() + square2.getWidth()/2; 
     int y2 = square2.getY() + square2.getHeight()/2; 
     drawArcs(x1, y1, x2, y2); 
    } 

    @Override 
    public void mouseClicked(MouseEvent arg0) {} 
    @Override 
    public void mouseEntered(MouseEvent arg0) {} 
    @Override 
    public void mouseExited(MouseEvent arg0) {} 

    public static void main(String[] args) { 
     window.setVisible(true); 
     window.setSize(400, 400); 
     window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 


} 
+0

'window.getGraphics();'不是绘画的工作原理。请参阅[在AWT和Swing中绘画](http://www.oracle.com/technetwork/java/painting-140037.html)和[执行自定义绘画](http://docs.oracle.com/javase/tutorial/) uiswing/painting /)了解更多详情 – MadProgrammer 2015-02-12 00:53:33

+0

是的,我知道,但是为了这个例子,它好像是快速的做法。问题不在于画线,而是中心问题。 – user1334130 2015-02-12 00:58:33

+1

问题是你正在错误地绘画。您正在使用窗口的图形对象。如果您正确地绘画,则Graphics对象将反映相对于面板的适当坐标,而不是Window。 – camickr 2015-02-12 01:01:01

回答

2

因此,根本的问题是,你的组件的位置是相对于panel,这是由框架的装饰偏移,但您使用的是框架现有Graphics背景画的线,所以线错位。

除了不使用getGraphics,EVER,您可以通过使用框架的glassPane达到预期的效果,例如

enter image description here

import java.awt.Color; 
import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.geom.Line2D; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test extends JFrame implements MouseListener { 

    private JPanel panel = new JPanel(); 

    public Test() { 
     ConnectTheDots dots = new ConnectTheDots(); 
     setGlassPane(dots); 
     dots.setVisible(true); 
     panel.setLayout(new GridLayout(2, 2)); 

     panel.add(createLabel(Color.RED)); 
     panel.add(createLabel(Color.BLUE)); 
     panel.add(createLabel(Color.GREEN)); 
     panel.add(createLabel(Color.ORANGE)); 

     panel.addMouseListener(this); 

     this.add(panel); 
    } 

    private Component pressComponent; 
    private Component releaseComponent; 

    public void mousePressed(MouseEvent e) { 
     pressComponent = panel.getComponentAt(new Point(e.getX(), e.getY())); 
    } 

    public void mouseReleased(MouseEvent e) { 
     releaseComponent = panel.getComponentAt(new Point(e.getX(), e.getY())); 
     joinTheDots(); 
    } 

    @Override 
    public void mouseClicked(MouseEvent arg0) { 
    } 

    @Override 
    public void mouseEntered(MouseEvent arg0) { 
    } 

    @Override 
    public void mouseExited(MouseEvent arg0) { 
    } 

    protected void joinTheDots() { 

     Rectangle bounds = pressComponent.getBounds(); 
     Point startPoint = centerOf(bounds); 
     bounds = releaseComponent.getBounds(); 
     Point endPoint = centerOf(bounds); 

     ((ConnectTheDots) getGlassPane()).drawLine(startPoint, endPoint); 

    } 

    protected Point centerOf(Rectangle bounds) { 

     return new Point(
         bounds.x + (bounds.width/2), 
         bounds.y + (bounds.height/2)); 

    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       Test frame = new Test(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    protected JLabel createLabel(Color background) { 
     JLabel label = new JLabel() { 
      @Override 
      public Dimension getPreferredSize() { 
       return new Dimension(100, 100); 
      } 
     }; 
     label.setOpaque(true); 
     label.setBackground(background); 
     return label; 
    } 

    public class ConnectTheDots extends JPanel { 

     private Point startPoint; 
     private Point endPoint; 

     public ConnectTheDots() { 
      setOpaque(false); 
     } 

     public void drawLine(Point startPoint, Point endPoint) { 
      this.startPoint = startPoint; 
      this.endPoint = endPoint; 
      repaint(); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (startPoint != null && endPoint != null) { 
       Graphics2D g2d = (Graphics2D) g.create(); 
       Line2D line = new Line2D.Double(startPoint, endPoint); 
       g2d.setColor(Color.BLACK); 
       g2d.draw(line); 
       g2d.dispose(); 
      } 
     } 

    } 

} 

现在,如果内容覆盖整个这只会工作contentPane的可见区域,尽管您可能会将位置信息从一个组件上下文转换为另一个组件,但更简单的解决方案是使用JXLayer

在这种情况下,我会避免重写paint的原因是Swing组件可以在不需要绘制父组件的情况下进行更新,这可以消除上次绘制父组件时所绘的东西...

看看How to Use Root Panes了解更多详情

+0

哇,这是一个全面的答案,感谢MadProgrammer。 – user1334130 2015-02-12 01:24:24

+0

@ user1334130我至少想知道我的疯狂想法会起作用...:P – MadProgrammer 2015-02-12 01:25:32

+0

不错。你是怎么做出漂亮的小动画的? – Shannon 2015-02-12 01:26:41