Search code examples
javaswingjpaneljcomponent

Custom JComponent only Displays on JFrame not JPanel


Can somebody please help me understand why my custom JComponent 'Bar', only displays when added directly to the JFrame, and not when added to a JPanel (which is then added to the JFrame)?

Thanks!

package main;

import java.awt.BorderLayout;

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

public class Board {

    public void start(){
        JFrame frame = new JFrame();
        JButton button1 = new JButton("Button 1");
        Bar statusbar = new Bar();
        JLabel status = new JLabel("Status: ");

        JPanel topPanel = new JPanel();
        topPanel.add(status);
        topPanel.add(statusbar);

        JPanel mainPanel = new JPanel();
        mainPanel.add(button1);
        mainPanel.add(statusbar);

        frame.getContentPane().add(BorderLayout.NORTH, topPanel);
        frame.getContentPane().add(BorderLayout.SOUTH, mainPanel);
        frame.getContentPane().add(BorderLayout.CENTER, statusbar);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(200,100);
        frame.setVisible(true);
    }
}

Here is my Bar Class...

package main;

import java.awt.Graphics;

import javax.swing.JComponent;

public class Bar extends JComponent{
    public void paint(Graphics g){
        g.fillRect(0, 0, 100, 10);
    }
}

Solution

  • You're adding statusbar to several different places in the component tree, Swing doesn't deal with that well (or at all).

    Create a separate Bar instances each time you use it, if you want their display to be synchronized, they should share the same model.

    Edit

    Ah, on a second glance, the problem here is that you never set a size (or preferred size) for the Bar components, so they get squished to 0 by the layout manager.

    Try:

    public static class Bar extends JComponent {
    
        private Bar() {
            setPreferredSize(new Dimension(25, 5));
        }
    
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.fillRect(0, 0, 100, 10);
        }
    }
    

    You should also add a frame.pack() before display.

    (the multiple references to the same component thing is still true, too)