自定义 JComponent(一行)未显示在 JPanel 上

Custom JComponent (A Line) Doesn't Show Up On JPanel

它在jframe上显示没有jpanel的行,但是当我把它添加到jpanel时却没有。我尝试将 jpanel 的布局管理器设置为 null 但没有结果。我想使用 JComponents 来绘制线条,因为我希望它们可以点击。

Main.java 文件:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Main {
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
    frame.setSize(500, 500);

    //Parent Panel
    JPanel panel = new JPanel();
    panel.setBackground(Color.YELLOW);
    panel.setLayout(null);

    //Add Line To Panel
    Line line = new Line(new Point2D.Double(20,20), new Point2D.Double(180,180));

    panel.add(line);
    panel.repaint();

    frame.add(panel);
    frame.setVisible(true);
  }
}

class Line extends JComponent {

   private final Point2D start, end;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(Color.BLUE);
        g2.setStroke(new BasicStroke(2.0F));
        g2.draw(new Line2D.Double(start,end));
    }

    public Line( Point2D start, Point2D end){
        this.start = start;
        this.end = end;
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("mouse clicked");
            }
        });
    }
}

在 Line 构造函数中添加自定义尺寸。

public Line( Point2D start, Point2D end){ ...
this.setSize(200, 200); }

已更新以适应 painted Graph

建议从 JComponent 更改为 JPanel 以便查看 background

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Main {
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
    frame.setSize(500, 500);

    //Parent Panel
    JPanel panel = new JPanel();
    panel.setSize(300,300);
    frame.add(panel);
    panel.setBackground(Color.YELLOW);
    panel.setLayout(null);

    //Add Line To Panel
    Line line = new Line(new Point2D.Double(20,20), new Point2D.Double(180,180));
    panel.add(line);

    frame.setVisible(true);
  }
}

class Line extends JPanel {

   private final Point2D start, end;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setBackground(Color.RED);
        g2.setColor(Color.BLUE);
        g2.setStroke(new BasicStroke(2.0F));
        g2.draw(new Line2D.Double(start,end));
        Rectangle r = g2.getClipBounds();
        System.out.println(r.x+":"+r.y);
    }

    public Line( Point2D start, Point2D end){

        this.start = start;
        this.end = end;
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("mouse clicked at "+e.getX()+":"+e.getY());

            }
        });
        int max_x = (int) Math.max(start.getX(), end.getX());
        int max_y = (int) Math.max(start.getY(), end.getY());
        System.out.println("max x="+max_y+",y="+max_y);
        setSize(max_x,max_y);
        setVisible(true);
        setBackground(Color.GREEN);
    } 
}

注意:只允许 inside_green 次点击!

It shows the line without jpanel on jframe, but it doesn't when I add it to jpanel

Swing 组件负责确定它们自己的首选大小。

当您将组件添加到面板时,布局管理器将根据布局管理器的规则设置组件的 size/location。

当您将组件添加到框架时,实际上是将其添加到框架的内容窗格中,该框架是 Jpanel,默认情况下使用 BorderLayout。因此组件的大小可以填充框架中可用的 space。

panel.setLayout(null);

然后您将组件添加到具有空布局的面板。现在您负责设置组件的 size/location 。如果您不这样做,则大小为 (0, 0),因此没有什么可绘制的。

您应该将 class 的 getPreferredSize() 方法重写为 return 组件的首选大小。然后布局管理器就可以完成他们的工作了。

如果您确实需要一个空布局,那么应该在应用程序代码中设置组件的大小,而不是行 class 本身。

But now my line has a big container that listens for any clicks,

如果你想要命中检测,那么你重写 contains(...) 方法。

下面是一个实现上述建议的基本示例:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Line extends JComponent
{
   private Line2D.Double line;

    public Line( Point2D start, Point2D end)
    {
        line = new Line2D.Double(start, end);

        addMouseListener(new MouseAdapter()
        {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                System.out.println("mouse clicked");
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;
        g2.setColor( Color.BLUE );
        g2.setStroke( new BasicStroke(2.0F) );
        g2.draw( line );
    }

    @Override
    public Dimension getPreferredSize()
    {
        Rectangle bounds = line.getBounds();

        int width = bounds.x + bounds.width;
        int height = bounds.y + bounds.height;

        return new Dimension(width, height);
    }

    @Override
    public boolean contains(int x, int y)
    {
        double distance = line.ptSegDist( new Point2D.Double(x, y) );

        return distance < 2;
    }

    public static void main(String[] args)
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
        frame.setSize(500, 500);

        //Parent Panel
        JPanel panel = new JPanel();
        panel.setBackground(Color.YELLOW);

        //Add Line To Panel
        Line line = new Line(new Point2D.Double(20,20), new Point2D.Double(180,180));

        panel.add(line);
        panel.repaint();

        frame.add(panel);
        frame.setVisible(true);
    }
}