Random Gamer
Random Gamer

Reputation: 1

Why does my window in Java (JFrame) crash when i double click on a JTextField?

I wrote this little program for an specific utility, didn't optimize it yet but so far everything works as intended, but when I accidentaly double click on JTextField it crashes, and I have no idea why. (JTextField is on line 62 for the matter)

package smoothies;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;
import java.awt.*;

public class smoothies extends JFrame {
    
    public smoothies(List<List<List<String>>> smoothies) {
        //setBackground(new Color());
        setDefaultCloseOperation(3);
        setSize(400,400);
        setLayout(new BorderLayout(50,50));
        
        JPanel lIng= new JPanel();
        lIng.setLayout(new GridLayout(8,2));
        ArrayList<JCheckBox> ingredients = new ArrayList<>();
        // kelp,horse,grapes,apple,pepper,nectar,milk,cactus,potato,salt,butter,pumpkin,guts,fang,mango,egg
        JCheckBox kelp = new JCheckBox("kelp");
        ingredients.add(kelp);
        JCheckBox horse = new JCheckBox("horse");
        ingredients.add(horse);
        JCheckBox grapes = new JCheckBox("grapes");
        ingredients.add(grapes);
        JCheckBox apple = new JCheckBox("apple");
        ingredients.add(apple);
        JCheckBox pepper = new JCheckBox("pepper");
        ingredients.add(pepper);
        JCheckBox nectar = new JCheckBox("nectar");
        ingredients.add(nectar);
        JCheckBox milk = new JCheckBox("milk");
        ingredients.add(milk);
        JCheckBox cactus = new JCheckBox("cactus");
        ingredients.add(cactus);
        JCheckBox potato = new JCheckBox("potato");
        ingredients.add(potato);
        JCheckBox salt = new JCheckBox("salt");
        ingredients.add(salt);
        JCheckBox butter = new JCheckBox("butter");
        ingredients.add(butter);
        JCheckBox pumpkin = new JCheckBox("pumpkin");
        ingredients.add(pumpkin);
        JCheckBox guts = new JCheckBox("guts");
        ingredients.add(guts);
        JCheckBox fang = new JCheckBox("fang");
        ingredients.add(fang);
        JCheckBox mango = new JCheckBox("mango");
        ingredients.add(mango);
        JCheckBox egg = new JCheckBox("egg");
        ingredients.add(egg);
        for(JCheckBox ing: ingredients) {
            lIng.add(ing);
        }
        
        Button calculate = new Button("calculate");
        JTextField result = new JTextField("hai :D");
        result.setEditable(false);
        
        calculate.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("\n\n\n\n\n\n\n\n\n\n\n\nSMOOTHIES YOU CAN MAKE:");
                for(List<List<String>> smoothie: smoothies) {
                    for(JCheckBox ing1: ingredients) {
                        if(smoothie.get(0).contains(ing1.getText()) && ing1.isSelected()) {
                            for(JCheckBox ing2: ingredients) {
                                if(smoothie.get(1).contains(ing2.getText()) && ing2.isSelected()) {
                                    System.out.println(smoothie);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        });
        
        Thread h = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    int p = 0;
                    for(List<List<String>> smoothie: smoothies) {
                        for(JCheckBox ing1: ingredients) {
                            if(smoothie.get(0).contains(ing1.getText()) && ing1.isSelected()) {
                                for(JCheckBox ing2: ingredients) {
                                    if(smoothie.get(1).contains(ing2.getText()) && ing2.isSelected()) {
                                        p++;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    result.setText(String.valueOf(p));
                }
            }
        });
        h.start();
        

        
        
        add(lIng,BorderLayout.WEST);
        add(result,BorderLayout.CENTER);
        add(calculate,BorderLayout.EAST);
        setVisible(true);
    }
    
    public static void main(String[] args) {
        
        
        List<List<List<String>>> smoothies = List.of(List.of(List.of("nectar"), List.of("nectar")),
                List.of(List.of("nectar"), List.of("milk")),
                List.of(List.of("grapes"), List.of("grapes")),
                List.of(List.of("grapes"), List.of("horse","apple","cactus","salt","butter","mango")),
                List.of(List.of("grapes"), List.of("nectar")),
                List.of(List.of("grapes"), List.of("milk")),
                List.of(List.of("milk"), List.of("milk")),
                List.of(List.of("milk"), List.of("apple","cactus")),
                List.of(List.of("milk"), List.of("salt")),
                List.of(List.of("mango"), List.of("mango")),
                List.of(List.of("mango"), List.of("kelp","apple","cactus","butter")),
                List.of(List.of("nectar"), List.of("mango")),
                List.of(List.of("milk"), List.of("mango")),
                List.of(List.of("salt"), List.of("mango")),
                List.of(List.of("cactus"), List.of("cactus","horse","nectar","pumpkin")),
                List.of(List.of("cactus"), List.of("salt")),
                List.of(List.of("pepper"), List.of("pepper")),
                List.of(List.of("pepper"), List.of("cactus","pumpkin")),
                List.of(List.of("pepper"), List.of("potato")),
                List.of(List.of("pepper"), List.of("grapes","apple","milk","mango")),
                List.of(List.of("apple"), List.of("apple")),
                List.of(List.of("apple"), List.of("horse","nectar","cactus","potato")),
                List.of(List.of("apple"), List.of("salt")),
                List.of(List.of("kelp"), List.of("kelp")),
                List.of(List.of("kelp"), List.of("grapes","apple","potato")),
                List.of(List.of("kelp"), List.of("pumpkin")),
                List.of(List.of("kelp"), List.of("milk")),
                List.of(List.of("kelp"), List.of("salt")),
                List.of(List.of("horse"), List.of("horse","kelp","pepper","nectar","potato","salt","mango")),
                List.of(List.of("horse"), List.of("milk")),
                List.of(List.of("potato"), List.of("potato")),
                List.of(List.of("potato"), List.of("grapes","cactus","butter")),
                List.of(List.of("nectar"), List.of("potato")),
                List.of(List.of("milk"), List.of("potato")),
                List.of(List.of("potato"), List.of("mango")),
                List.of(List.of("potato"), List.of("salt")),
                List.of(List.of("butter"), List.of("butter","kelp")),
                List.of(List.of("apple"), List.of("butter")),
                List.of(List.of("cactus"), List.of("butter")),
                List.of(List.of("nectar"), List.of("butter")),
                List.of(List.of("butter"), List.of("pumpkin")),
                List.of(List.of("milk"), List.of("butter")),
                List.of(List.of("salt"), List.of("butter")),
                List.of(List.of("pumpkin"), List.of("pumpkin")),
                List.of(List.of("pumpkin"), List.of("horse","grapes","apple","potato")),
                List.of(List.of("nectar"), List.of("pumpkin")),
                List.of(List.of("milk"), List.of("pumpkin")),
                List.of(List.of("pumpkin"), List.of("mango")),
                List.of(List.of("salt"), List.of("pumpkin")),
                List.of(List.of("egg"), List.of("egg","grapes","nectar","milk","salt")),
                List.of(List.of("egg"), List.of("mango")),
                List.of(List.of("egg"), List.of("cactus")),
                List.of(List.of("egg"), List.of("pepper")),
                List.of(List.of("egg"), List.of("apple")),
                List.of(List.of("egg"), List.of("kelp")),
                List.of(List.of("egg"), List.of("horse")),
                List.of(List.of("egg"), List.of("potato")),
                List.of(List.of("egg"), List.of("butter")),
                List.of(List.of("egg"), List.of("pumpkin")),
                List.of(List.of("guts"), List.of("mango")),
                List.of(List.of("guts"), List.of("cactus")),
                List.of(List.of("fang"), List.of("pepper")),
                List.of(List.of("guts"), List.of("pepper")),
                List.of(List.of("guts"), List.of("apple")),
                List.of(List.of("fang"), List.of("kelp")),
                List.of(List.of("fang"), List.of("horse")),
                List.of(List.of("fang"), List.of("potato")),
                List.of(List.of("fang"), List.of("butter")),
                List.of(List.of("fang"), List.of("pumpkin")));
        
        
        System.out.println(smoothies);
        new smoothies(smoothies);
    }

}

You are not supposed to interact with it, and i did setEditable to false, but sometimes it just crashes out of nowhere, and other times it actualy sends the error

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: bad position: 1

that along something about caret, I don't understand what means this here

https://youtu.be/MxIIx3QBYw8

Upvotes: -1

Views: 64

Answers (1)

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48693

You should organize your code into reusable methods (and classes).

Use a singleton thread executor to spawn a loop to calculate the possible smoothies based on the currently selected ingredients.

Here is a refined updater method:

private void startSmoothieUpdater(List<Smoothie> smoothies) {
    executor.submit(() -> {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                int smoothieCount = calculateSmoothiesCount(smoothies);
                SwingUtilities.invokeLater(() -> resultField.setText(String.valueOf(smoothieCount)));
                Thread.sleep(UPDATE_INTERVAL_MS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    });
}

Demo

Here it is in action. At the bottom, I included a YAML file that can be used as configuration. This makes the application more dynamic. A separate model package makes data more readable and modular.

I also included lombok and SnakeYAML as dependencies:

  • implementation: 'org.yaml:snakeyaml:2.3'
  • compileOnly 'org.projectlombok:lombok:1.18.36'
package org.example.smoothies;

import javax.swing.*;

import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.example.smoothies.model.Ingredients;
import org.example.smoothies.model.Smoothie;
import org.example.smoothies.model.SmoothiesWrapper;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

public class SmoothieApp {
    private static final String[] INGREDIENTS_LIST = {
            "apple", "butter", "cactus", "egg", "fang", "grapes",
            "guts", "horse", "kelp", "mango", "milk", "nectar",
            "pepper", "potato", "pumpkin", "salt"
    };
    private static final int WINDOW_WIDTH = 400;
    private static final int WINDOW_HEIGHT = 400;
    private static final int GRID_ROWS = 8;
    private static final int GRID_COLUMNS = 2;
    private static final int UPDATE_INTERVAL_MS = 500;

    private final List<JCheckBox> ingredientCheckBoxes = new ArrayList<>();
    private final JTextField resultField = new JTextField("hai :D");
    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    public SmoothieApp(List<Smoothie> smoothies) {
        JFrame frame = initializeUI(smoothies);
        startSmoothieUpdater(smoothies);
        frame.setVisible(true);
    }

    private JFrame initializeUI(List<Smoothie> smoothies) {
        JFrame frame = new JFrame("Smoothie Maker");
        frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        frame.setLayout(new BorderLayout(10, 10));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        frame.add(createIngredientPanel(), BorderLayout.WEST);
        frame.add(resultField, BorderLayout.CENTER);
        frame.add(createCalculateButton(smoothies), BorderLayout.EAST);

        resultField.setEditable(false);

        return frame;
    }

    private JPanel createIngredientPanel() {
        JPanel panel = new JPanel(new GridLayout(GRID_ROWS, GRID_COLUMNS));
        for (String ingredient : INGREDIENTS_LIST) {
            JCheckBox checkBox = new JCheckBox(ingredient);
            ingredientCheckBoxes.add(checkBox);
            panel.add(checkBox);
        }
        return panel;
    }

    private JButton createCalculateButton(List<Smoothie> smoothies) {
        JButton calculateButton = new JButton("Calculate");
        calculateButton.addActionListener(e -> displayPossibleSmoothies(smoothies));
        return calculateButton;
    }

    private void displayPossibleSmoothies(List<Smoothie> smoothies) {
        System.out.println("\n=== SMOOTHIES YOU CAN MAKE ===");
        boolean smoothiesFound = false;

        for (Smoothie smoothie : smoothies) {
            Ingredients ingredients = smoothie.getIngredients();
            if (canMakeSmoothie(ingredients)) {
                smoothiesFound = true;
                System.out.printf("Smoothie: %s%n", smoothie.getName());
                System.out.printf("  - Required: %s%n", String.join(", ", ingredients.getRequired()));
                System.out.printf("  - Optional: %s%n%n", String.join(", ", ingredients.getOptional()));
            }
        }

        if (!smoothiesFound) {
            System.out.println("No smoothies can be made with the selected ingredients.");
        }

        System.out.println("================================");
    }

    private boolean canMakeSmoothie(Ingredients ingredients) {
        return ingredients.getRequired().stream().anyMatch(this::isIngredientSelected) &&
                ingredients.getOptional().stream().anyMatch(this::isIngredientSelected);
    }

    private boolean isIngredientSelected(String ingredient) {
        return ingredientCheckBoxes.stream()
                .anyMatch(box -> box.getText().equals(ingredient) && box.isSelected());
    }

    private void startSmoothieUpdater(List<Smoothie> smoothies) {
        executor.submit(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    int smoothieCount = calculateSmoothiesCount(smoothies);
                    SwingUtilities.invokeLater(() -> resultField.setText(String.valueOf(smoothieCount)));
                    Thread.sleep(UPDATE_INTERVAL_MS);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
    }

    private int calculateSmoothiesCount(List<Smoothie> smoothies) {
        int count = 0;
        for (Smoothie smoothie : smoothies) {
            Ingredients ingredients = smoothie.getIngredients();
            if (canMakeSmoothie(ingredients)) {
                count++;
            }
        }
        return count;
    }

    public static void main(String[] args) {
        Yaml yaml = new Yaml(new Constructor(SmoothiesWrapper.class, new LoaderOptions()));

        try (InputStream inputStream = SmoothieApp.class.getClassLoader().getResourceAsStream("smoothies.yaml")) {
            if (inputStream == null) {
                throw new RuntimeException("smoothies.yaml not found");
            }

            SmoothiesWrapper wrapper = yaml.load(inputStream);
            SwingUtilities.invokeLater(() -> new SmoothieApp(wrapper.getSmoothies()));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("Failed to load YAML", e);
        }
    }
}
package org.example.smoothies.model;

import java.util.*;
import lombok.*;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class SmoothiesWrapper {
    private List<Smoothie> smoothies;
}
package org.example.smoothies.model;

import lombok.*;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Smoothie {
    private String name;
    private Ingredients ingredients;
}
package org.example.smoothies.model;

import lombok.*;
import java.util.*;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Ingredients {
    private List<String> required;
    private List<String> optional;
}

Note: I generated a YAML file (smoothies.yaml) based on all the smoothie possibilities from your original code:

smoothies:
  - name: Nectar Smoothie
    ingredients:
      required: ["nectar"]
      optional: ["nectar"]
  - name: Nectar Milkshake
    ingredients:
      required: ["nectar"]
      optional: ["milk"]
  - name: Grape Smoothie
    ingredients:
      required: ["grapes"]
      optional: ["grapes"]
  - name: Grape Medley
    ingredients:
      required: ["grapes"]
      optional: ["horse", "apple", "cactus", "salt", "butter", "mango"]
  - name: Grape Nectar Blend
    ingredients:
      required: ["grapes"]
      optional: ["nectar"]
  - name: Grape Milkshake
    ingredients:
      required: ["grapes"]
      optional: ["milk"]
  - name: Double Milkshake
    ingredients:
      required: ["milk"]
      optional: ["milk"]
  - name: Milk Cactus Delight
    ingredients:
      required: ["milk"]
      optional: ["apple", "cactus"]
  - name: Milk with a Dash of Salt
    ingredients:
      required: ["milk"]
      optional: ["salt"]
  - name: Mango Puree
    ingredients:
      required: ["mango"]
      optional: ["mango"]
  - name: Mango Adventure
    ingredients:
      required: ["mango"]
      optional: ["kelp", "apple", "cactus", "butter"]
  - name: Nectar Mango Fusion
    ingredients:
      required: ["nectar"]
      optional: ["mango"]
  - name: Milk Mango Smoothie
    ingredients:
      required: ["milk"]
      optional: ["mango"]
  - name: Salted Mango Smoothie
    ingredients:
      required: ["salt"]
      optional: ["mango"]
  - name: Cactus Delight
    ingredients:
      required: ["cactus"]
      optional: ["cactus", "horse", "nectar", "pumpkin"]
  - name: Cactus and Salt Combo
    ingredients:
      required: ["cactus"]
      optional: ["salt"]
  - name: Pepper Explosion
    ingredients:
      required: ["pepper"]
      optional: ["pepper"]
  - name: Spicy Cactus Pumpkin Mix
    ingredients:
      required: ["pepper"]
      optional: ["cactus", "pumpkin"]
  - name: Pepper Potato Mashup
    ingredients:
      required: ["pepper"]
      optional: ["potato"]
  - name: Pepper Grape Smoothie
    ingredients:
      required: ["pepper"]
      optional: ["grapes", "apple", "milk", "mango"]
  - name: Apple Smoothie
    ingredients:
      required: ["apple"]
      optional: ["apple"]
  - name: Apple Adventure
    ingredients:
      required: ["apple"]
      optional: ["horse", "nectar", "cactus", "potato"]
  - name: Salted Apple Mix
    ingredients:
      required: ["apple"]
      optional: ["salt"]
  - name: Kelp Smoothie
    ingredients:
      required: ["kelp"]
      optional: ["kelp"]
  - name: Kelp Fruit Blend
    ingredients:
      required: ["kelp"]
      optional: ["grapes", "apple", "potato"]
  - name: Pumpkin with a Hint of Kelp
    ingredients:
      required: ["kelp"]
      optional: ["pumpkin"]
  - name: Kelp Milkshake
    ingredients:
      required: ["kelp"]
      optional: ["milk"]
  - name: Salted Kelp Smoothie
    ingredients:
      required: ["kelp"]
      optional: ["salt"]
  - name: Horsepower Smoothie
    ingredients:
      required: ["horse"]
      optional: ["horse", "kelp", "pepper", "nectar", "potato", "salt", "mango"]
  - name: Horse Milkshake
    ingredients:
      required: ["horse"]
      optional: ["milk"]
  - name: Potato Smoothie
    ingredients:
      required: ["potato"]
      optional: ["potato"]
  - name: Potato Grape Mashup
    ingredients:
      required: ["potato"]
      optional: ["grapes", "cactus", "butter"]
  - name: Potato Nectar Blend
    ingredients:
      required: ["nectar"]
      optional: ["potato"]
  - name: Milk Potato Mix
    ingredients:
      required: ["milk"]
      optional: ["potato"]
  - name: Mango Potato Fusion
    ingredients:
      required: ["potato"]
      optional: ["mango"]
  - name: Salted Potato
    ingredients:
      required: ["potato"]
      optional: ["salt"]
  - name: Butter Smoothie
    ingredients:
      required: ["butter"]
      optional: ["butter", "kelp"]
  - name: Apple Butter Delight
    ingredients:
      required: ["apple"]
      optional: ["butter"]
  - name: Cactus Butter Smoothie
    ingredients:
      required: ["cactus"]
      optional: ["butter"]
  - name: Butter Nectar Mix
    ingredients:
      required: ["nectar"]
      optional: ["butter"]
  - name: Butter Pumpkin Smoothie
    ingredients:
      required: ["butter"]
      optional: ["pumpkin"]
  - name: Milk Butter Combo
    ingredients:
      required: ["milk"]
      optional: ["butter"]
  - name: Salted Butter Mix
    ingredients:
      required: ["salt"]
      optional: ["butter"]
  - name: Pumpkin Delight
    ingredients:
      required: ["pumpkin"]
      optional: ["pumpkin"]
  - name: Pumpkin Harvest
    ingredients:
      required: ["pumpkin"]
      optional: ["horse", "grapes", "apple", "potato"]
  - name: Pumpkin Nectar Smoothie
    ingredients:
      required: ["nectar"]
      optional: ["pumpkin"]
  - name: Milk Pumpkin Fusion
    ingredients:
      required: ["milk"]
      optional: ["pumpkin"]
  - name: Pumpkin Mango Smoothie
    ingredients:
      required: ["pumpkin"]
      optional: ["mango"]
  - name: Salted Pumpkin Blend
    ingredients:
      required: ["salt"]
      optional: ["pumpkin"]
  - name: Egg Smoothie
    ingredients:
      required: ["egg"]
      optional: ["egg", "grapes", "nectar", "milk", "salt"]
  - name: Mango Egg Mix
    ingredients:
      required: ["egg"]
      optional: ["mango"]
  - name: Egg and Cactus Combo
    ingredients:
      required: ["egg"]
      optional: ["cactus"]
  - name: Spicy Egg
    ingredients:
      required: ["egg"]
      optional: ["pepper"]
  - name: Apple Egg Delight
    ingredients:
      required: ["egg"]
      optional: ["apple"]
  - name: Egg and Kelp Mix
    ingredients:
      required: ["egg"]
      optional: ["kelp"]
  - name: Horse Egg Smoothie
    ingredients:
      required: ["egg"]
      optional: ["horse"]
  - name: Potato Egg Combo
    ingredients:
      required: ["egg"]
      optional: ["potato"]
  - name: Buttered Egg Delight
    ingredients:
      required: ["egg"]
      optional: ["butter"]
  - name: Pumpkin Egg Fusion
    ingredients:
      required: ["egg"]
      optional: ["pumpkin"]
  - name: Gutsy Mango Mix
    ingredients:
      required: ["guts"]
      optional: ["mango"]
  - name: Guts and Cactus Combo
    ingredients:
      required: ["guts"]
      optional: ["cactus"]
  - name: Fang Pepper Mashup
    ingredients:
      required: ["fang"]
      optional: ["pepper"]
  - name: Gutsy Pepper Smoothie
    ingredients:
      required: ["guts"]
      optional: ["pepper"]
  - name: Apple Guts Smoothie
    ingredients:
      required: ["guts"]
      optional: ["apple"]
  - name: Fang Kelp Mix
    ingredients:
      required: ["fang"]
      optional: ["kelp"]
  - name: Horse Fang Smoothie
    ingredients:
      required: ["fang"]
      optional: ["horse"]
  - name: Potato Fang Delight
    ingredients:
      required: ["fang"]
      optional: ["potato"]
  - name: Butter Fang Fusion
    ingredients:
      required: ["fang"]
      optional: ["butter"]
  - name: Pumpkin Fang Combo
    ingredients:
      required: ["fang"]
      optional: ["pumpkin"]

Upvotes: 0

Related Questions