Java在组件中心之间画一条线 [英] Java drawing a line between the centre of components

查看:140
本文介绍了Java在组件中心之间画一条线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to have a line drawn between the centre of two JLabels when the user clicks on one label, drags and releases on top of another. Which should work no matter what size the window is.

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

But the lines are not centre, how can I fix it?

以下示例正常工作,但这些行似乎被JFrame的边界所抵消,因此它们不是中心。

The following example is working, but the lines seem to be offset by the boundaries of the JFrame, so they are not centre.

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

I do not want to try to remove the JFrame border from the point calculation, since the real interface is more complex than the example given, and has many more components included in the JFrame.

我认为点数计算与我正在使用的JPanel相关,所以我不会遇到JFrame边界问题,但似乎并非如此。

I thought the point calculation would be relative to the JPanel I am using so I would not run into the JFrame boundary issues, but this does not seem to be the case.

提前感谢您的帮助。

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);
    }


}


推荐答案

所以,基本的问题是,你的组件的位置是相对于面板,它被框架的装饰所抵消,但是你正在使用框架的现有图形上下文用于绘制线条,因此线条未对齐。

So, the basic problem is, the location of your components are relative to panel, which is offset by the frame's decorations, but you are using the frame's existing Graphics context to paint the line, so the lines are misaligned.

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

Apart from NOT using getGraphics, EVER, you could achieve the expected results by using the frame's glassPane, for example

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

Now, this will only work if the content covers the entire visible area of the contentPane, while you could mess around with converting the location information from one component context to another, a simpler solution would be to use JXLayer.

我会避免覆盖<$的原因在这种情况下,可以更新Swing组件而不需要绘制父组件,这可能会消除上次绘制时父组件绘制的内容...

The reason I would avoid overriding paint in this case, is Swing components can be updated without requiring the parent component to be painted, this could wipe out what ever the parent component painted the last time it was painted...

看看如何使用根窗格获取更多详细信息

这篇关于Java在组件中心之间画一条线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