animation with multiple jComponents using jframe

2019-09-09 15:17发布

问题:

I am having trouble getting the animation visible on top of my garden grid panel. Whichever I add last to the contentpane that one shows. is there anyway to show multiple components at the same time. I've tried switching the classes animation and garden grid to extend jpanel but nothing has worked. Animation is a series of images that shows a character moving when you are dragging it with a mouse. I need that character to move on top of the garden grid panel. any help?

  package view;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.GridBagLayout;
import java.awt.Panel;

import javax.swing.JFrame;
import javax.swing.JLayeredPane;


public class Driver {
public static void main(String[] args) {

    JFrame frame = new JFrame();
   JLayeredPane pane = new JLayeredPane();
   frame.add(pane);

   Animation animation = new Animation();
   GardenPanel garden = new GardenPanel(6,4,600,800);


   pane.add(animation,new Integer(1));

   pane.add(garden, new Integer(0));
    frame.setSize(800, 600);


    System.out.println(pane.highestLayer());// just to check I dont have hidden layers







    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

    while(true){
        frame.repaint();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

}

--------Animation Class-----------

you should see a moving orc. you can drag the orc using your mouse. If you press * your mouse without moving it, the power will increase. * */

package view;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

public class Animation extends JComponent implements MouseMotionListener, MouseListener{
    final int frameCount = 10;
    int picNum = 0;
    BufferedImage[][] pics;
    int xloc = 0;
    int yloc = 0;
    final int xIncr = 8;
    final int yIncr = 2;
    final static int frameWidth = 900;
    final static int frameHeight = 600;
    final static int imgWidth = 165;
    final static int imgHeight = 165;
    //basic info about the orc

    BufferedImage seedImage; 
    int mouseX;
    int mouseY;
    int seedX = xloc;
    int seedY = yloc;
    boolean mouseholding;
    boolean moving = false;
    int power;
    public enum stage {
        MOVE, POWER
    }
    stage s;

    //Override this JPanel's paint method to cycle through picture array and draw images
    public void paint(Graphics g) {
        picNum = (picNum + 1) % frameCount;
        if(mouseholding && (s == s.POWER)){
            System.out.println(power++);
        }


        g.drawImage(pics[0][picNum], xloc, yloc, Color.gray, this);
        g.drawImage(seedImage, seedX, seedY, imgWidth/8, imgHeight/8, this);
    }


    //Constructor: get image, segment and store in array
    public Animation(){
        seedImage = createImage(); 
        BufferedImage[] img = createAnimation();
        pics = new BufferedImage[img.length][10];
        for(int j = 0; j < img.length; j++){
            for(int i = 0; i < frameCount; i++)
                pics[j][i] = img[j].getSubimage(imgWidth*i, 0, imgWidth, imgHeight);
        }
        addMouseMotionListener(this);
        addMouseListener(this);
    }  

    //Read image from file and return
    private BufferedImage[] createAnimation(){
        BufferedImage[] bufferedImage = new BufferedImage[4];
        try {
            bufferedImage[0] = ImageIO.read(new File("images/orc_forward_southeast.png"));
            bufferedImage[1] = ImageIO.read(new File("images/orc_forward_southwest.png"));
            bufferedImage[2] = ImageIO.read(new File("images/orc_forward_northeast.png"));
            bufferedImage[3] = ImageIO.read(new File("images/orc_forward_northwest.png"));
            return bufferedImage;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private BufferedImage createImage(){
        BufferedImage bufferedImage;
        try {
            bufferedImage = ImageIO.read(new File("images/seed.png"));
            return bufferedImage;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;

        // TODO: Change this method so you can load other orc animation bitmaps
    }

    // implement the method in mouseListener and mouseMotionListener interface
    @Override
    public void mouseDragged(MouseEvent event) {
        mouseX = event.getX();
        mouseY = event.getY();
        if( ( xloc<mouseX ) && (xloc+imgWidth >mouseX) && (yloc<mouseY) && (yloc+imgHeight>mouseY) && (s==stage.MOVE) ){

            //System.out.println("Imagecoor:("+xloc+", "+yloc+")"+" mousecoor:("+mouseX+","+mouseY+")"); 
            // you can print the coordinate if you want     
            xloc = mouseX-imgWidth/2;
            yloc = mouseY-imgHeight/2;
            seedX = mouseX;
            seedY = mouseY;
        }   
    } // draging the image
    @Override
    public void mouseMoved(MouseEvent arg0) {
    }
    @Override
    public void mouseClicked(MouseEvent e) {
    }
    @Override
    public void mouseEntered(MouseEvent e) {    
    }
    @Override
    public void mouseExited(MouseEvent e) { 
    }

    // for increasing the power.
    @Override
    public void mousePressed(MouseEvent event) { 
        mouseholding = true;
        mouseX = event.getX();
        mouseY = event.getY();
        if( (xloc == mouseX-imgWidth/2) && (yloc == mouseY-imgHeight/2) ){
            s = stage.POWER;
        }
    }
    @Override
    public void mouseReleased(MouseEvent event) {
        mouseholding = false;
        s = stage.MOVE;
        power = 0;
    }
}

--------GardenPanel Class------------ should display 2 black lines

package view;

import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

public class GardenPanel extends JComponent {
    private int numOfRows;
    private int numOfColumns;
    private int frameWidth;
    private int frameHeight;

    public GardenPanel(int numOfRows, int numOfColumns, int frameHeight, int frameWidth){
        this.numOfRows = numOfRows;
        this.numOfColumns = numOfColumns;
        this.frameHeight = frameHeight;
        this.frameWidth = frameWidth;


    }
    int secondX = ((frameWidth -((frameWidth/3) *2)) / 4) * 3;

    @Override
    public void paint(Graphics g){
        g.drawLine((frameWidth/3) * 2, (frameHeight/4) * 3, (frameWidth/3 * 2) - 30, frameHeight/4);

        g.drawLine(((frameWidth/3) * 2) + 200, (frameHeight/4) * 3, ((frameWidth -((frameWidth/3) *2)/4) * 3) - 30, frameHeight/4);



    }

}

回答1:

You state:

I am having trouble getting the animation visible on top of my garden grid panel. Whichever I add last to the contentpane that one shows.

A JFrame's contentPane uses BorderLayout, and that's how BorderLayouts work. If you add a component by default (without an int 2nd parameter), it is placed by default in the BorderLayout.CENTER position and covers anything added there previously. You will want to read the Swing layout manager tutorial for more details on this.

is there anyway to show multiple components at the same time.

Yes, use different layout managers and components. If you want components on top of each other, consider using a JLayeredPane.

I've tried switching the classes animation and garden grid to extend jpanel but nothing has worked. Animation is a series of images that shows a character moving when you are dragging it with a mouse. I need that character to move on top of the garden grid panel. any help?

Not sure what your exact question is here.



回答2:

There are two ways to make the animation sit on top of the Garden Panel. However as pointed out by "Hovercraft Full Of Eels" there are issues with how you are using a "GridBagLayout".

When working with animations I tend to use absolution positioning, this way it is easy to manually specify the exact location of components, and you can ensure that everything will be visible. I do this by adding a jLayeredPane/jPanel to the jFrame and adding components to them instead of the jFrame.

Here are two ways you can make the animation sit on top of the GardenPanel.

1) Add the component in a different order for different results. Give it a try.

2) Once all components have been added to the "ContentPane" you can set the Z-Order of the component you want on top, something like this:

//Create this object first so we can set the Z-Order later
Animation animation = new Animation()
frame.getContentPane().add(animation); //use object above, not a "new" Animation
frame.getContentPane().add(new GardenPanel(6,4,600,800));
//Do something like this after all other components have been added to the ContentPane.
frame.getContentPane().setComponentZOrder(animation, 0);

Edit: From what you have showed you have the basics, so here is a self contained example that you can compile that I believe demonstrates what you want to do.

The animation is represented by the red box, the GardenPanel is represented by the blue area.

Please note:

  1. The order that I have added components to the pane. First: pane.add(animation); Then: pane.add(GardenPanel);.
  2. I kept this example very simple by using a JLabel instead of your custom Animation component and a JLayeredPane instead of your GardenPanel component, you should be able to just swap them both out.
  3. Remove the while loop in the Drive class, at least while testing. You can sort out the repaint issue later once you know both components are showing correctly.

    import java.awt.Point;
    import javax.swing.JFrame;
    import javax.swing.JLayeredPane;
    import javax.swing.JLabel;
    
    public class Driver
    {
    //components
    static JFrame frame = new JFrame();
    static JLayeredPane pane = new JLayeredPane();
    static JLabel animation = new JLabel();
    static JLayeredPane GardenPanel = new JLayeredPane();
    
    //variables
    static Point startPos = new Point(0, 0);
    static Point draggedPos = new Point(0, 0);
    
    public static void main(String[] args)
    {
    //setup components
    frame.setSize(800, 600);
    pane.setSize(frame.getSize());
        pane.setBackground(java.awt.Color.GRAY);
        pane.setOpaque(true);
    
    animation.setSize(100, 150);
    animation.setLocation((pane.getWidth() - animation.getWidth())/2, (pane.getHeight() - animation.getHeight())/2);
    animation.setOpaque(true);
    animation.setBackground(java.awt.Color.RED);
    animation.addMouseListener(new java.awt.event.MouseAdapter()
    {
        @Override
        public void mousePressed(java.awt.event.MouseEvent evt)
        {
        startPos = evt.getLocationOnScreen();
        }
    });
    animation.addMouseMotionListener(new java.awt.event.MouseMotionAdapter()
    {
        @Override
        public void mouseDragged(java.awt.event.MouseEvent evt)
        {
        draggedPos = evt.getLocationOnScreen();
        animation.setLocation(animation.getX() + (draggedPos.x - startPos.x), animation.getY() + (draggedPos.y - startPos.y));
        startPos = evt.getLocationOnScreen();
        }
    });
    
    GardenPanel.setSize(800, 600);
    GardenPanel.setLocation(0, 0);
    GardenPanel.setOpaque(true);
    GardenPanel.setBackground(java.awt.Color.BLUE);
    
    //add components
    frame.add(pane);
    //The order of the following will get the desired results, I do not specify Z-Order, I simply add the top component first
    pane.add(animation);
    pane.add(GardenPanel);
    
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    }
    

    }

Using this example code you can possibly adapt your original code to follow a similar path.