I am using a card layout as a refreshing element on a JFrame and want to switch to a specific card after the user selects a button. Is there a way to call a specific card in the CardLayout on an action event?
public class ComboBoxTest() extends JFrame implements ActionListener {
JPanel comboBoxPane = new JPanel(); //use FlowLayout
JButton cb = new JButton("next");
cb.setActionCommand(next);
cb.addActionListener(this);
cb.setText("Forward");
this.add(cb);
comboBoxPane.add(cb);
JButton cb2 = new JButton("next");
cb2.setActionCommand(previous);
cb2.addActionListener(this);
cb2.setText("Back");
this.add(cb2);
comboBoxPane.add(cb2);
//Create the "cards".
card1 = new JPanel();
card1.add(HomeGui.getBody());
card2 = new JPanel();
card2.add(HomeGui.getSecondCard());
card3 = new JPanel();
card3.add(Start.getbody());
//Create the panel that contains the "cards".
cards = new JPanel(new CardLayout());
cards.add(card1, next);
cards.add(card2, previous);
Container base = getContentPane();
pane.add(header, BorderLayout.BEFORE_FIRST_LINE);
pane.add(comboBoxPane, BorderLayout.AFTER_LAST_LINE);
pane.add(cards);
}
public void actionPerformed(ActionEvent e) {
CardLayout c1 = (CardLayout)(cards.getLayout());
String button = e.getActionCommand();
if(button.equals(next)) {
c1.last(cards);
}
if(button.equals(previous)) {
c1.first(cards);
}
if(button.equals(card3)) {
//calls the third, specified card
}
}
}
You have to use show method of the CardLayout object
Related
I am learning Java creating small projects for fun. I am fairly new to it and easily stuck, hence the question I am asking.
I'm trying to create a simple Shopping Cart program, which in it's main panel has a 3x3 grid consisting of empty labels later
going to be replaced with images. And to the right of the grid there is four buttons, Add a Meal, Add a Drink, Total Price
and Clear All. So when either of the first two buttons are clicked, I want it to change the current panel to the panels corresponding to the button that was clicked.
The panel that is displayed then has data, like type of the food in a combobox which displays set food and quantity of the food.
Which then when the user chooses the type and quantity, presses the Add button, that would then change the panel
back to the main panel and the first empty label now has an image of the item that has been added to the cart.
This is all I currently know and as far as I can get.
Main class
public class ShoppingCart
{
public ShoppingCart()
{
JFrame app = new JFrame("Cart");
MainPanel main = new MainPanel();
app.add(main);
app.pack();
app.setResizable(false);
app.setLocationRelativeTo(null);
app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
app.setVisible(true);
}
public static void main(String[] args)
{
new ShoppingCart();
}
}
MainPanel class
public class MainPanel extends JPanel implements ActionListener
{
private final JLabel labels[] = new JLabel[9];
private final JButton button[] = new JButton[4];
public MainPanel()
{
String buttonText[] ={"Add a Meal", "Add a Drink", "Total Price", "Clear All"};
String buttonToolTipText[] =
{"This will add food", "This will add drink", "This will display the price", "Clear the cart"};
this.setLayout(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(4, 1, 2, 2));
for (int i = 0; i < 4; i++)
{
button[i] = new JButton(buttonText[i]);
button[i].setOpaque(true);
button[i].setBackground(Color.WHITE);
button[i].setFont(new Font("Ariel", Font.PLAIN, 18));
button[i].setPreferredSize(new Dimension(150,50));
button[i].setVisible(true);
button[i].setToolTipText(buttonToolTipText[i]);
button[i].addActionListener(this);
buttonPanel.add(button[i]);
}
JPanel labelPanel = new JPanel(new GridLayout(3, 3, 2, 2));
Border border = BorderFactory.createLineBorder(Color.GRAY);
for (int i = 0; i < 9; i++)
{
labels[i] = new JLabel();
labels[i].setOpaque(true);
labels[i].setVisible(true);
labels[i].setPreferredSize(new Dimension(100, 100));
labels[i].setBorder(border);
labels[i].setBackground(Color.WHITE);
labelPanel.add(labels[i]);
//set empty label to the image of the type chose,
//if right clicked, show type and quantity chosen
}
add(labelPanel, BorderLayout.WEST);
add(buttonPanel, BorderLayout.EAST);
}
#Override
public void actionPerformed(ActionEvent e)
{
if(button[0] == e.getSource())
{
//Change panel to Meal panel
}
if(button[1] == e.getSource())
{
//Change panel to Drink panel
}
if(button[2] == e.getSource())
{
//JOptionPane to show total price
}
if(button[3] == e.getSource())
{
//Check whether labels are empty, if not clear them else display message
}
}
}
MealPanel class
public class MealPanel extends JPanel implements ActionListener
{
public MealPanel()
{
this.setLayout(new BorderLayout());
JPanel titlePanel = new JPanel();
JPanel labelPanel = new JPanel(new GridLayout(2, 1, 3, 3));
JPanel inputField = new JPanel(new GridLayout(2, 1, 3, 3));
JPanel addCancel = new JPanel();
JLabel title = new JLabel("Add a Meal");
title.setBorder(BorderFactory.createMatteBorder(5,0,10,0, new Color(0,0,0,0)));
titlePanel.add(title);
JLabel type = new JLabel("Type:", JLabel.RIGHT);
labelPanel.add(type);
JLabel quantity = new JLabel("Quantity:", JLabel.RIGHT);
labelPanel.add(quantity);
final String arr[] = {"Burger", "Pizza"};
JComboBox mealType = new JComboBox(arr);
inputField.add(mealType);
JTextField quant = new JTextField();
inputField.add(quant);
JButton add = new JButton("Add");
add.addActionListener(this);
addCancel.add(add);
JButton cancel = new JButton("Cancel");
cancel.addActionListener(this);
addCancel.add(cancel);
add(titlePanel, BorderLayout.NORTH);
add(labelPanel, BorderLayout.WEST);
add(inputField, BorderLayout.EAST);
add(addCancel, BorderLayout.SOUTH);
}
#Override
public void actionPerformed(ActionEvent e)
{
//If cancel is pressed, return back to main, nothing changed on this panel
//else if add is pressed, set the type and quantity and return back to main
}
}
I guess what is shown, is I don't know how to specifically change the current panel to the panel chosen via which button is clicked. Then when the panel is shown, how to set the data then change the panel back to the MainPanel to then have that type of food displayed in the label as an image within the grid corresponding to the type that was chosen, so either a burger or pizza in the first empty label.
How would one go about doing the application?
There are 2 JPanels in my code. The first one is Furutsu7 which is the main JPanel which includes my game. The second JPanel is the start Jbutton. What I'm trying to accomplish is after the user clicks the Jbutton, the Furutsu7 JPanel will appear.
This is my setup class where I created the buttons.
public void setup(){
JFrame f = new JFrame("Start ");
JPanel card1 = new JPanel();
JPanel card2 = new JPanel();
cards = new JPanel(new CardLayout());
JButton Card1Button = new JButton("Start");
card1.add(Card1Button);
JButton Card2Button = new JButton("Exit");
card2.add(Card2Button);
cards.add(card1, "C1");
cards.add(card2, "C2");
f.add(cards, BorderLayout.CENTER);
f.setTitle("Furutsu");
f.setSize(500, 300);
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
What I need help on is what should I put in my action performed in order to switch to the Furutsu JPanel.
public void actionPerformed(ActionEvent e) {
}
Make your CardLayout a field of the class so that you can more easily get to it in your actionPerformed method. Otherwise you would need to call (CardLayout) cards.getLayout(), a riskier thing to do. For example:
public class MyClass implements ActionListener {
private CardLayout cardLayout = new CardLayout();
private JPanel cards = new JPanel(cardLayout);
public void setup(){
JFrame f = new JFrame("Start ");
JPanel card1 = new JPanel();
JPanel card2 = new JPanel();
// cards = new JPanel(new CardLayout());
JButton Card1Button = new JButton("Start");
card1.add(Card1Button);
JButton Card2Button = new JButton("Exit");
card2.add(Card2Button);
cards.add(card1, "C1");
cards.add(card2, "C2");
f.add(cards, BorderLayout.CENTER);
f.setTitle("Furutsu");
f.setSize(500, 300);
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
Then you can directly refer to it:
#Override
public void actionPerformed(ActionEvent e) {
// now you can call methods on your cardLayout variable:
cardLayout.show(...); // I'll leave it to you to figure out what to put in here
}
For more on CardLayout, please check out its tutorial
Note that if you just want to swap components in forward or backwards order, look at the other methods of CardLayout, such as next(cards) and previous(cards)
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 8 years ago.
The NullPointerException only comes about when I click the 'next' button.
I'm trying to get the frame to transition to another panel using cardlayout, but I have failed to do so.
Second question: How do I get my current panel to transition to the next panel (LoginPanel) in another class? I've already created an instance of it
public class InsuranceMain extends JFrame {
private CardLayout cardPanel;
private JPanel buttonPanel;
private JButton next;
private JLabel label;
public InsuranceMain() {
buttonPanel = new JPanel();
JPanel card1 = new JPanel();
JPanel cards = new JPanel(cardPanel);
LoginPanel loginPanelA = new LoginPanel(this);
CardLayout cardLayout = new CardLayout();
cards.setLayout(cardLayout);
next = new JButton("Next"); // Button
label = new JLabel("Test");
// Main frame settings
setTitle("Travel Insurance Application");
setSize(300, 300);
setLayout(new FlowLayout());
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel.add(next);
add(buttonPanel);
card1.add(label);
cards.add(card1, "card1");
cards.add(loginPanelA, "loginPanelA");
next.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(e.getSource() == next) {
cardLayout.show(cards, "loginPanelA");
}}
});
}
public static void main(String[] args) {
InsuranceMain test = new InsuranceMain();
}
}
Here's my LoginPanel code. I apologize if it's very disorganized
public class LoginPanel extends JPanel {
private JButton loginB, registerB, clearB;
private JTextField nricTextField, passwordTextField;
private JLabel nric, password, loginTitle;
private JPanel centerPanel, southPanel;
private InsuranceMain main;
public LoginPanel(InsuranceMain main){
this.main = main;
// JLabels
loginTitle = new JLabel("Insurance Login", JLabel.CENTER);
nric = new JLabel("NRIC: ");
password = new JLabel("Password: ");
// JTextField
nricTextField = new JTextField("");
passwordTextField = new JTextField("");
// JButton
loginB = new JButton("Login");
loginB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(e.getSource() == loginB) {
//cardLayout.show(cards, "card1");
}}
});
registerB = new JButton("Register");
clearB = new JButton("Clear");
// North Panel
setLayout(new BorderLayout()); // main panel's layout
add(loginTitle, BorderLayout.NORTH);
// Center Panel
centerPanel = new JPanel();
centerPanel.setLayout(new GridLayout(2,2));
centerPanel.add(nric);
centerPanel.add(nricTextField);
centerPanel.add(password);
centerPanel.add(passwordTextField);
add(centerPanel, BorderLayout.CENTER);
// South Panel
southPanel = new JPanel();
southPanel.setLayout(new FlowLayout());
southPanel.add(loginB);
southPanel.add(registerB);
southPanel.add(clearB);
add(southPanel, BorderLayout.SOUTH);
}
}
A NPE in the actionPerformed method can only be caused by cardLayout being null. So instead of
CardLayout cardLayout = (CardLayout) cards.getLayout(); // yields null
You should create the layout you need.
CardLayout cardLayout = new CardLayout();
See also
Cannot refer to a non-final variable inside an inner class defined in a different method
See also Erwin's comment.
//change to
final CardLayout cardLayout = new CardLayout();
final JPanel cards = new JPanel(cardPanel);
cards.setLayout(cardLayout);
You have to declare the variables final so you can refer to them from an anonymus inner class
new ActionListener() {}
Also use the naming convention of java for naming classes => start with capital letter i.e InsuranceMain, LoginPanel
im trying to to use cards layout, and i have 2 buttons at the the top that supoose to change the card but for some reason it wont work, the next method works but the show or first\last doesnt, ofcourse i cant use next, cause i want a specific card for every button, here is my code:
cards = new CardLayout();
cardPanel = new JPanel();
cardPanel.setLayout(cards);
cards.show(cardPanel, "gapas");
JPanel firstCard = new JPanel();
firstCard.setBackground(Color.WHITE);;
JPanel secondCard = new JPanel();
secondCard.setBackground(Color.blue);
cardPanel.add(firstCard, "kalam");
cardPanel.add(secondCard, "gapan");
guiFrame.add(tabsPanel,BorderLayout.NORTH);
guiFrame.add(cardPanel,BorderLayout.CENTER);
guiFrame.setVisible(true);
}
ActionListener action = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().matches("kalam")){
cards.show(cardPanel,"kalam");
System.out.println("kalam");
}
else{
cards.show(cardPanel, "gapas");
System.out.println("gapas");
}
}
};
I think you want something like this.
public class TestCard extends JFrame implements ActionListener {
CardLayout cards;
JPanel cardPanel, tabsPanel;
JButton b1, b2;
public TestCard() {
b1= new JButton("kalam");
b2= new JButton("gapas");
tabsPanel = new JPanel();
cards = new CardLayout();
cardPanel = new JPanel();
cardPanel.setLayout(cards);
JPanel firstCard = new JPanel();
firstCard.setBackground(Color.WHITE);
JPanel secondCard = new JPanel();
secondCard.setBackground(Color.blue);
cardPanel.add(firstCard, "kalam");
cardPanel.add(secondCard, "gapas");
tabsPanel.add(b1);
tabsPanel.add(b2);
add(tabsPanel, BorderLayout.NORTH);
add(cardPanel, BorderLayout.CENTER);
b1.addActionListener(this);
b2.addActionListener(this);
setSize(800, 600);
cards.show(cardPanel, "gapas");
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().matches("kalam")) {
cards.show(cardPanel, "kalam");
System.out.println("kalam");
} else {
cards.show(cardPanel, "gapas");
System.out.println("gapas");
}
}
public static void main(String[] args) {
new TestCard();
}
}
Documentation states:
show (Container parent, String name) Flips to the component that was added to this layout with the specified name, using the addLayoutComponent method.
You add two items:
kalam
gapan
but you try to show: gapas.
Additionally I would add first and then try 2 show.
I just started to learn swing by myself, I'm little bit confused why my event does not work here:
1.I'm trying to delete everything from my panel if the user click menu bar -> load but it force me to change the panel to final because i'm using it inside the event!
2.I have defined new panel in my event and defined two more container to add to that panel and then add it to the main frame but it seems nothing happening!
Please help me if you can find out what is wrong.
Sorry in advance for messy code.
I appreciate any hints.
public class SimpleBorder {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable()
{
public void run()
{
myFrame frame = new myFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class MyFrame extends JFrame {
public MyFrame()
{
setSize(500,500);
JPanel panel = new JPanel();
panel.setLayout(null);
JLabel label = new JLabel("my name is bernard...");
Color myColor = new Color(10, 150, 80);
panel.setBackground(myColor);
label.setFont(new Font("Serif", Font.PLAIN, 25));
Dimension size = label.getPreferredSize();
Insets insets = label.getInsets();
label.setBounds(85+insets.left, 120+insets.top , size.width, size.height);
panel.add(label);
JMenuBar menu = new JMenuBar();
setJMenuBar(menu);
JMenu col = new JMenu("Collection");
menu.add(col);
JMenu help = new JMenu("Help");
menu.add(help);
Action loadAction = new AbstractAction("Load")//menu item exit goes here
{
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent event)
{
JTextArea text = new JTextArea(10, 40);
JScrollPane scrol1 = new JScrollPane(text);
String[] items = {"A", "B", "C", "D"};
JList list = new JList(items);
JScrollPane scrol2 = new JScrollPane(list);
JPanel panel2 = new JPanel(new BorderLayout());
panel2 = new JPanel(new GridLayout(1, 2 ));
panel2.add(scrol1,BorderLayout.WEST);
panel2.add(scrol2,BorderLayout.EAST);
add(panel2);
}
};
JMenuItem load = new JMenuItem(loadAction);
col.add(load);
add(panel);
}
}
Call revalidate()/repaint() on your JFrame instance after adding the new panel:
JPanel panel2 = new JPanel(new BorderLayout());
// panel2 = new JPanel(new GridLayout(1, 2 ));//why this it will overwrite the above layout
panel2.add(scrol1,BorderLayout.WEST);
panel2.add(scrol2,BorderLayout.EAST);
add(panel2);
revalidate();
repaint();
Also call pack() on you JFrame instance so all components are spaced by the layoutmanager. As said in a comment dont extend the JFrame class, create a variable of the frame and initiate all that you need on the frames instance, and dont set a layout to null, unless you love hard work :P
Alternatively as mentioned by mKorbel, a CardLayout may be more what you want, it will allow you to use a single JPanel and switch between others/new ones:
JPanel cards;
final static String BUTTONPANEL = "Card with JButtons";
final static String TEXTPANEL = "Card with JTextField";
//Where the components controlled by the CardLayout are initialized:
//Create the "cards".
JPanel card1 = new JPanel();
...
JPanel card2 = new JPanel();
...
//Create the panel that contains the "cards".
cards = new JPanel(new CardLayout());
cards.add(card1, BUTTONPANEL);
cards.add(card2, TEXTPANEL);
//add card panel to frame
frame.add(cards);
//swap cards
CardLayout cl = (CardLayout)(cards.getLayout());//get layout of cards from card panel
cl.show(cards, TEXTPANEL);//show another card