5

Well I'm having some troubles by making a CardLayout with different sizes on each card.

After reading The Use of Multiple JFrames: Good or Bad Practice? I noticed I was doing things in a way that is not the apropiate, so I decided to start learning how to use CardLayout

I have tried this answer from @HovercraftFullOfEels

This one from @mKorbel

And finally the answer of @Kleopatra

All of them are based on Hovercraft's answer but with some changes. I was able to create the CardLayout (and still confused about it), and I (in some way) could implement Kleopatra's method, it resizes the frame but not as it should, when copy and pasting the code, you will notice it reduces frame's size just a couple of milimeters (or pixels).

I'm not sure if this is about the Layout managers that I'm using or it is because of I'm not using Kleopatra's methods in the correct way since I also don't know how @Override method works at all or when to use it and when not.

Here's an MCVE (the shortest I could made).

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;

public class PageViewer extends CardLayout{ 
    private static final String loginCard = "login";
    private static final String userCard = "createUser";

    JFrame frame;
    JPanel contentPane;
    CardLayout cardLayout;

    @Override
    public Dimension preferredLayoutSize(Container parent) {
        Component current = findCurrentComponent(parent);
        if (current != null) {
            Insets insets = parent.getInsets();
            Dimension pref = current.getPreferredSize();
            pref.width += insets.left + insets.right;
            pref.height += insets.top + insets.bottom;
            return pref;
        }
        return super.preferredLayoutSize(parent);
    }

    public Component findCurrentComponent(Container parent) {
        for (Component comp : parent.getComponents()) {
            if (comp.isVisible()) {
                return comp;
            }
        }
        return null;
    }

    public void createAndShowUI() {
        frame = new JFrame("Welcome");
        cardLayout = new CardLayout();
        contentPane = new JPanel(cardLayout);

        LoginPage lp = new LoginPage();
        CreateUser cu = new CreateUser();

        lp.register.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e){
                createNewUser();
                frame.pack();
            }
        });

        contentPane.add(lp, loginCard);
        contentPane.add(cu, userCard);

        frame.add(contentPane, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(150, 150);
        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);
    }

    PageViewer() {
        createAndShowUI();
    }

    public void createNewUser() {
        cardLayout.show(contentPane, userCard);
    }

    public static void main(String[] args) {
        new PageViewer();
    }

    public class LoginPage extends JPanel {
        Image image;
        ImageIcon imageIcon;

        JPanel userPanel;
        JPanel passwordPanel;
        JPanel buttonsPanel;
        JPanel fieldsPanel;

        JFrame frame;

        JLabel usernameLabel;
        JLabel passwordLabel;
        JLabel logo;

        JTextField usernameField;
        JPasswordField passwordField;

        JButton login;
        JButton register;

        public LoginPage() {
            image = Toolkit.getDefaultToolkit().getImage("image.jpg");
            imageIcon = new ImageIcon("image.jpg");

            userPanel = new JPanel();
            passwordPanel = new JPanel();
            buttonsPanel = new JPanel();
            fieldsPanel = new JPanel();

            usernameLabel = new JLabel("username:");
            passwordLabel = new JLabel("password:");
            logo = new JLabel(imageIcon);

            usernameField = new JTextField();
            passwordField = new JPasswordField();

            login = new JButton("Login");
            register = new JButton("Register");

            this.setLayout(new BorderLayout(10, 15));
            this.setBorder(new EmptyBorder(10, 10, 10, 10));
            fieldsPanel.setLayout(new BorderLayout());

            usernameField.setColumns(8);
            passwordField.setColumns(8);

            userPanel.add(usernameLabel);
            userPanel.add(usernameField);

            passwordPanel.add(passwordLabel);
            passwordPanel.add(passwordField);

            fieldsPanel.add(userPanel, BorderLayout.CENTER);
            fieldsPanel.add(passwordPanel, BorderLayout.SOUTH);

            buttonsPanel.add(login);
            buttonsPanel.add(register);

            this.add(logo, BorderLayout.NORTH);
            this.add(fieldsPanel, BorderLayout.CENTER);
            this.add(buttonsPanel, BorderLayout.SOUTH);
        }
    }
    public class CreateUser extends JPanel {
        JPanel userPanel;
        JPanel passPanel;
        JPanel repPassPanel;
        JPanel buttonsPanel;
        JPanel fieldsPanel;

        JLabel username;
        JLabel password;
        JLabel repPassword;

        JTextField userField;
        JPasswordField passField;
        JPasswordField repPassField;

        JButton acceptButton;
        JButton cancelButton;

        public CreateUser() {

            userPanel = new JPanel();
            passPanel = new JPanel();
            repPassPanel = new JPanel();
            buttonsPanel = new JPanel();
            fieldsPanel = new JPanel();

            username = new JLabel("username: ");
            password = new JLabel("password: ");
            repPassword = new JLabel("repeat password: ");

            userField = new JTextField();
            passField = new JPasswordField();
            repPassField = new JPasswordField();

            acceptButton = new JButton("Accept");
            cancelButton = new JButton("Cancel");

            userField.setColumns(8);
            passField.setColumns(8);
            repPassField.setColumns(8);

            userPanel.add(username);
            userPanel.add(userField);

            passPanel.add(password);
            passPanel.add(passField);

            repPassPanel.add(repPassword);
            repPassPanel.add(repPassField);

            buttonsPanel.add(acceptButton);
            buttonsPanel.add(cancelButton);

            fieldsPanel.setLayout(new BoxLayout(fieldsPanel, BoxLayout.Y_AXIS));

            this.setLayout(new BorderLayout(10, 15));
            this.setBorder(new EmptyBorder(10, 10, 10, 10));

            fieldsPanel.add(userPanel);
            fieldsPanel.add(passPanel);
            fieldsPanel.add(repPassPanel);

            this.add(fieldsPanel, BorderLayout.CENTER);
            this.add(buttonsPanel, BorderLayout.SOUTH);
        }
    }
}

