user1432671
user1432671

Reputation: 71

How to use frame.add method to create multiple visible objects

When I try to add a second instance of an elevator class, the first one disappears. How can I rearrange this code in order to see both objects?

Here is my main class:

public class MainClass extends JPanel implements ActionListener {
    public static void main(String[] args) {
        JFrame frame = new JFrame("title");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1000, 700);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        Component component1 = frame.add(new elevator(0,0));
        Component component2 = frame.add(new elevator(505,50));   
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
    }
}

And this is the elevator class:

public class elevator extends JPanel implements ActionListener {
    Timer timer;
    private double angle = 0;
    private double scale = 1;
    private double delta = 0.01;
    private int x=0;
    private int y=0;

    Rectangle.Float r = new Rectangle.Float(0, 0, 3, 3);

    public elevator(int input_x, int input_y) {
        x=input_x;
        y=input_y;
        timer = new Timer(10, this);
        timer.start();
    }

    public elevator() {
        timer = new Timer(10, this);
        timer.start();
    }

    public void paint(Graphics g) {
        this.setSize(100,200);
        this.setLocation(x, y);
        int h = getHeight();
        int w = getWidth();

        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

        g2d.translate(w / 5, scale*140);
        g2d.scale(20, 20);

        g2d.fill(r);
    }

    public void actionPerformed(ActionEvent e) {
        if (scale < 0.01 || scale > 0.99) {
            delta = -delta;
        } 
        scale += delta;
        angle += 0.01;
        repaint();
    }
}

Upvotes: 2

Views: 6079

Answers (4)

reggoodwin
reggoodwin

Reputation: 1544

UPDATED

Strictly speaking, all I think you need to do to get the code working may be this. Specify a BorderLayout position when you add to the frame:

frame.add(new elevator(0, 0), BorderLayout.WEST);
frame.add(new elevator(505, 50), BorderLayout.EAST);

The other answers here are of course proposing better long term approaches to your project code.

(Thanks sbat for pointing out that the default layout is actually BorderLayout not FlowLayout).

Cheers,

Upvotes: 0

Paul Samsotha
Paul Samsotha

Reputation: 208994

Don't make elevator extends JPanel at all. Just make it a class for holding state, manipulating the state, and drawing the state. Then just have one main drawing panel, that you add elevators to, using a List<elevator>.

Elevator.java (notice Java naming convention)

public class Elevator {
    public void draw(Graphics g) {}
    public void move() {}
}

ElevatorPanel.java

public class ElevatorPanel extends JPanel {
    List<Elevator> elevators;

    @Override
    protected void paintComponent(Grapchics g) {
        super.paintComponent(g);
        for (Elevator elevator: elevators) {
            elevator.draw(g);
        }
    }
}

Just have the timer (only one) in the ElevatorPanel class and loop through the list of elevators and call the move method.

Timer timer = new Timer(40, new ActionListener(){
    public void actionPerformed(ActionEvent e) {
        for (Elevator elevator : elevators) {
            elevator.move();
        }
        repaint();
    }
});

You can see a bunch of similar examples here and here and here and here and here and here.


Side Notes:

  • Follow Java naming convention. Class names begin with upper case letters.

  • You should be override paintComponent and not paint

  • Swing apps should be run on the Event Dispatch Thread. See Initial Threads

Upvotes: 2

APerson
APerson

Reputation: 8422

You will need some sort of container to put both of the components in. You could use a JPanel, in which case your code would look like:

JPanel panel = new JPanel();
panel.add(new elevator(0,0));
panel.add(new elevator(505,50));
frame.add(panel);

For both of them to take up the same area (and for the JPanel to fill up all the space it can), you could pass in a GridLayout to the JPanel constructor:

JPanel panel = new JPanel(new GridLayout(2, 1)); // 2 rows, 1 column

or

JPanel panel = new JPanel(new GridLayout(1, 2)); // 1 row, 2 columns

Upvotes: 2

Ordous
Ordous

Reputation: 3884

A frame can only handle one component by default. Create a JPanel and add it to the JFrame, then specify a layout for your JPanel and start adding components to it, instead of the frame

Upvotes: 1

Related Questions