Search code examples
javawindowsswingjbuttoncardlayout

CardLayout not rendering properly on windows


I've been working on a login screen for a new project and came across a weird rendering "error" while using CardLayout on windows.

SignUp screen on Mac:SignUp Screen Mac

The screens load up correctly on my Mac computer, but on windows they look like these after you click "Register" or after you click "Back".

The same screens on windows:SignUp Screen Windows

As you can see, on windows the SignUp "card" from the CardLayout is rendered over the Login "card" without hiding the other one and vise versa, not like on mac.

Now my question is, could this be caused because of the transparent background and therefore windows thinks that the one behind should still be visible, or could it be creating a brand new "card" each time i switch, or just be forgetting to hide the one in the back all together?

Why does this work on Mac but not on Windows?

And also, how could i go about fixing this?

I will put the whole Class so you can test it for yourself.

(Side note: you may also notice that the button "Register" shows the white button shape on windows even though it has btnRegister.setBorder(null); set (works on Mac))

The complete one Class code:

package testing;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import utilities.ComponentMover;

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Insets;

import javax.swing.JSeparator;
import javax.swing.JPasswordField;

@SuppressWarnings("serial")
public class ClientStarter extends JFrame implements ActionListener {

JPanel cards;

private int height = 450;
private int width = 700;
private int trasparancy = 90;
private int labelWidth = 400;

final static String BACK = "Back";
final static String REGISTER = "Register";

private Color textLine = Color.GRAY;
private Color textColor = Color.WHITE;
private Color tipColor = Color.GRAY;
private Color disabledTipColor = new Color(90, 90, 90);



//   LOGIN //

JPanel loginCard;

public static JTextField usernameIn = new JTextField();
private JLabel userLabel = new JLabel("Username :");

public static JPasswordField passwordIn = new JPasswordField();
private JLabel passLabel = new JLabel("Password :");

private JButton btnLogin = new JButton("Login");
private JButton btnRegister = new JButton(REGISTER);
private JLabel registerLabel = new JLabel("Don't own an Account? ");

private JSeparator separatorUser = new JSeparator();
private JSeparator separatorPass = new JSeparator();

//    SIGNUP   //

JPanel joinCard;

public static JTextField emailNew = new JTextField();
public static JLabel newEmailLabel = new JLabel("Email : (Not Available)");

public static JTextField usernameNew = new JTextField();
public static JLabel newUserLabel = new JLabel("Username :");

public static JTextField passwordNew = new JTextField();
public static JLabel newPassLabel = new JLabel("Password :");

public static JTextField passwordNew2 = new JTextField();
public static JLabel newPassLabel2 = new JLabel("Re-enter password :");


private JButton btnSignUp = new JButton("Signup");
private JButton btnBack = new JButton(BACK);

private JSeparator separatorMailNew = new JSeparator();
private JSeparator separatorUserNew = new JSeparator();
private JSeparator separatorPassNew = new JSeparator();
private JSeparator separatorPassNew2 = new JSeparator();

public ClientStarter() {
    getContentPane().setBackground(Color.GRAY);
    setUndecorated(true);
    setBackground(new Color(0, 0, 0, trasparancy));
    setTitle("EnChant");
    setSize(width, height);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setVisible(true);
    setResizable(false);

    //Create the cards
    //     LOGIN     //
    Font avenir = new Font("Avenir", Font.PLAIN, 18);

    loginCard = new JPanel();
    loginCard.setLayout(null);

    usernameIn.setBounds(348, 150, 327, 35);
    usernameIn.setColumns(10);
    usernameIn.setFont(avenir);
    usernameIn.setBorder(null);

    passwordIn.setBounds(348, usernameIn.getY() + 74, 327, 35);
    passwordIn.setColumns(10);
    passwordIn.setFont(avenir);
    passwordIn.setBorder(null);

    userLabel.setBounds(usernameIn.getX(), usernameIn.getY() - 20, labelWidth, 16);
    userLabel.setFont(avenir);

    passLabel.setBounds(passwordIn.getX(), passwordIn.getY() - 20, labelWidth, 16);
    passLabel.setFont(avenir);

    btnLogin.setBounds(348, passwordIn.getY() + 81, 327, 45);
    btnLogin.addActionListener(this);

    registerLabel.setBounds(btnLogin.getX(), btnLogin.getY() + btnLogin.getHeight() + 5, labelWidth, 16);
    registerLabel.setFont(new Font("Avenir", Font.PLAIN, 13));  
    btnRegister.setBounds(btnLogin.getX() + 130, registerLabel.getY() - 1, 70, 16);
    btnRegister.addActionListener(this);
    btnRegister.setBorder(null);


    loginCard.setBackground(new Color(0, 0, 0, trasparancy));

    usernameIn.setBackground(new Color(0, 0, 0, 0));
    usernameIn.setForeground(textColor);

    passwordIn.setBackground(new Color(0, 0, 0, 0));
    passwordIn.setForeground(textColor);


    userLabel.setForeground(tipColor);
    passLabel.setForeground(tipColor);


    btnLogin.setForeground(new Color(70, 130, 180));
    btnLogin.setBackground(Color.WHITE);

    btnRegister.setForeground(new Color(70, 130, 180));
    registerLabel.setForeground(tipColor);


    separatorUser.setForeground(textLine);
    separatorUser.setBounds(usernameIn.getX(), usernameIn.getY()+usernameIn.getHeight()-8, usernameIn.getWidth(), 6);

    separatorPass.setForeground(textLine);
    separatorPass.setBounds(passwordIn.getX(), passwordIn.getY()+passwordIn.getHeight()-8, passwordIn.getWidth(), 6);

    loginCard.add(usernameIn);
    loginCard.add(separatorUser);
    loginCard.add(userLabel);
    loginCard.add(passwordIn);
    loginCard.add(separatorPass);
    loginCard.add(passLabel);
    loginCard.add(btnLogin);
    loginCard.add(btnRegister);
    loginCard.add(registerLabel);



    //    SIGNUP   //
    joinCard = new JPanel();
    joinCard.setLayout(null);

    emailNew.setBounds(348, 62, 327, 35);
    emailNew.setColumns(10);
    emailNew.setFont(avenir);
    emailNew.setBorder(null);
    emailNew.setEditable(false);

    usernameNew.setBounds(348, emailNew.getY() + 74, 327, 35);
    usernameNew.setColumns(10);
    usernameNew.setFont(avenir);
    usernameNew.setBorder(null);

    passwordNew.setBounds(348, usernameNew.getY() + 74, 327, 35);
    passwordNew.setColumns(10);
    passwordNew.setFont(avenir);
    passwordNew.setBorder(null);

    passwordNew2.setBounds(348, passwordNew.getY() + 74, 327, 35);
    passwordNew2.setColumns(10);
    passwordNew2.setFont(avenir);
    passwordNew2.setBorder(null);

    //32, 106, 180, 254  : 2, 76, 150, 224

    newEmailLabel.setBounds(emailNew.getX(), emailNew.getY() - 20, labelWidth, 16);
    newEmailLabel.setFont(avenir);

    newUserLabel.setBounds(usernameNew.getX(), usernameNew.getY() - 20, labelWidth, 16);
    newUserLabel.setFont(avenir);

    newPassLabel.setBounds(passwordNew.getX(), passwordNew.getY() - 20, labelWidth, 16);
    newPassLabel.setFont(avenir);

    newPassLabel2.setBounds(passwordNew2.getX(), passwordNew2.getY() - 20, labelWidth, 16);
    newPassLabel2.setFont(avenir);


    btnSignUp.setBounds(348, passwordNew2.getY() + 71, 327, 45); //335  // +81
    btnSignUp.addActionListener(this);

    btnBack.setBounds(btnSignUp.getX()-70, btnSignUp.getY(), 70, 45); //380 
    btnBack.addActionListener(this);


    joinCard.setBackground(new Color(0, 0, 0, trasparancy));

    emailNew.setBackground(new Color(0, 0, 0, 0));
    emailNew.setForeground(textColor);

    usernameNew.setBackground(new Color(0, 0, 0, 0));
    usernameNew.setForeground(textColor);

    passwordNew.setBackground(new Color(0, 0, 0, 0));
    passwordNew.setForeground(textColor);

    passwordNew2.setBackground(new Color(0, 0, 0, 0));
    passwordNew2.setForeground(textColor);

    newEmailLabel.setForeground(disabledTipColor);
    newUserLabel.setForeground(tipColor);
    newPassLabel.setForeground(tipColor);
    newPassLabel2.setForeground(tipColor);

    btnSignUp.setForeground(new Color(70, 130, 180));
    btnBack.setBackground(Color.WHITE);


    separatorMailNew.setBounds(emailNew.getX(), emailNew.getY()+emailNew.getHeight()-8, emailNew.getWidth(), 6);
    separatorMailNew.setForeground(textLine);

    separatorUserNew.setBounds(usernameNew.getX(), usernameNew.getY()+usernameNew.getHeight()-8, usernameNew.getWidth(), 6);
    separatorUserNew.setForeground(textLine);

    separatorPassNew.setBounds(passwordNew.getX(), passwordNew.getY()+passwordNew.getHeight()-8, passwordNew.getWidth(), 6);
    separatorPassNew.setForeground(textLine);

    separatorPassNew2.setBounds(passwordNew2.getX(), passwordNew2.getY()+passwordNew2.getHeight()-8, passwordNew2.getWidth(), 6);
    separatorPassNew2.setForeground(textLine);

    joinCard.add(emailNew);
    joinCard.add(newEmailLabel);
    joinCard.add(usernameNew);
    joinCard.add(newUserLabel);
    joinCard.add(passwordNew);
    joinCard.add(newPassLabel);
    joinCard.add(passwordNew2);
    joinCard.add(newPassLabel2);
    joinCard.add(btnSignUp);
    joinCard.add(btnBack);
    joinCard.add(separatorMailNew);
    joinCard.add(separatorUserNew);
    joinCard.add(separatorPassNew);
    joinCard.add(separatorPassNew2);



    //    End    //

    JPanel whiteRectLogin = new JPanel();
    whiteRectLogin.setBackground( Color.WHITE );
    whiteRectLogin.setBounds(0, 0, 250, height);
    loginCard.add(whiteRectLogin);

    JPanel whiteRectJoin = new JPanel();
    whiteRectJoin.setBackground( Color.WHITE );
    whiteRectJoin.setBounds(0, 0, 250, height);
    joinCard.add(whiteRectJoin);



    cards = new JPanel(new CardLayout());
    cards.setBackground(new Color(0, 0, 0, trasparancy));

    cards.add(loginCard, BACK);
    cards.add(joinCard, REGISTER);

    getContentPane().add(cards); 

    //Top, Left, bottom, right
    ComponentMover cm = new ComponentMover(this, this);
    cm.setEdgeInsets(new Insets(-50, 1, 0, -50));

    validate();

    repaint();
    getContentPane().setLayout(null);


}


public void actionPerformed(ActionEvent e) {
    if(e.getSource() == btnRegister) {
        CardLayout cl = (CardLayout) (cards.getLayout());
        cl.show(cards, REGISTER);
        loginCard.setVisible(false);

    }
    if(e.getSource() == btnBack) {
        CardLayout cl = (CardLayout) (cards.getLayout());
        cl.show(cards, BACK);
        loginCard.setVisible(false);
    }
    if(e.getSource() == btnSignUp) {
        //new SignUpCheck();
    }
}

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

Solution

