Search code examples
javaswingjmenubar

Swing JMenuBar not rendering properly


First time actually using anything to do with swing - sorry for the poor code and crude visuals!
Using swing for a massively over-complicated password checker school project, and when I came to loading in a JMenuBar, it doesn't render properly the first time. Once I run through one of the options first, it reloads correctly, but the first time it comes out like this: First render attempt
But after I run one of the methods, either by clicking one of the buttons that I added to check if it was just the JFrame that was broken or using one of the broken menu options, it reloads correctly, but has a little grey bar above where the JMenuBar actually renders: Post-method render

The code for the visuals is as follows:

public void draw_menu(){
        this.parent.pack();
        this.parent.setExtendedState(JFrame.MAXIMIZED_BOTH);
        JButton check = new JButton("Check Password");
        JButton generate = new JButton("Generate Password");
        generate.addActionListener(e -> this.generator());
        check.addActionListener(e -> this.char_checker());
        check.setBounds(500,500, 170, 50);
        generate.setBounds(500, 200, 170, 50);
        this.parent.add(check);
        this.parent.add(generate);
        JMenu a = new JMenu("Check Password");
        JMenu b = new JMenu("Generate Password");
        JMenu c = new JMenu("Extra Codes");
        JMenuItem a1 = new JMenuItem("Enter password >>>");
        JMenuItem b1 = new JMenuItem("Generate >>>");
        JMenuItem c1 = new JMenuItem("Valid >>>");
        JMenuItem c2 = new JMenuItem("Why >>>");
        a1.addActionListener(e -> this.char_checker());
        b1.addActionListener(e -> this.generator());
        c1.addActionListener(e -> JOptionPane.showMessageDialog(Password.this.parent, Arrays.asList(valid_chars).toString(), "Valid Characters", JOptionPane.PLAIN_MESSAGE));
        c2.addActionListener(e -> this.why());
        a.add(a1);
        b.add(b1);
        c.add(c1);
        c.add(c2);
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(a);
        menuBar.add(b);
        menuBar.add(c);
        this.parent.setJMenuBar(menuBar);
        this.parent.add(menuBar);
        this.parent.setVisible(true);
    }

If you want to have the whole file to contextualize it (and be able to run it) you can view it below:

import java.awt.*;
import java.util.*;
import java.lang.*;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import javax.swing.*;

public class Password {

    Scanner scanner;
    String password;
    Integer score;
    List<Character> pass;
    JFrame parent;
    JLabel frameScore;

