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

China☆狼群 提交于 2020-06-26 12:26:52

问题


It shows the line without jpanel on jframe, but it doesn't when I add it to jpanel. I've tried setting the layout manager of jpanel to null but no result. I want to use JComponents for drawing lines because I want them clickable.

Main.java file:

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

回答1:


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

Swing components are responsible for determining their own preferred size.

When you add a component to a panel, the layout manager will then set the size/location of the component based on the rules of the layout manager.

When you add a component to the frame you really add it to the content pane of the frame which is a Jpanel which uses a BorderLayout by default. So the component is sized to fill the space available in the frame.

panel.setLayout(null);

You then added the component to a panel with a null layout. Now you are responsible for setting the size/location of the component. If you don't the size is (0, 0) so there is nothing to paint.

You should override the getPreferredSize() method of your class to return the preferred size of the component. Then layout managers can do their job.

If you really need a null layout, then the size of the component should be set in the application code, not it the Line class itself.

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

If you want hit detection then you override the contains(...) method.

Here is a basic example implementing the above suggestions:

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



回答2:


Add custom size in Line constructor.

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

Updated to fit also with painted Graph

Advice to change from JComponent to JPanel in order to see 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);
    } 
}

Note: Only inside_green clicks allowed !



来源:https://stackoverflow.com/questions/62128874/custom-jcomponent-a-line-doesnt-show-up-on-jpanel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!