wrong parent for CardLayout in java - java

I want to change cards in my CardLayout (which contains labels) for every choice in my combo box. So when I select Item2 in the combo box it should show the second card but it returns error instead.
Inside the method initComponents() I successfully showed the first card using cardLayout.show(imagePanel, "1"); but when I tried to do the same inside private void comboMenuActionPerformed(), it returns the error "IllegalArgumentException: wrong parent for CardLayout". Why is this happening?
public class MyFrame extends JFrame {
public MyFrame() {
initComponents();
}
private void initComponents() {
cardLayout = new java.awt.CardLayout();
mainPanel = new javax.swing.JPanel();
centerPanel = new javax.swing.JPanel();
imagePanel = new javax.swing.JPanel(cardLayout);
comboMenu = new javax.swing.JComboBox<>();
JLabel firstPicture = new JLabel("");
JLabel secondPicture = new JLabel("");
...
firstPicture.setIcon(...);
secondPicture.setIcon(...);
imagePanel.add(firstPicture, "1");
imagePanel.add(secondPicture, "2");
String[] menu = {"Item1", "Item2", "Item3"};
cardLayout.show(imagePanel, "1"); //this works fine
imagePanel.setLayout(new java.awt.CardLayout());
centerPanel.add(imagePanel);
comboMenu.setModel(new javax.swing.DefaultComboBoxModel<>(menu));
mainPanel.add(centerPanel);
}
private void comboMenuActionPerformed(java.awt.event.ActionEvent evt) {
if(comboMenu.getSelectedItem().toString().equals("Item2")) {
cardLayout.show(imagePanel, "2"); //WHY THIS DOESN'T WORK
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MyFrame().setVisible(true);
}
});
}
private javax.swing.JComboBox<String> comboMenu;
private javax.swing.JPanel centerPanel;
private javax.swing.JPanel imagePanel;
private javax.swing.JPanel mainPanel;
private java.awt.CardLayout cardLayout;
}

imagePanel = new javax.swing.JPanel(cardLayout);
...
cardLayout.show(imagePanel, "1"); //this works fine
imagePanel.setLayout(new java.awt.CardLayout());
You replace the layout of the image panel with a new instance of the CardLayout. Get rid of the last statement:
//imagePanel.setLayout(new java.awt.CardLayout());

You assign the card layout to imagePanel by:
imagePanel = new javax.swing.JPanel(cardLayout);
But then you assign a new card layout by:
imagePanel.setLayout(new java.awt.CardLayout());
This overwrites the first card layout to which you added the labels.

Related

Java Swing- Panel not appearing in frame