So, resuming (and added some more questions that came to my mind while doing the MCVE):

  1. Why the frame isn't resizing as expected?
  2. Am I using the correct Layout managers?
  3. Is my lp.register.addActionListener(... or am I doing it so difficult?

Thanks in advance :)

Community
  • 1
  • 1
Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • Try reversing the calls `frame.pack();`, `frame.setResizable(false);`, so that `setResizable` is called first...There's no need to extend `CardLayout` – MadProgrammer May 27 '14 at 05:32
  • @MadProgrammer ok I'll make it and go back with results, btw I extend it just to be able to use Kleopatra's methods because I wasn't able to call it's super method. But thanks for that advice. – Frakcool May 27 '14 at 05:36
  • @MadProgrammer even by doing that reverse of the calls still don't solve the issue. – Frakcool May 27 '14 at 05:37
  • You do realsie that you're not actually using the `PageViewer` layout at call, so the `preferredLayoutSize` isn't been called – MadProgrammer May 27 '14 at 05:42

1 Answers1

5

Switch the pack and setResizable calls. setResizable will change the border size of the frame on some systems, so instead of

frame.setResizable(false);
frame.pack();

You should be using...

frame.pack();
frame.setResizable(false);

An example of the difference between the calls...

Resizebale

You may also want to actually make use of the PageViewer layout manager...

cardLayout = new PageViewer();

Now, the UI shouldn't be wrapped up in the layout manager like you have it, they should be separated, for example...

