2

I am trying to create a UI for an imaginary vehicle that has both Automatic and Manual modes. When the user sets the vehicle into one of the modes, it should only display the controls relevant to that mode, and I've accomplished this using a CardLayout.

However, I'd also like to be able to specify the location of the various elements of the layout for each card manually - for a static layout I'd do something along the lines of mainPanel.setLayout(null), but this simply gives a blank window when used on a CardLayout (hence the two commented-out lines in the code below).

How would I achieve both of these things? My current code is below:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class UI extends JFrame implements ActionListener{

public UI() {
    initUI();
}

private JPanel cardPanel;
private CardLayout cardLayout = new CardLayout();

public final void initUI() {

    cardPanel = new JPanel();
    cardPanel.setLayout(cardLayout);

    JPanel manualPanel = new JPanel();
    getContentPane().add(manualPanel);
    //manualPanel.setLayout(null);
    cardPanel.add(manualPanel, "manual");

    JPanel autoPanel = new JPanel();
    //autoPanel.setLayout(null);
    cardPanel.add(autoPanel, "auto");

    JButton startButton = new JButton("START/STOP");
    startButton.setBounds(50, 150, 200, 50);
    startButton.addActionListener(new startListener());
    manualPanel.add(startButton);
    autoPanel.add(startButton);

    JButton autoButton = new JButton("SWITCH TO AUTO");
    autoButton.setBounds(50, 250, 200, 50);
    autoButton.addActionListener(new autoListener());
    manualPanel.add(autoButton);

    JButton upButton = new JButton("^");
    upButton.setBounds(125, 320, 50, 50);
    upButton.addActionListener(new returnListener());
    manualPanel.add(upButton);

    JButton downButton = new JButton("\\/");
    downButton.setBounds(125, 380, 50, 50);
    downButton.addActionListener(new returnListener());
    manualPanel.add(downButton);

    JButton ccwButton = new JButton("<-");
    ccwButton.setBounds(55, 350, 50, 50);
    ccwButton.addActionListener(new returnListener());
    manualPanel.add(ccwButton);

    JButton cwButton = new JButton("->");
    cwButton.setBounds(195, 350, 50, 50);
    cwButton.addActionListener(new returnListener());
    manualPanel.add(cwButton);

    JButton ngzButton = new JButton("SOMETHING ELSE");
    ngzButton.setBounds(50, 450, 200, 50);
    ngzButton.addActionListener(new returnListener());
    manualPanel.add(ngzButton);

    JButton manualButton = new JButton("SWITCH TO MANUAL");
    manualButton.setBounds(50, 250, 200, 50);
    manualButton.addActionListener(new manualListener());
    autoPanel.add(manualButton);

    JButton returnButton = new JButton("SOMETHING ELSE");
    returnButton.setBounds(50, 350, 200, 50);
    returnButton.addActionListener(new returnListener());
    autoPanel.add(returnButton);

    setTitle("UI");
    setSize(800, 600);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    add(cardPanel, BorderLayout.NORTH);
}

public static void main(String[] args) {

    UI ui = new UI();
    ui.setVisible(true);
}

public void actionPerformed(ActionEvent e){
}

private class returnListener implements ActionListener {
    public void actionPerformed (ActionEvent event) {
    }
}

private class autoListener implements ActionListener {
    public void actionPerformed (ActionEvent event) {
        cardLayout.show(cardPanel, "auto");
    }
}

private class startListener implements ActionListener {
    public void actionPerformed (ActionEvent event) {
    }
}

private class manualListener implements ActionListener {
    public void actionPerformed (ActionEvent event) {
        cardLayout.show(cardPanel, "manual");
    }
}


}
DTR
  • 372
  • 6
  • 22

1 Answers1

3

In your example, you create a startButton, but you then attempt to add the same instance to two different panels. Because a component can only occupy one container, you'll need to create two buttons, one for each panel.

As an aside, instead of using a null layout, give each panel BorderLayout, add the buttons to a JPanel having the default FlowLayout, and add the button panel to the SOUTH. You can then nest your illustrations in the CENTER using whatever layout is appropriate.

Addendum: As @Frakcool comments, using a layout will improve the cross-platform appearance of your buttons. Invoke pack() on the enclosing window, and override getPreferredSize() on the nested illustration panel to give it the needed size. In this related example, the CENTER panel is used for drawing only; having no components, its layout then becomes irrelevant.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thanks for pointing that out, but it doesn't solve the main problem. For example, deleting the line `autoPanel.add(startButton);` for now still wont get the elements to respect the `setBounds()` - the UI either ignores the bounds with the code as-is, or shows a blank window if the two commented lined are uncommented. – DTR Aug 21 '15 at 18:28
  • 3
    @DTR `setBounds()` method stands for a `null` layout which isn't the best option to create an application due it can generate visual bugs because of different platforms / screen resolutions, etc. Instead use a [Layout Manager](https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html) as trashgod already stated with a `BorderLayout` That way your code should work fine. I could try helping with it once I'm at home in 6 more hours if you haven't solved it yet. – Frakcool Aug 21 '15 at 18:43
  • 1
    Try the layouts suggested and invoke `pack()`; override [`getPreferredSize()`](http://stackoverflow.com/q/7229226/230513) on the nested illustration panel to give it the size need to hold your illustration(s). – trashgod Aug 21 '15 at 18:45
  • 1
    In this related [example](http://stackoverflow.com/a/18025684/230513), the `CENTER` panel is used for drawing only; having no components, it's layout is irrelevant. – trashgod Aug 21 '15 at 18:55
  • I'm glad it helped! :) Good luck then – Frakcool Aug 21 '15 at 19:54