I am new to swing and am wondering why my login panel isn't appearing in the frame. I believe it should show on the left side of the frame, is this correct? What needs to be changed to make the panel appear. Thanks.
Here is the GUIFrame code
public class GUIFrame extends JFrame {
private static final long serialVersionUID = 1L;
public GUIFrame(){
Container container = getContentPane();
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screenDimension = toolkit.getScreenSize();
setSize(screenDimension.width/2, screenDimension.height/2);
setLocation(screenDimension.width/4,screenDimension.height/4);
setLayout(new GridLayout(1,2));
add(new Login(this));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
Here is the panels code:
public class Login extends JPanel {
private JPanel panel = new JPanel();
private JButton cancel = new JButton("Cancel");
private JButton submit = new JButton("Submit");
private JLabel username_label = new JLabel("Username :");
private JLabel password_label = new JLabel("Password :");
private JTextField username_text = new JTextField();
private JPasswordField password_text = new JPasswordField();
private GUIFrame frame;
public Login(GUIFrame frame){
this.frame = frame;
setLayout(new GridLayout(3,2,20,40));
addComponents();
}
public void addComponents(){
panel.add(username_label);
panel.add(username_text);
panel.add(password_label);
panel.add(password_text);
panel.add(cancel);
panel.add(submit);
}
}
Here is the main method which displays the frame:
public class Project {
public static void main(String[] args){
Project project = new Project();
}
public Project() {
//Login login = new Login();
GUIFrame frame = new GUIFrame();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
}
}
panel.add(username_label);
panel.add(username_text);
panel.add(password_label);
panel.add(password_text);
panel.add(cancel);
panel.add(submit);
You create a separate JPanel and add the component to this panel, but you never add the panel to your Login panel.
Your Login panel already is a JPanel, so there is no need to create another JPanel.
The code should just be:
add(username_label);
add(username_text);
add(password_label);
add(password_text);
add(cancel);
add(submit);
There is also no reason to pass the JFrame as a parameter to your Login class.
Also, you are using the invokeLater() incorrectly. All Swing components should be created on the Event Dispatch Thread (EDT). So you should also include the new GuiFrame() inside the invokeLater().
Generally there is no need to have a separate JFrame class. The logic in your Project class should simply create an instance of the frame and add the Login panel to the frame. In other words don't extend JFrame.

How to add back and next button for CardLayout?

I want to add a 'back' and 'next' button for my gui but it doesn't seem to work. It feels like I'm missing something important in my code. I tried using cl.next(ImagePanel); but the method is not working for some reason.
private void initComponents() {
mainPanel = new javax.swing.JPanel();
cardLayout = new java.awt.CardLayout();
imagePanel = new javax.swing.JPanel(cardLayout);
JLabel firstPicture = new JLabel("");
JLabel secondPicture = new JLabel("");
jButton back = new jButton("\u22b2Back");
jButton next = new jButton("Next\u22b3");
firstPicture.setIcon(...);
secondPicture.setIcon(...);
imagePanel.add(firstPicture, "1");
imagePanel.add(secondPicture, "2");
cardLayout.show(imagePanel, "1");
//...buttons actionPerformed(evt);
mainPanel.add(imagePanel);
}
private void backActionPerformed(java.awt.event.ActionEvent evt) {
CardLayout cl = (CardLayout) imagePanel.getLayout();
cl.previous(imagePanel); //should proceed to the previous image... not working
}
private void nextActionPerformed(java.awt.event.ActionEvent evt) {
CardLayout cl = (CardLayout) imagePanel.getLayout();
cl.next(imagePanel); //should proceed to the next image... not working
}

Dynamic JPanels error

I hava CardLayout and want to have changing panels on it. For that I wrote my JFrame Class:
public class GUI_NewList extends javax.swing.JFrame {
CardLayout layout = new CardLayout();
public GUI_NewList() {
initComponents();
this.setLayout(layout);
JPanel paChoose = new Choose();
layout.addLayoutComponent(paChoose, "1");
layout.show(paChoose, "1");
}
The class Choose:
public class Choose extends JPanel {
public Choose() {
setLayout(new GridLayout(3, 1));
JButton btnPractice = new JButton("Practice");
add(btnPractice);
JButton btnNewList = new JButton("Create a new List");
add(btnNewList);
JButton btnEditList = new JButton("Edit a List");
add(btnEditList);
}
}
If I run this I get an error:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: wrong parent for CardLayout
Could you please tell me what I have done wrong?
Here is an MCVE that fixes the problem. See code comments for details of the problem(s).
import java.awt.*;
import javax.swing.*;
public class GUI_NewList extends JFrame {
CardLayout layout = new CardLayout();
public GUI_NewList() {
this.setLayout(layout);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel paChoose = new Choose();
// this only adds it to the layout, not the container.
layout.addLayoutComponent(paChoose, "1");
// this adds it to the container (the content pane)
add(paChoose);
// the container of interest is the content pane.
layout.show(this.getContentPane(), "1");
pack();
setVisible(true);
}
public static void main(String[] args) {
Runnable r = () -> {
new GUI_NewList();
};
SwingUtilities.invokeLater(r);
}
}
class Choose extends JPanel {
public Choose() {
setLayout(new GridLayout(3, 1));
JButton btnPractice = new JButton("Practice");
add(btnPractice);
JButton btnNewList = new JButton("Create a new List");
add(btnNewList);
JButton btnEditList = new JButton("Edit a List");
add(btnEditList);
}
}
Note: There is no good case here for extending either JFrame or JPanel.

Implementing CardLayout within a JFrame and switching cards based on specific button presses

I've posted my code below. I have the simple task of creating a navigable GUI. I've spent the past few hours doing research on how to accomplish this, and this is the code that I've put together.
Originally I wanted to perform the navigation without any layouts or anything. I need the home panel to display after the user clicks on the "login" button on the welcome panel.
It displays the welcome card just fine, but when I get to the validateLogin method(which is activated when the login button is press, and upon successful login it should show the home panel within cards) it simply stays on the welcome panel even though I have validated that my program reaches the loop to change cards via the system.out.Println()
Please help. I spent my entire Saturday trying to solve this one problem through trials and research, but with no success. This is a last resort for me so if anyone can show me my flaws then I'll happily be on my way and fix it. Then apply that fix to the many other cards that are required for my program.
enter code here
public class mainGUI implements ActionListener{
JFrame main;
JPanel cards = new JPanel(new CardLayout());
CardLayout cl = (CardLayout)(cards.getLayout());
//Items for the welcome panel
JPanel welcome = welcomePanel();
JButton login;
JButton register;
JTextField username;
JTextField password;
//home panel
JPanel home = homePanel();
//WelcomePanel welcome = new WelcomePanel();
ArrayList<Student> students = new ArrayList<Student>();
Student workingStudent;
/**
* calls load() at start and save() on exit
*
*/
public mainGUI(){
load();
main = new JFrame();
main.setSize(900, 600);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setTitle("MyCourses 2k16");
main.setContentPane(welcomePanel());
//fill out the cards
cards.add(welcome, "Welcome");
cards.add(home, "Home");
//display welcome card
cl.show(cards, "welcome");
main.setVisible(true);
saveState();
}
private JPanel welcomePanel() {
JPanel welcome = new JPanel();
welcome.setLayout(null);
welcome.setBackground(Color.DARK_GRAY);
JLabel hi = new JLabel("Welcome to MyCourses 2K16");
hi.setSize(800, 100);
hi.setLocation(50,50);
hi.setFont(new Font("Serif", Font.BOLD, 48));
hi.setForeground(Color.WHITE);
JLabel select = new JLabel("Fill in the information, then click login or register to proceed, no special characters allowed");
select.setSize(700,100);
select.setLocation(75,100);
select.setFont(new Font("Serif", Font.PLAIN, 18));
select.setForeground(Color.WHITE);
login = new JButton( "login");
login.setSize(100, 50);
login.setLocation(50, 200);
login.addActionListener(this);
register = new JButton( "register");
register.setSize(100,50);
register.setLocation(200, 200);
register.addActionListener(this);
JLabel un = new JLabel("username");
un.setSize(100, 30);
un.setLocation(50, 270);
un.setForeground(Color.WHITE);
username = new JTextField();
username.setSize(200, 30);
username.setLocation(50,300);
JLabel pw = new JLabel("password");
pw.setSize(100, 30);
pw.setLocation(50, 350);
pw.setForeground(Color.WHITE);
password = new JTextField();
password.setSize(200, 30);
password.setLocation(50,380);
welcome.add(hi);
welcome.add(select);
welcome.add(login);
welcome.add(register);
welcome.add(un);
welcome.add(username);
welcome.add(pw);
welcome.add(password);
return welcome;
}
private JPanel homePanel() {
JPanel home = new JPanel();
home.setLayout(null);
home.setBackground(Color.DARK_GRAY);
JLabel hi = new JLabel("HOME");
hi.setSize(800, 100);
hi.setLocation(50,50);
hi.setFont(new Font("Serif", Font.BOLD, 48));
hi.setForeground(Color.WHITE);
return home;
}
public void load(){
}
private void saveState(){
Iterator<Student> it = students.iterator();
while(it.hasNext()){
it.next().saveStudent();
}
}
public static void main(String[] args) {
new mainGUI();
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource()==login){
System.out.println("Logging in...");
validateLogin(students);
}
else if (e.getSource()==register){
}
}
private void validateLogin(ArrayList<Student> students){
boolean valid = false;
for(int i = 0; i < students.size(); i++){
if(username.getText().equals(students.get(i).getUsername())
&& password.getText().equals(students.get(i).getPassword()))
{
valid = true;
workingStudent=(students.get(i));
System.out.println("Successful Login!");
cl.show(cards, "home");
}
}
if(valid == false){
System.out.println("Invalid Login, try again");
}
}
}
You create a JPanel that uses CardLayout, cards, but you add it to nothing, so it will of course not display itself, nor its cards. Solution: add this JPanel to your GUI.
So instead of:
main.setContentPane(welcomePanel());
do:
main.setContentPane(cards);
Issue number 2:
Use String constants when using Strings as a type of key. Note that you add one JPanel to the cards JPanel thusly:
cards.add(home, "Home");
But then try to display it like so:
cl.show(cards, "home");
But Home isn't the same as home.
Instead declare a constant, HOME:
public static final String HOME = "home";
and use the same constant to add the JPanel and to display it.
For a simplistic example:
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class MainGui2 extends JPanel {
private CardLayout cardLayout = new CardLayout();
private WelcomePanel welcomePanel = new WelcomePanel(this);
private HomePanel homePanel = new HomePanel();
public MainGui2() {
setLayout(cardLayout);
add(welcomePanel, WelcomePanel.NAME);
add(homePanel, HomePanel.NAME);
}
public void showCard(String name) {
cardLayout.show(this, name);
}
private static void createAndShowGui() {
MainGui2 mainPanel = new MainGui2();
JFrame frame = new JFrame("MainGui2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class WelcomePanel extends JPanel {
public static final String NAME = "welcome panel";
private MainGui2 mainGui2;
public WelcomePanel(final MainGui2 mainGui2) {
this.mainGui2 = mainGui2;
add(new JLabel(NAME));
add(new JButton(new AbstractAction("Logon") {
#Override
public void actionPerformed(ActionEvent e) {
mainGui2.showCard(HomePanel.NAME);
}
}));
}
}
class HomePanel extends JPanel {
public static final String NAME = "home panel";
public HomePanel() {
add(new JLabel(NAME));
}
}

CardLayout (swing) with action listeners on buttons?

I've been trying to figure out CardLayout with action listeners on button
(so like - starts on a load-up page- and on a button click switches to a different "card"
my code won't even run right now i'm not entirely sure why - most implementations I can find use ItemListeners and Combo Boxes
The basic process I've done is create a master JPanel, but my cards JPanel onto the master JPanel, but my different cards into the cards JPanel, then add the master JPanel to the frame to display...
Also, for one of my cards I only need to display a picture - I previously implemented this by just creating a new pop-up window but It would be nice to be able to switch the frame to show it... I don't know why I can't figure this out
Here's my code:
import java.awt.*;
/**
* Game
* Main class that specifies the frame and widgets of the GUI
*/
public class Game implements Runnable {
public void run(){
final String ON_OPEN = "Welcome!"; //Opening frame
final String GAME = "Play!"; // Game Frame
final String STATS = "Stats"; // Post-Game Stat Frame
final String HELP = "Help"; //tutorial frame
JPanel cards = new JPanel();
JPanel master; // a panel for the card layout
final JFrame frame = new JFrame(ON_OPEN);
frame.setLocation(500,200);
//Create the master layout for the program
master = (JPanel) frame.getContentPane();
master.setLayout(new BorderLayout()); // creating master layout
//Create panel for all the cards in CardLayout
final CardLayout cLay = new CardLayout();
cards.setLayout(cLay);
// all the cards
final JPanel help = new JPanel();
final JPanel stats = new JPanel();
final JPanel game = new JPanel (new BorderLayout());
final JPanel open = new JPanel (new FlowLayout());
// setting up ON_OPEN layout - uses JPanel open
final ImageIcon img = new ImageIcon("Instructions.png", "My Instructions..."); // the image I want shown under HELP card
final JButton info = new JButton("Help");
info.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// cLay.show(help, HELP); // WHAT I NORMALLY SHOULD BE DOING, RATHER JUST MAKE A NEW FRAME FOR THIS THOUGH
// frame.pack();
final JFrame infoFrame = new JFrame("Tutorial");
infoFrame.setLocation(500,50);
JLabel tutorialImg = new JLabel(img);
// int w = img.getIconWidth();
// int h = img.getIconHeight();
//infoFrame.setSize(w, h);
infoFrame.pack();
infoFrame.add(tutorialImg);
infoFrame.setVisible(true);
}
});
open.add(info); // the open-tutorial button
//Add them to the cards JPanel
cards.add(open, ON_OPEN);
cards.add(help, HELP);
cards.add(stats, STATS);
cards.add(game, GAME);
//Add the cards panel to the Master layout panel
master.add(cards);
// This code is all commented out because I'm not sure what I'm doing here...
// frame.add(cards);
// cLay.show(cards, ON_OPEN);
// frame.add(open, BorderLayout.CENTER);
// Main playing area - I want this to be shown in the GAME card...
GridLayout tileGrid = new GridLayout(4,4);
final JPanel grid = new JPanel(tileGrid);
// game.add(grid, BorderLayout.CENTER);
// grid.setLayout(tileGrid);
// frame.add(grid, BorderLayout.CENTER);
// Input - holds typing box
// final JPanel status_panel = new JPanel();
// frame.add(cards, BorderLayout.CENTER);
// frame.add(open, BorderLayout.CENTER);
final JTextField typingArea = new JTextField();
typingArea.setFocusTraversalKeysEnabled(false);
typingArea.setEditable(true);
typingArea.setFocusable(true);
typingArea.requestFocus();
frame.add(typingArea, BorderLayout.SOUTH);
typingArea.addKeyListener(new KeyAdapter() {
public void keyPressed (KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) { // enter key is pressed
String userWord = typingArea.getText().toLowerCase();
typingArea.setText("");
}
}
});
final JLabel status = new JLabel("Running...");
// status_panel.add(status);
// Reset button
final JPanel control_panel = new JPanel();
frame.add(control_panel, BorderLayout.NORTH);
]
// Put the frame on the screen
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Game());
}
}
Problems:
Your code doesn't compile for us since we don't have the JLetterField class.
You're trying to add the JFrame's contentPane back on itself, and causes an exception and doesn't make sense.
Edit 1:
Your latest code shows you putting everything into one very large run() method but in doing so, you loose much and gain nothing.
I suggest getting rid of the Runnable interface, there's no need for it, and creating a true OOP compliant class, one with private fields and public and private methods.
Your actionPerformed method shows no attempt at changing the CardLayout's displayed card.
I suggest that you get rid of the code to show a new window and try to place card swapping code there.
Make your CardLayout and the card-displaying JPanel fields of the class so that other methods can access them and call their methods.
Edit 2:
For example the following code shows the swapping of cards using 3 JButtons. One to get the previous card, one to get the next card, and one to show how to get a specific card (here the 2nd):
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class CardLayoutEg extends JPanel {
private static final String[] CARD_LABELS = { "one", "two", "three", "four",
"five", "six", "seven", "eight", "nine", "ten" };
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private CardLayout cardlayout = new CardLayout();
private JPanel cardHolder = new JPanel(cardlayout);
private Action[] actions = { new ShowPreviousAction(), new ShowNextAction(),
new ShowTwoCardAction() };
public CardLayoutEg() {
for (String cardLabelText : CARD_LABELS) {
JLabel cardLabel = new JLabel(cardLabelText, SwingConstants.CENTER);
cardHolder.add(cardLabel, cardLabelText);
}
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0));
for (Action action : actions) {
btnPanel.add(new JButton(action));
}
setLayout(new BorderLayout());
add(cardHolder, BorderLayout.CENTER);
add(btnPanel, BorderLayout.SOUTH);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class ShowPreviousAction extends AbstractAction {
public ShowPreviousAction() {
super("Previous");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.previous(cardHolder);
}
}
private class ShowNextAction extends AbstractAction {
public ShowNextAction() {
super("Next");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.next(cardHolder);
}
}
private class ShowTwoCardAction extends AbstractAction {
public ShowTwoCardAction() {
super("Show Two");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cardHolder, CARD_LABELS[1]);
}
}
private static void createAndShowGui() {
CardLayoutEg mainPanel = new CardLayoutEg();
JFrame frame = new JFrame("CardLayout Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories