Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 4 of 4

Thread: JPanel not showing up dynamically inside JLayeredPane

  1. #1
    Junior Member
    Join Date
    Apr 2019
    Posts
    3
    My Mood
    Confused
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default JPanel not showing up dynamically inside JLayeredPane

    I have a JLayeredPane and it contains a JPanel to start with. Now I want another smaller JPanel to display on top of the previous JPanel inside the JLayeredPane dynamically. By dynamically I mean when a certain event occurs, so I put its code inside the event handler for the event as well.

    The problem is that sometimes the JPanel shows up as expected while other times it doesn't. And I cannot even predict what makes it show up when it does, because it is very random.

    Following is the code for the JPanel that I want to display dynamically...
    private class PromotionOptions extends JPanel {
     
            private PromotionOptions(PieceColor color) {
                super.setSize(50,200);
                super.setBackground(Color.WHITE);
                super.setLayout(new GridLayout(4, 1));
     
                ImageIcon queenIcon = new ImageIcon(getClass().getResource("/pieceIcons/" + color.abbr + "Q.png"));
                ImageIcon rookIcon = new ImageIcon(getClass().getResource("/pieceIcons/" + color.abbr + "R.png"));
                ImageIcon bishopIcon = new ImageIcon(getClass().getResource("/pieceIcons/" + color.abbr + "B.png"));
                ImageIcon knightIcon = new ImageIcon(getClass().getResource("/pieceIcons/" + color.abbr + "N.png"));
     
                JLabel queenLabel = new JLabel(queenIcon);
                JLabel rookLabel = new JLabel(rookIcon);
                JLabel bishopLabel = new JLabel(bishopIcon);
                JLabel knightLabel = new JLabel(knightIcon);
     
                super.add(queenLabel);
                super.add(rookLabel);
                super.add(bishopLabel);
                super.add(knightLabel);
            }
        }

    Dont worry about the class and the constructors being private, because this is an inner class for the Board class. It is accessed from a method inside that class. Here is how I am calling the promotion options to display dynamically...
    case PROMOTION:
                        moveMade.initialTile.removePiece();
                        JPanel promotionOptions = new PromotionOptions(colorToMove);
                        promotionOptions.setLocation(200,200);
                        layeredPaneContainer.add(promotionOptions, 2);
                        layeredPaneContainer.revalidate();
                        break;

    Here layeredPaneContainer is the reference to the JLayeredPane that I created inside another class and passed to this Board class through the constructor. Here is the code for where I created the JLayeredPane object...

    class Game extends JFrame {
     
        Game() {
            super.setLayout(new TableLayout(new double[][]{{0.5, 475, 0.5}, {0.5, 475, 0.5}}));
     
            JLayeredPane layeredContainer = new JLayeredPane();
            layeredContainer.setLayout(null);
     
            Board board = new Board(layeredContainer);
            board.arrange();
     
            layeredContainer.add(board, 1);
            board.setSize(475, 475);
     
            super.add(layeredContainer, "1, 1");
     
            super.setSize(600, 600);
            super.setResizable(false);
            super.setDefaultCloseOperation(EXIT_ON_CLOSE);
     
     
            super.validate();
        }
    It would be really helpful if someone can point out the bug.
    Thank you for your time...

  2. #2
    Member
    Join Date
    Sep 2018
    Location
    Virginia
    Posts
    284
    My Mood
    Cool
    Thanks
    0
    Thanked 38 Times in 36 Posts

    Default Re: JPanel not showing up dynamically inside JLayeredPane

    If I can't compile this and run it I can't help. I need more than just a case statement for a switch construct. And since you have too many images and some third party layout managers, I would need a smaller example that demonstrates the problem.

    Regards,
    Jim

  3. The Following User Says Thank You to jim829 For This Useful Post:

    javaAllDay (April 15th, 2019)

  4. #3
    Junior Member
    Join Date
    Apr 2019
    Posts
    3
    My Mood
    Confused
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel not showing up dynamically inside JLayeredPane

    After hours of frustrated debugging, I finally somehow made it work correctly. What I did was I added SwingUtilities.invokeLater() method and passed the code inside it like this..
    case PROMOTION:
                        moveMade.initialTile.removePiece();
                        SwingUtilities.invokeLater(() -> {
                            JPanel promotionOptions = new PromotionOptions(colorToMove.opposite);
                            promotionOptions.setLocation(clickedTile.getLocation());
                            layeredPaneContainer.add(promotionOptions, 2);
                            layeredPaneContainer.revalidate();
                        });
                        break;
    Although I made it to work somehow, I am not completely satisfied yet. I dont understand when I need to use the invokeLater() method and when I donot need to use it. I have made a few GUI applications before and there also I had to add components dynamically, and I could do it without this passing my code inside this method.

    Can someone please clarify when and when not to use this invokeLater(). Also for the record, I already have read the Java docs about this method, I just need a little non technical explanation for this.

    Thanks in advance...

  5. #4
    Member
    Join Date
    Sep 2018
    Location
    Virginia
    Posts
    284
    My Mood
    Cool
    Thanks
    0
    Thanked 38 Times in 36 Posts

    Default Re: JPanel not showing up dynamically inside JLayeredPane

    I understand the frustration. Every time you modify a Swing component you should do so using invokeLater (or invokeAndWait). The problem arises if several threads decide to do something to the same Swing component at the same time. Unexpected results could occur. So if each thread simply schedules that task to run on the EDT, they are guaranteed that the event will occur sequentially with no inter-thread interference. But it is important to not do things that would take too long because the gui could become unresponsive. So do most of the work outside of the EDT and then update the gui accordingly. Here is an example that demonstrates the issue(s).

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
     
    public class EDTDemo implements ActionListener {
     
       public static void main(String[] args) {
    	  new EDTDemo().start();
       }
     
       public void start() {
    	  // Simple bookkeeping to create a frame and button
    	  // and center it on screen.
    	  JFrame frame = new JFrame();
    	  frame.setLayout(new FlowLayout());
    	  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    	  frame.setPreferredSize(new Dimension(200, 200));
    	  JButton button = new JButton("Click");
    	  button.setPreferredSize(new Dimension(100, 100));
    	  button.addActionListener(this);
    	  frame.add(button);
    	  frame.pack();
    	  frame.setLocationRelativeTo(null); // center on screen
    	  frame.setVisible(true);
       }
     
       public void actionPerformed(ActionEvent ae) {
    	  JButton b = (JButton) ae.getSource();
    	  b.setBackground(Color.RED);
    	  SwingUtilities.invokeLater(() ->
    	  {
    		 try {
    			// simulates other processing (exaggerated of course)
    			TimeUnit.SECONDS.sleep(10);
    		 }
    		 catch (InterruptedException ie) {
    		 }
    	  });
       }
    }

    Without the invokeLater, that task would tie up the EDT and the button wouldn't be painted for 10 seconds. But this is still a problem. The 10 second task is also scheduled to run on the EDT. So even though the button gets painted immediately, tje program will be unresponsive for 10 seconds. When one clicks to close the window, that event gets scheduled to run on the EDT *after* the long task runs.

    Note that setting the color was done in the EDT because it was done during the processing of an event -- the button click. But it was just updating a setting to be painted later so it didn't need to be scheduled separately.

    Regards,
    Jim
    Last edited by jim829; April 15th, 2019 at 11:31 AM.

  6. The Following User Says Thank You to jim829 For This Useful Post:

    javaAllDay (April 15th, 2019)

Similar Threads

  1. Graphics in Jpanel are not showing! Help please ! T^T
    By Toad in forum What's Wrong With My Code?
    Replies: 1
    Last Post: June 11th, 2013, 11:09 PM
  2. [SOLVED] JPanel not showing in JFrame
    By Tjstretch in forum AWT / Java Swing
    Replies: 2
    Last Post: October 31st, 2011, 12:27 AM
  3. Dynamically add a Jpanel to a Jframe
    By Closet_Rambo in forum AWT / Java Swing
    Replies: 6
    Last Post: October 3rd, 2011, 03:51 AM
  4. Showing JPanel error
    By Fermen in forum What's Wrong With My Code?
    Replies: 5
    Last Post: June 20th, 2011, 12:12 PM
  5. Creating and displaying a JPanel inside another JPanel
    By JayDuck in forum AWT / Java Swing
    Replies: 1
    Last Post: April 7th, 2009, 08:02 AM

Tags for this Thread