Java在组件中心之间画一条线

当用户点击一个标签时,我试图在两个JLabel的中心之间绘制一条线,拖动并释放另一个标签。 无论窗户的大小是多少都应该有效。

但线条不是中心,我该如何解决?

以下示例正在运行,但这些行似乎被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); } } 

因此,基本问题是,组件的位置是相对于panel ,它被框架的装饰所抵消,但是您使用框架的现有Graphics上下文来绘制线条,因此线条未对齐。

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

在此处输入图像描述

 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组件可以更新而不需要绘制父组件,这可能会消除上次绘制时父组件绘制的内容…

有关更多详细信息,请参阅如何使用根窗格