    static Character[] valid_chars = {'!', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+'};
    static Character[] lower_alpha = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
    static Character[] upper_alpha = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
    static Character[] valid_nums = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
    static String[] keyboard_combos = {"qwe", "wer", "ert", "rty", "tyu", "yui", "uio", "iop", "asd", "sdf", "dfg", "fgh", "gjh", "hjk", "jkl", "zxc", "xcv", "cvb", "vbn", "bnm"};

    boolean num = false;
    boolean upper = false;
    boolean lower = false;
    boolean character = false;

    public Password() {
    }

    public void why() throws NullPointerException {
        if (Objects.isNull(this.score)){
            JOptionPane.showMessageDialog(parent, "Try checking a password first!", "Error!", JOptionPane.ERROR_MESSAGE);
            System.out.println("Error -> this.score returns null!\t|\tTry checking a password first!");
            this.draw_menu();
        }
        String out = "Your password achieved a score of "+this.score.toString()+" because you included ";
        if (this.num){out = out.concat("at least one number, ");}
        if (this.character){out = out.concat("at least one special character, ");}
        if (this.upper){out = out.concat("at least one upper case letter, ");}
        if (this.lower){out = out.concat("at least one lower case letter, ");}
        out  = out.concat("Achieving your score of: "+this.score.toString());
        System.out.println(out);
        JOptionPane.showMessageDialog(parent, out, "Score: "+this.score.toString(), JOptionPane.PLAIN_MESSAGE);
        this.draw_menu();
    }
    public void char_checker() {
        this.password = JOptionPane.showInputDialog(this.parent, "Enter your password:", null, JOptionPane.PLAIN_MESSAGE);
        if (this.password.length() == 0) {
            System.out.println("Error <- this.password.length() returns null!\t|\tTry entering a password!");
        }
        if (this.password.length() < 8 || this.password.length() > 24) {
            System.out.println("Error <- this.password.length() exceeds bounds!\t|\t( [Bounds 7 < password < 24] String length = "+this.password.length()+")");
        } else {
            char[] pass_array = this.password.toCharArray();
            for (Character temp : pass_array) {
                if (Arrays.asList(valid_chars).contains(temp) || Arrays.asList(lower_alpha).contains(temp) || Arrays.asList(upper_alpha).contains(temp) || Arrays.asList(valid_nums).contains(temp)) {
                    System.out.print("valid placement @ temp:" + temp);
                } else {
                    System.out.println("\nError <- $temp: '" + temp + "' not found in character bank!\t|\tNot valid character (alphanumerical + valid_chars only)\nEnter valid on menu for more information.");
                    this.draw_menu();
                }
            }
            this.security_score(pass_array);
        }
        this.draw_menu();
    }

    public void security_score(char[] array){
        if (!Objects.isNull(this.frameScore)){
            this.frameScore.setText("");
        }
        this.num = false;
        this.upper = false;
        this.lower = false;
        this.character = false;
        System.out.println("\nGenerating security score...");
        this.score = 0;
        this.score = this.password.length();
        for (Character temp: array) {
            if (Arrays.asList(valid_chars).contains(temp)) {
                if (!this.character) {
                    this.score = this.score + 5;
                    this.character = true;
                }
            } else if (Arrays.asList(valid_nums).contains(temp)){
                if (!this.num){
                    this.score = this.score + 5;
                    this.num = true;
                }
            } else if (Arrays.asList(lower_alpha).contains(temp)){
                if (!this.lower){
                    this.score = this.score + 5;
                    this.lower = true;
                }
            } else if (Arrays.asList(upper_alpha).contains(temp)){
                if (!this.upper){
                    this.score = this.score + 5;
                    this.upper = true;
                }
            }
        }
        if (this.lower && this.upper && this.character && this.num){
            this.score = this.score + 10;
        } else if (!this.character && !this.num) {
            this.score = this.score - 5;
        } else if (!this.character && !this.lower && !this.upper){
            this.score = this.score - 5;
        } else if (!this.lower && !this.upper && !this.num){
            this.score = this.score - 5;
        }
        for (String temp : keyboard_combos){
            if (this.password.contains(temp)) {
                this.score = this.score - 5;
            }
        }

        if (this.score > 20){
            System.out.println("With a score of "+this.score+", your password is Strong.");
        } else if (this.score < 20 && this.score > 0){
            System.out.println("With a score of "+this.score+", your password is Average.");
        } else {
            System.out.println("With a score of "+this.score+", your password is Weak.");
        }
        System.out.println("To see why you achieved a score of "+this.score.toString()+", enter \"why\" on the menu!");
        this.frameScore = new JLabel("<html>Your previous score was: "+this.score.toString()+"<br/>with:"+this.password+"</html>", SwingConstants.CENTER);
        Dimension size = this.frameScore.getPreferredSize();
        this.frameScore.setBounds(150, 100, size.width, size.height);
        this.parent.setLayout(null);
        this.parent.add(this.frameScore);
    }

    public void generator() {
        if (!Objects.isNull(this.frameScore)){
            this.frameScore.setText("");
        }
        if (!Objects.isNull(this.score)) {
            this.frameScore = new JLabel("<html>Your previous score was: " + this.score + "<br/>with:" + this.password + "</html>", SwingConstants.CENTER);
        }
        this.pass.clear();
        System.out.println("generating password...");
        int length = ThreadLocalRandom.current().nextInt(8, 12);
        System.out.println(length);
        int count = 0;
        int item;
        while (count < length - 1){
            int choice = ThreadLocalRandom.current().nextInt(1, 4);
            switch (choice){
                case 1:
                    item = ThreadLocalRandom.current().nextInt(0, valid_chars.length);
                    this.pass.add(valid_chars[item]);
                    count++;

                case 2:
                    item = ThreadLocalRandom.current().nextInt(0, lower_alpha.length);
                    this.pass.add(lower_alpha[item]);
                    count++;

                case 3:
                    item = ThreadLocalRandom.current().nextInt(0, upper_alpha.length);
                    this.pass.add(upper_alpha[item]);
                    count++;

                case 4:
                    item = ThreadLocalRandom.current().nextInt(0, valid_nums.length);
                    this.pass.add(valid_nums[item]);
                    count++;
            }
        }
        System.out.println("Your password is:");
        char[] array = new char[this.pass.size()];
        for (char temp : this.pass){
            System.out.print(temp);
            array[this.pass.indexOf(temp)] = this.pass.get(this.pass.indexOf(temp));
        }
        this.password = String.valueOf(array);
        this.security_score(array);
        System.out.println("Generation complete!");
        if (this.score < 20){
            this.generator();
        }
        JOptionPane.showMessageDialog(parent, "<html>Generation complete!<br/>"+this.password+"</html>", "Generated!", JOptionPane.INFORMATION_MESSAGE);
        this.draw_menu();
    }

    //visual rendering code
    public void draw_menu(){
        this.parent.pack();
        this.parent.setExtendedState(JFrame.MAXIMIZED_BOTH);
        JButton check = new JButton("Check Password");
        JButton generate = new JButton("Generate Password");
        generate.addActionListener(e -> this.generator());
        check.addActionListener(e -> this.char_checker());
        check.setBounds(500,500, 170, 50);
        generate.setBounds(500, 200, 170, 50);
        this.parent.add(check);
        this.parent.add(generate);
        JMenu a = new JMenu("Check Password");
        JMenu b = new JMenu("Generate Password");
        JMenu c = new JMenu("Extra Codes");
        JMenuItem a1 = new JMenuItem("Enter password >>>");
        JMenuItem b1 = new JMenuItem("Generate >>>");
        JMenuItem c1 = new JMenuItem("Valid >>>");
        JMenuItem c2 = new JMenuItem("Why >>>");
        a1.addActionListener(e -> this.char_checker());
        b1.addActionListener(e -> this.generator());
        c1.addActionListener(e -> JOptionPane.showMessageDialog(Password.this.parent, Arrays.asList(valid_chars).toString(), "Valid Characters", JOptionPane.PLAIN_MESSAGE));
        c2.addActionListener(e -> this.why());
        a.add(a1);
        b.add(b1);
        c.add(c1);
        c.add(c2);
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(a);
        menuBar.add(b);
        menuBar.add(c);
        this.parent.setJMenuBar(menuBar);
        this.parent.add(menuBar);
        this.parent.setVisible(true);
    }


    public static void main(String[] args) {
        Password user = new Password();
        user.scanner = new Scanner(System.in);
        user.pass = new ArrayList<>();
        user.parent = new JFrame();
        user.draw_menu();
    }
}

Thanks in advance!


Solution