CardLayout

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class CardLayoutTest {

    private static final String loginCard = "login";
    private static final String userCard = "createUser";

    private JFrame frame;
    private CardLayout cardLayout;
    private JPanel contentPane;

    public static void main(String[] args) {
        new CardLayoutTest();
    }

    public CardLayoutTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                createAndShowUI();
            }
        });
    }

    public void createAndShowUI() {
        frame = new JFrame("Welcome");
        cardLayout = new PageViewer();
        contentPane = new JPanel(cardLayout);

        LoginPage lp = new LoginPage();
        CreateUser cu = new CreateUser();

        lp.register.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                createNewUser();
                frame.pack();
            }
        });

        contentPane.add(lp, loginCard);
        contentPane.add(cu, userCard);

        frame.add(contentPane, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(150, 150);
        frame.setResizable(false);
        frame.pack();
        frame.setVisible(true);
    }

    public void createNewUser() {
        cardLayout.show(contentPane, userCard);
    }

    public class LoginPage extends JPanel {

        Image image;
        ImageIcon imageIcon;

        JPanel userPanel;
        JPanel passwordPanel;
        JPanel buttonsPanel;
        JPanel fieldsPanel;

        JFrame frame;

        JLabel usernameLabel;
        JLabel passwordLabel;
        JLabel logo;

        JTextField usernameField;
        JPasswordField passwordField;

        JButton login;
        JButton register;

        public LoginPage() {
            image = Toolkit.getDefaultToolkit().getImage("image.jpg");
            imageIcon = new ImageIcon("image.jpg");

            userPanel = new JPanel();
            passwordPanel = new JPanel();
            buttonsPanel = new JPanel();
            fieldsPanel = new JPanel();

            usernameLabel = new JLabel("username:");
            passwordLabel = new JLabel("password:");
            logo = new JLabel(imageIcon);

            usernameField = new JTextField();
            passwordField = new JPasswordField();

            login = new JButton("Login");
            register = new JButton("Register");

            this.setLayout(new BorderLayout(10, 15));
            this.setBorder(new EmptyBorder(10, 10, 10, 10));
            fieldsPanel.setLayout(new BorderLayout());

            usernameField.setColumns(8);
            passwordField.setColumns(8);

            userPanel.add(usernameLabel);
            userPanel.add(usernameField);

            passwordPanel.add(passwordLabel);
            passwordPanel.add(passwordField);

            fieldsPanel.add(userPanel, BorderLayout.CENTER);
            fieldsPanel.add(passwordPanel, BorderLayout.SOUTH);

            buttonsPanel.add(login);
            buttonsPanel.add(register);

            this.add(logo, BorderLayout.NORTH);
            this.add(fieldsPanel, BorderLayout.CENTER);
            this.add(buttonsPanel, BorderLayout.SOUTH);
        }
    }

    public class CreateUser extends JPanel {

        JPanel userPanel;
        JPanel passPanel;
        JPanel repPassPanel;
        JPanel buttonsPanel;
        JPanel fieldsPanel;

        JLabel username;
        JLabel password;
        JLabel repPassword;

        JTextField userField;
        JPasswordField passField;
        JPasswordField repPassField;

        JButton acceptButton;
        JButton cancelButton;

        public CreateUser() {

            userPanel = new JPanel();
            passPanel = new JPanel();
            repPassPanel = new JPanel();
            buttonsPanel = new JPanel();
            fieldsPanel = new JPanel();

            username = new JLabel("username: ");
            password = new JLabel("password: ");
            repPassword = new JLabel("repeat password: ");

            userField = new JTextField();
            passField = new JPasswordField();
            repPassField = new JPasswordField();

            acceptButton = new JButton("Accept");
            cancelButton = new JButton("Cancel");

            userField.setColumns(8);
            passField.setColumns(8);
            repPassField.setColumns(8);

            userPanel.add(username);
            userPanel.add(userField);

            passPanel.add(password);
            passPanel.add(passField);

            repPassPanel.add(repPassword);
            repPassPanel.add(repPassField);

            buttonsPanel.add(acceptButton);
            buttonsPanel.add(cancelButton);

            fieldsPanel.setLayout(new BoxLayout(fieldsPanel, BoxLayout.Y_AXIS));

            this.setLayout(new BorderLayout(10, 15));
            this.setBorder(new EmptyBorder(10, 10, 10, 10));

            fieldsPanel.add(userPanel);
            fieldsPanel.add(passPanel);
            fieldsPanel.add(repPassPanel);

            this.add(fieldsPanel, BorderLayout.CENTER);
            this.add(buttonsPanel, BorderLayout.SOUTH);
        }
    }

    public class PageViewer extends CardLayout {

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            Component current = findCurrentComponent(parent);
            if (current != null) {
                Insets insets = parent.getInsets();
                Dimension pref = current.getPreferredSize();
                pref.width += insets.left + insets.right;
                pref.height += insets.top + insets.bottom;
                return pref;
            }
            return super.preferredLayoutSize(parent);
        }

        public Component findCurrentComponent(Container parent) {
            for (Component comp : parent.getComponents()) {
                if (comp.isVisible()) {
                    return comp;
                }
            }
            return null;
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • well actually the issue comes when clicking the "Register Button". That page is suposed to have an image above and therefore the issue is more visible. Try copying a jpg image with `image.jpg` name, it should give you a better idea of what I'm saying. I'll attach SS too to the question indeed. – Frakcool May 27 '14 at 05:44
  • @Frakcool ps- As a user, sudden frame size changes would really annoy me, just saying ;) – MadProgrammer May 27 '14 at 05:46
  • yeah I'm looking at it. – Frakcool May 27 '14 at 05:46
  • I'm making the frame resizing because it will have a menu window after user logins, and a `JTable` which is like a LOOOOOT bigger than the login page. It's size is `1350 x 700` so it's a huge thing. That's why I was using frame resize. Anyway thanks for that :) I'll check the updated code – Frakcool May 27 '14 at 05:49
  • You could consider using a `JDialog` or `JOptionPane` for the login screen, but what ever makes it work for you ;) – MadProgrammer May 27 '14 at 05:50
  • I was thinking the same. Thanks for all :) I'll move that code for the menu and later improve the login with `JDialog` or `JOptionPane` as you say. Btw... May I ask, which page / program did you used for the gif image? – Frakcool May 27 '14 at 05:53
  • could you again post the program you used for the gif making? I lost the link and would like to use it on an answer (not the program, but a gif made with the tool) – Frakcool Oct 08 '15 at 16:00
  • Licecap is what you're after – MadProgrammer Oct 08 '15 at 20:10