Search code examples
javaswingkeyboardjpanelboxlayout

adding JPanels left to right AND keyboard input


1. I am having trouble adding my JPanels in sequence. Essentially, the user will select between 1 and 4 "drone" objects to run simultaneously. If they select two, the layout should add the 2 "drones" panels to the JFrame left to right. the current code just stacks them on top of one another.

2. when i add the keyboard.nextInt(); to the program, it initializes the JFrame and then just freezes.

public class RunDrones {

public int numDrones;
final JFrame display;
private final JLabel howMany;
private MakeDrone DronePane;

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            }

            new RunDrones();
        }
    });
}

public RunDrones() {
    //Scanner keyboard = new Scanner(System.in);

    display = new JFrame();
    display.setLayout(new GridLayout());
    JPanel container = new JPanel();
    container.setLayout(new BoxLayout(container,BoxLayout.LINE_AXIS));

    DronePane = new MakeDrone();
    DronePane.setSize(200, 400);
    DronePane.setBorder(BorderFactory.createLineBorder(Color.black));

    howMany = new JLabel("How many Drones (1-4): ", JLabel.CENTER);
    howMany.setFont(new Font("Verdana", 1, 25));

    display.setSize(800, 400);
    display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    display.setLocationRelativeTo(null);
    container.add(howMany);
    display.add(container);
    display.setVisible(true);

    //numDrones = keyboard.nextInt();

    numDrones = 2;

    if (numDrones >= 5) {
        howMany.setText("BETWEEN 1 AND 4 IDIOT. Try again: ");
        //numDrones = keyboard.nextInt();
    }
    else {
        container.remove(howMany);
        switch (numDrones){
        case 4:
            Timer drone1 = new Timer(30, new Drone(DronePane));
            container.add(DronePane);
            drone1.setInitialDelay(0);
            drone1.start();
        case 3:
            Timer drone2 = new Timer(30, new Drone(DronePane));
            container.add(DronePane);
            drone2.setInitialDelay(0);
            drone2.start();
        case 2:
            Timer drone3 = new Timer(30, new Drone(DronePane));
            container.add(DronePane);
            drone3.setInitialDelay(0);
            drone3.start();
        case 1:
            Timer drone4 = new Timer(30, new Drone(DronePane));
            container.add(DronePane);
            drone4.setInitialDelay(0);
            drone4.start();
        }
    }
}

public static int getRandom() {
    int firstNum = new Random().nextInt(5) + 1;
    int secondNum = new Random().nextInt(5) + 1;
    return firstNum - secondNum;
}

public class MakeDrone extends JPanel {

    private int yPos;

    public void setYPos(int yPos) {
        this.yPos = yPos;
        repaint();
    }

    public int getYPos() {
        return yPos;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); 

        g.setColor(Color.BLACK);
        int y = ((getHeight() / 2) - 90);
        int x = ((getWidth() / 2) - 45);
        g.drawRect(x, y, 90, 180);

        y = (getHeight() + getYPos()) / 2;
        //        y = (getHeight() / 2) + getYPos();
        g.setColor(getForeground());
        g.fillRect(x, y, 90, 12);

    }

}

public class Drone implements ActionListener {

    private int droneStatus;
    private MakeDrone levelBar;

    public Drone(MakeDrone levelBar) {
        this.levelBar = levelBar;
        levelBar.setForeground(Color.BLACK);
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if (droneStatus >= -85 && droneStatus <= 85) {
            droneStatus += getRandom();
            levelBar.setYPos(droneStatus);
            if (droneStatus < -40 && droneStatus > -85) {
                levelBar.setForeground(Color.ORANGE);
            }
            if (droneStatus < 85 && droneStatus > 40) {
                levelBar.setForeground(Color.ORANGE);
            }
            if (droneStatus <= 40 && droneStatus >= -40) {
                levelBar.setForeground(Color.BLACK);
            }
        } else {
            levelBar.setForeground(Color.RED);
            ((Timer) e.getSource()).stop();
        }
    }

}
}

Solution

  • Change the layout before you add the drones based on the number of columns you need...

    container.remove(howMany);
    container.setLayout(new GridLayout(1, numDrones));
    switch (numDrones){
        case 4:
        //...
    

    Don't forget, if you need to, you will need to reset the layout afterwards ;)

    Updated...

    The "other" problem is you're adding the instance of MakeDrone to the container. A instance of a component can only reside on a single parent, so effectively, you've only added DronePane once.

    Instead, you'll need to create a new instance of MakeDrone for each column. Try replacing your switch statement with something more like

    for (int index = 0; index < numDrones; index++) {
        MakeDrone md = new MakeDrone();
        Timer timer = new Timer(30, new Drone(md));
        container.add(md);
        timer.setInitialDelay(0);
        timer.start();
    }