the feels the feels - 9 months ago 29
Java Question

box isn't appearing or moving on JPanel.. Java

I am trying to create this box on my panel 1 of Java but nothing is showing up on the screen :/ what is the problem? Sorry I am new to java animation and its so hard! Also, I want the box to only appear and move on the first panel not the second.. Here are my codes.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class frog extends JPanel implements ActionListener{
JFrame frame= new JFrame();
JPanel panel=new JPanel();
JButton button = new JButton("Hungry");
JPanel panel2=new JPanel();
JTextField t;
Timer tm= new Timer(5, this);
int x=0, velX=2;
public void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.RED);
g.drawRect(100,10,30,40);
g.fillRect(x,10,20,10);
tm.start();
}
JLabel l= new JLabel("Good");
frog(){
panel.setBackground(Color.CYAN);
panel2.setBackground(Color.GREEN);
t= new JTextField("Frog is hungry",10);
panel2.add(t);
panel2.add(button);
frame.add(panel,BorderLayout.CENTER);
frame.add(panel2,BorderLayout.PAGE_END);
button.addActionListener(this);
frame.setSize(500,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}

public static void main(String[] args) {
frog f= new frog();

}


@Override
public void actionPerformed(ActionEvent e) {
t.setText("Now he is full");
x=x+velX;
repaint();
}

}

Answer Source

Let's stop for a minute and have a look at what you've done.

You've created a class which extends from JPanel

public class Frog extends JPanel implements ActionListener {

Okay. You've overridden paintComponent to do some custom painting

@Override
public void paintComponent(Graphics g) {
    super.paintComponents(g);
    g.setColor(Color.RED);
    g.drawRect(100, 10, 30, 40);
    g.fillRect(x, 10, 20, 10);
    tm.start();
}

Okay, there's some issues here, but lets keep going. In the panel's constructor, you've create two new panels, you've added this two panels to a JFrame and made it visible

Frog() {
    panel.setBackground(Color.CYAN);
    panel2.setBackground(Color.GREEN);
    t = new JTextField("Frog is hungry", 10);
    panel2.add(t);
    panel2.add(button);
    frame.add(panel, BorderLayout.CENTER);
    frame.add(panel2, BorderLayout.PAGE_END);
    button.addActionListener(this);
    frame.setSize(500, 400);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}

But wait, what about the Frog panel that never gets added to anything, so how is it suppose to be displayed?

Also, the constructor has some very nasty side effects, put aside the non-associated panels, it creates a frame when ever it's called, this really a bad idea.

Basic OO

With OO, you want to limit the functionality of any object to a single responsibility, the Frog panel has no responsibility creating the additional panels (they add no functionality to the Frog panel) or making a frame, it's responsibility is to paint and animate the frog, nothing else.

public class FrogPane extends JPanel {

    private Timer timer;
    int x = 0, velX = 2;

    public FrogPane() {
        timer = new Timer(40, new ActionListener() {
                                        @Override
                                        public void actionPerformed(ActionEvent e) {
                                            x = x + velX;
                                            repaint();
                                        }
                                    });
        setBackground(Color.CYAN);
    }

    public void start() {
        timer.start();
    }

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

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.RED);
        g2d.drawRect(100, 10, 30, 40);
        g2d.fillRect(x, 10, 20, 10);
        g2d.dispose();
    }

}

Okay, so the FrogPane is pretty basic, it paints a representation of the frog and updates the position via the use of a Timer. Notice that the Timer is NOT started in the paintComponent, paintComponent can be called for any number of reasons, many of which you don't control, so don't do anything within it which might change the state of the component or which you are relying on to perform some secondary task

The next thing we need to do is to display it and have some way to start it

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                FrogPane frogPane = new FrogPane();

                JTextField t = new JTextField("Frog is hungry", 10);
                JButton button = new JButton("Hungry");

                JPanel actionPane = new JPanel();
                actionPane.setBackground(Color.GREEN);
                actionPane.add(t);
                actionPane.add(button);
                button.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        t.setText("Run frog run");
                        frogPane.start();
                    }
                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(frogPane);
                frame.add(actionPane, BorderLayout.PAGE_END);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

So, your next question is going to be able how to manage state between different classes, which suggest to me that you need to go away and do some more research into Model-View-Controller and better understand the concept of separation of responsibilities. The basic answer is, you use a model.