I am trying to use JLayeredPane to overlay one JPanel on top of another. For some reason the added panels don't show up.

This is the code that creates the JLayeredPane and adds elements to it:

import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.SwingUtilities;

public class CarAnimator extends JFrame {

    public CarAnimator()
    {
        JLayeredPane racingOverlay = new JLayeredPane();

        CarAnimatorJPanel animation = new CarAnimatorJPanel();
        Racetrack racetrack = new Racetrack();

        racingOverlay.add(racetrack,JLayeredPane.DEFAULT_LAYER);
        racingOverlay.add(animation,new Integer(2));

        racingOverlay.setBorder(BorderFactory.createTitledBorder("Can't see a thing"));

        this.getContentPane().add(racingOverlay,BorderLayout.CENTER);

        this.setLocationByPlatform(true);
        this.setPreferredSize(new Dimension(850,650));
        this.setMaximumSize(new Dimension(850,650));
        this.setMinimumSize(new Dimension(850,650));
        this.setResizable(false);//prevents user from resizing the window

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(() -> {
            (new CarAnimator()).setVisible(true);
        });
    }  
}

This is the code for the racing track JPanel:

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;

public class Racetrack extends JPanel
{
    Graphics g = this.getGraphics();

    @Override
    public void paintComponent(Graphics g)
    {
        Color c1 = Color.green; 
        g.setColor( c1 ); 
        g.fillRect( 150, 200, 550, 300 ); //grass

        Color c2 = Color.black; 
        g.setColor( c2 ); 
        g.drawRect(50, 100, 750, 500); // outer edge 
        g.drawRect(150, 200, 550, 300); // inner edge 

        Color c3 = Color.yellow; 
        g.setColor( c3 ); 
        g.drawRect( 100, 150, 650, 400 ); // mid-lane marker 

        Color c4 = Color.white; 
        g.setColor( c4 ); 
        g.drawLine( 425, 500, 425, 600 ); // start line
    }
}

And this is the JPanel animation example, taken from Java: How to Program book (http://java.uom.gr/~chaikalis/javaLab/Java_HowTo_9th_Edition.pdf), adapted to work with my code:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;

public class CarAnimatorJPanel extends JPanel
{

 protected ImageIcon images[];
 private int currentImage=0;
 private final int ANIMATION_DELAY=50;
 private int width;
 private int height;
 private Timer animationTimer;

   public CarAnimatorJPanel()
   {
      try
      {
         File directory = new File("C://Users/eltaro/Desktop/Car images");
         File[] files = directory.listFiles();
         images = new ImageIcon[files.length];
         for (int i=0;i<files.length;i++)
         {
            if (files[i].isFile())
            {
                images[i]=new ImageIcon(ImageIO.read(files[i]));
            }
         }

         width = images[0].getIconWidth();
         height = images[0].getIconHeight();
      }
      catch(java.io.IOException e)
      {
         e.printStackTrace();
      }
   }

   @Override
   public void paintComponent(Graphics g)
   {
      super.paintComponent(g);
      images[currentImage].paintIcon(this,g,0,0);

      if(animationTimer.isRunning())
      {
         currentImage=(currentImage+1)%images.length;
      }
   }

   public void startAnimation()
   {
      if(animationTimer==null)
      {
         currentImage=0;
         animationTimer=new Timer(ANIMATION_DELAY, new TimerHandler());
         animationTimer.start();
      }
      else
      {
         if(!animationTimer.isRunning())
         {
            animationTimer.restart();
         }
      }
   }

   public void stopAnimation()
   {
      animationTimer.stop();
   }

   @Override
   public Dimension getMinimumSize()
   {
      return getPreferredSize();
   }

   @Override
   public Dimension getPreferredSize()
   {
      return new Dimension(width,height);
   }

   private class TimerHandler implements ActionListener
   {
      @Override
      public void actionPerformed(ActionEvent actionEvent)
      {
      repaint();
      }
   }
}

When I add the two JPanels to the JLayeredPane inside CarAnimator constructor, they fail to show:

enter image description here

有帮助吗?

解决方案

Some recommendations:

  • Since I'm guessing that your CarAnimatorJPanel sits on top of a background JPanel, you'd better set CarAnimatorJPanel to be non-opaque via setOpaque(false) so that the JPanel behind it can be seen.
  • When adding components to a JLayeredPane, you're essentially adding the components to a null layout. This means that you absolutely need to set the sizes (or override getSize()) of those components, not the preferred sizes.
  • As always, when dealing with image files, debug that you're able to adequately read in the image in a separate small test program. As usual, consider getting the image in as a resource and not as a File.
  • You have some program logic code in your paintComponent(Graphics g) method -- you change the state of the currentImage field. Never do this since you never have full control over when or even if paintComponent is called. This bit of code belongs in your animation loop, your Swing Timer's ActionListener.
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top