  • You should separate creating your menu from your content. Please review the following example. I decoupled your menu, component, and event logic into meaningful phases.

    import java.util.*;
    import javax.swing.*;
    
    public class App implements Runnable {
        private static final long serialVersionUID = 6924949643971067836L;
    
        private static final Character[] VALID_CHARS = {'!', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+'};
        private static final Character[] LOWER_ALPHA = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
        private static final Character[] UPPER_ALPHA = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
        private static final Character[] VALID_NUMS = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
        private static final String[] KEYBOARD_COMBOS = {"qwe", "wer", "ert", "rty", "tyu", "yui", "uio", "iop", "asd", "sdf", "dfg", "fgh", "gjh", "hjk", "jkl", "zxc", "xcv", "cvb", "vbn", "bnm"};
        
        private Scanner scanner;
        private String password;
        private Integer score;
        private List<Character> pass;
        private JFrame parent;
        private JLabel frameScore;
    
        private boolean num = false;
        private boolean upper = false;
        private boolean lower = false;
        private boolean character = false;
        
        public App() { }
        
        private void checkPassword() {
            System.out.println("Checking password...");
        }
    
        private void generatePassword() {
            System.out.println("Generating password...");
        }
        
        private void why() {
            System.out.println("Why...");
        }
        
        protected JPanel createContent() {
            JPanel mainPanel = new JPanel();
            JButton check = new JButton("Check Password");
            JButton generate = new JButton("Generate Password");
            
            check.addActionListener(e -> this.checkPassword());
            generate.addActionListener(e -> this.generatePassword());
            
            check.setBounds(500,500, 170, 50);
            generate.setBounds(500, 200, 170, 50);
            
            mainPanel.add(check);
            mainPanel.add(generate);
            
            return mainPanel;
        }
        
        protected JMenuBar createMenu() {
            JMenuBar menuBar = new JMenuBar();
            JMenu checkPass = new JMenu("Check Password");
            JMenu resetPass = new JMenu("Generate Password");
            JMenu extraCodes = new JMenu("Extra Codes");
            
            JMenuItem enterPass = new JMenuItem("Enter password >>>");
            JMenuItem generatePass = new JMenuItem("Generate >>>");
            JMenuItem verify = new JMenuItem("Valid >>>");
            JMenuItem about = new JMenuItem("Why >>>");
            
            enterPass.addActionListener(e -> this.checkPassword());
            generatePass.addActionListener(e -> this.generatePassword());
            verify.addActionListener(e -> JOptionPane.showMessageDialog(this.parent, Arrays.asList(VALID_CHARS).toString(), "Valid Characters", JOptionPane.PLAIN_MESSAGE));
            about.addActionListener(e -> this.why());
            
            menuBar.add(checkPass);
            menuBar.add(resetPass);
            menuBar.add(extraCodes);
            
            checkPass.add(enterPass);
            resetPass.add(generatePass);
            extraCodes.add(verify);
            extraCodes.add(about);
            
            return menuBar;
        }
        
        @Override
        public void run() {
            this.parent = new JFrame();
            
            this.parent.setJMenuBar(createMenu());
            this.parent.setContentPane(createContent());
            this.parent.pack();
            this.parent.setLocationRelativeTo(null);
            this.parent.setVisible(true);
        }
        
        public static void main(String[] args) {
            try {
                SwingUtilities.invokeAndWait(new App());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }