Search code examples
javaswingjframejpanelpaintcomponent

Java GUI stumped. Only one display in JFrame


I am trying to create Jframe that houses three JPanels. I have extended JPanel so that each time it may be passed a color and a diameter. The end result being a JFrame that has 1 red, 1 yellow and 1 green stoplightpanel. I plan on adding an ActionListener to these panels which is why it is designed this way. It is not working because currently, I only can see the yellow panel.

Fair warning this is for a class. So I have tried every configuration I can think of and I still only see one instance of my subclass present in my Jframe. If anyone can point out the obvious I would be appreciated. Oddly enough only my yellow light is displayed.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;


class TrafficLight3 extends JFrame {

    public static void main ( String [] args ) {
        TrafficLight3 tl = new TrafficLight3 ( );
    }

    // Constructor 
    public TrafficLight3( ) {

        setTitle( "Traffic Light" );
        setSize ( 200, 400 );
        setLocation ( 200, 200 );
        setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );

        StopLightPanel red = new StopLightPanel( 100, Color.RED );

        // add stoplight panel's to JFrame's default border layout. 
        add( red, BorderLayout.NORTH );

        StopLightPanel yellow = new StopLightPanel( 100, Color.YELLOW );
        add( yellow, BorderLayout.CENTER );        

        StopLightPanel green = new StopLightPanel( 100, Color.GREEN );
        add ( green, BorderLayout.SOUTH );        

        setVisible( true );
    }
    class StopLightPanel extends JPanel {

        private int diameter;
        private Color color;

        public StopLightPanel ( int d, Color c) {

             diameter = d;
            color = c;
        }

        public void paintComponent ( Graphics g ) {

            g.setColor ( color );
            g.fillOval ( 50, 25, diameter, diameter );
       }
     }  
}

Solution

  • 1- Ensure that your code runs in EDT

    2- @Flight2039 is correct, it seems that BorderLayout where location is not the CENTER uses preferredSize to determinate the size. So you could override getPreferredSize()

    3- When you override paintComponent(..) you have to call super.paintComponent(..) to follow painting method chaining. More information here.

    4- Add @Override annotation always this will check at compile time for example if you make some typo overriding the method.

    See this runnable example, i used gridLayout with one column and three rows.

    package test2;
    
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.GridLayout;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class TrafficLight3 {
    
        private JPanel redPanel;
        private JPanel yellowPanel;
        private JPanel greenPanel;
    
        // Constructor
        public TrafficLight3() {        
            redPanel = new StopLightPanel(100, Color.RED);
            yellowPanel = new StopLightPanel(100, Color.YELLOW);
            greenPanel = new StopLightPanel(100, Color.GREEN);
        }
    
        private static class StopLightPanel extends JPanel {
            private int diameter;
            private Color color;
    
            public StopLightPanel(int d, Color c) {
                diameter = d;
                color = c;
            }
    
            @Override
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(color);
                g.fillOval(50, 25, diameter, diameter);
            }
    
            @Override
            public Dimension getPreferredSize(){
                int x = diameter*2;
                return new Dimension(x,x);
            }
        }
    
        /**
         * Create the GUI and show it. For thread safety, this method should be
         * invoked from the event-dispatching thread.
         */
        private static void createAndShowGUI() {
            // Create and set up the window.
            JFrame frame = new JFrame("Traffic Light");
            frame.setSize(200,500);
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.setLayout(new GridLayout(3,1));
            frame.setLocationByPlatform(Boolean.TRUE);
            TrafficLight3 example = new TrafficLight3();
            frame.add(example.redPanel);
            frame.add(example.yellowPanel);
            frame.add(example.greenPanel);
            // Display the window.      
            frame.setVisible(Boolean.TRUE);
        }
    
        public static void main(String[] args) {
            // Schedule a job for the event-dispatching thread:
            // creating and showing this application's GUI.
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI();
                }
            });
        }
    
    }
    

    And the output..

    enter image description here