Search code examples
javaswingjpanelboxlayout

The added JPanel only shows up when added from a different method?


enter image description hereI am trying to create a program which first adds rows of JPanel. After a JPanel has been added, you can then add squares by clicking "Add Horizontal" and specifying the row index (from 0) to which a square should be added.

I'm trying to add my JPanel with one of these squares already added. However, this first square does not show up. When I add another square, it's as if the square is there, but is just invisible.

You can see a demonstration of this in the attached image, where the first squares of index 2 and index 3 are simply invisible with no JLabel added.

How can I amend my code so that the first square is shown immediately after the "Add Vertical" JButton is clicked?

import javax.swing.*;
import java.awt.*;
import javax.swing.event.*;
import java.awt.event.*;
public class HistoryEditor extends JFrame{


public static Color randomColor(){
    return new Color((float)Math.random(), (float)Math.random(), (float)Math.random());
}

public HistoryEditor(){

    setLayout(new BorderLayout());

    final JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
    JPanel controlPanel = new JPanel(new FlowLayout());
    final JTextField tf = new JTextField(20);
    JButton addVertical = new JButton("Add Vertical");
    JButton addHorizontal = new JButton("Add Horizontal");
    JButton removeVertical = new JButton("Remove Vertical");

    addVertical.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            JPanel newPanel = new JPanel();
            newPanel.setPreferredSize( new Dimension(getWidth(), 50) );
            newPanel.setMaximumSize( newPanel.getPreferredSize() );
            newPanel.setMinimumSize( newPanel.getPreferredSize() );
            newPanel.setBackground( HistoryEditor.randomColor() );
            newPanel.setLayout( new BoxLayout( newPanel, BoxLayout.X_AXIS ) );

            JPanel eventPanel = new JPanel();
            eventPanel.setBackground( HistoryEditor.randomColor() );
            eventPanel.setMaximumSize( new Dimension(50, newPanel.getHeight() ) );
            eventPanel.setMinimumSize( new Dimension(50, newPanel.getHeight() ) );
            eventPanel.setPreferredSize( new Dimension(50, newPanel.getHeight() ) );
            eventPanel.add( new JLabel( tf.getText() ) );
            eventPanel.revalidate();
            newPanel.add(eventPanel);
            newPanel.revalidate();
            mainPanel.add( newPanel );
            mainPanel.revalidate();
            mainPanel.repaint();
            eventPanel.repaint();   


        }
    });

    addHorizontal.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            try{
                int index = Integer.parseInt(tf.getText());
                JPanel selectedPanel = (JPanel)mainPanel.getComponent( index );

                JPanel eventPanel = new JPanel();
                eventPanel.setBackground( HistoryEditor.randomColor() );
                eventPanel.setMaximumSize(new Dimension(50, selectedPanel.getHeight()));
                eventPanel.setMinimumSize(new Dimension(50, selectedPanel.getHeight()));
                eventPanel.add( new JLabel( tf.getText() ) );
                selectedPanel.add(eventPanel);
                selectedPanel.revalidate();
                selectedPanel.repaint();

            }catch(Exception ex){}
        }
    });


    removeVertical.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            try{
                int index = Integer.parseInt(tf.getText());
                mainPanel.remove(index);
                mainPanel.revalidate();
                mainPanel.repaint();

            }catch(Exception ex){}
        }
    });


    controlPanel.add(tf);
    controlPanel.add(addVertical);
    controlPanel.add(addHorizontal);
    controlPanel.add(removeVertical);   
    add(mainPanel, BorderLayout.CENTER);
    add(controlPanel, BorderLayout.SOUTH);
    setSize(1000, 1000);
    setVisible(true);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

public static void main(String[]args){
    HistoryEditor he = new HistoryEditor();
}

}

Solution

  • eventPanel.setPreferredSize( new Dimension(50, newPanel.getHeight() ) );
    

    Components have a size of (0, 0) when they are created.

    So you are setting the preferred size of your eventPanel to be (50, 0) which means the added component won't be seen because the height of the panel is 0.

    You only need the revalidate() and repaint() on the mainPanel. This will cause the layout manager to be invoked and all the child components of the mainPanel will be repainted.

    Also, there is no need for the eventPanel. You can just add the label directly to the newPanel. You just need to make sure you use:

    label.setOpaque(true);
    

    so the background of the label will be painted.

    And when you use the label there will be no need to set the maximum/minimum size since they are equal to the preferred size.