  • could this be caused because of the transparent background

    Probably. Swing does not renderer transparent backgrounds correctly. Swing expects a component to be either fully opaque or fully transparent.

    Check out Backgrounds With Transparency for a complete description of the problem and a couple of solutions.

    You can either do custom painting of every component with code something like:

    JPanel panel = new JPanel()
    {
        protected void paintComponent(Graphics g)
        {
            g.setColor( getBackground() );
            g.fillRect(0, 0, getWidth(), getHeight());
            super.paintComponent(g);
        }
    };
    panel.setOpaque(false); // background of parent will be painted first
    panel.setBackground( new Color(255, 0, 0, 20) );
    frame.add(panel);
    

    Or you can use the AlphaContainer class to do the painting for you.

    Also, you have several other problems:

    1. Don't use static variables for your Swing components. That is no the proper usage of the static keyword.

    2. Don't use a null layout and setBounds(). Swing was designed to be used with layout managers. Layout managers work well on multiple platforms.

    3. Don't use an alpha value of 0. The 0 means fully transparent, so just use the setOpaque(false) method on the component.

    4. Don't keep creating new Color objects. The same Color object can be used for every component. It save resources and makes it easier to change all Color for all components all at once.

    5. Don't use validate() and repaint() in the constructor of your class. All the components should be added to the frame BEFORE you invoke setVisible(true) so those methods are not required.