Создание графического интерфейса Java Swing - как правильно обновить динамически созданные кнопки

Мой университетский проект состоит в том, чтобы создать работающий графический интерфейс для приложения автостоянки, которое я сделал для более раннего проекта.

Автостоянка состоит из парков для персонала и парков для посетителей, и графический интерфейс создает кнопки для каждой из них, динамически зависящие от того, сколько из них пользователь хочет добавить.

Проблема, с которой я столкнулся, заключается в том, что после того, как я изначально создал свою автостоянку и принял пользовательский ввод для парков персонала / посетителей, парки отображаются, как предполагалось, за исключением того, что нажатие на каждый парк для получения информации не работает.

Когда я использую опцию «Добавить автомобиль», несмотря на то, в какой слот я пытаюсь добавить автомобиль, он обновляет только конечный парк для посетителей... например, если есть 5 парков для персонала и посетителей, и я добавляю автомобиль в слот S001, изменения отразятся на слоте V005.

PS. Я новичок в программировании, поэтому извините, если формат и логика неверны. Кроме того, мы должны использовать IDE под названием BlueJ, и для этого проекта нам не разрешено использовать любую IDE, в которой есть создатель графического интерфейса.

Мы будем очень благодарны за любые советы.

Спасибо, Майкл

Пакет состоит из 4 классов: GUI, CarPark, ParkingSlot и Car.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.regex.*;

public class GUI extends JFrame 
{
    private JPanel panel;
    private JButton but1;
    private JButton but2;
    private JButton but3; 
    private JButton but4;
    private JButton but5;
    private JButton but6;
    private JButton button;

    private static CarPark cp1 = new CarPark();
    private static ParkingSlot ps = new ParkingSlot("", true, null);
    public static final int YES_NO_OPTION = 0;

    public static void main(String[] args)
    {
        JFrame myApp = new GUI();
        myApp.setVisible(true);
    }

    public GUI()
    {
        //set size
        super("Car Park Application");
        
        createCarPark();
        addButtons();
        addListeners();

    }
   
    
    public void createCarPark()
    {
        
        JPanel staffFrame = new JPanel();
        JPanel visitorFrame = new JPanel();
        JPanel middle = new JPanel(new FlowLayout(FlowLayout.CENTER,100,10)); //panel to have staff/visitor parks

        middle.add(staffFrame);
        middle.add(visitorFrame);

        add(middle, BorderLayout.CENTER);
        // add a scrollpane
        JScrollPane scrollPane = new JScrollPane(middle);
        setPreferredSize(new Dimension(600, 400));
        add(scrollPane, BorderLayout.CENTER);

        int i = 0, j = 0;
        String staffSlotNumber = "", visitorSlotNumber = ""; 
        int staffSlots = Integer.parseInt(JOptionPane.showInputDialog(this,
                    "How many staff parks do you need?", "Create Staff Parks", 2));
        int visitorSlots = Integer.parseInt(JOptionPane.showInputDialog(this,
                    "How many visitor parks do you need?", "Create Visitor Parks", 2));
        JOptionPane.showMessageDialog(this,"Staff parks created: " + staffSlots +
            "\nVisitor parks created: " + visitorSlots,
            "Car Park Created!",JOptionPane.WARNING_MESSAGE );  
        //Create the actual car park
        while (i < staffSlots)
        {
            if (i <9) 
            {
                staffSlotNumber = "S00";
            } 
            else if (i <99)
            {
                staffSlotNumber = "S0";
            }
            else if (i <999)
            {
                staffSlotNumber = "S";
            }
            else 
            { 
                JOptionPane.showMessageDialog(this,"No parks created. Exit and try again.",
                    "Massive error. Exit and try again.",JOptionPane.WARNING_MESSAGE );  
            }
            ParkingSlot ps = new ParkingSlot(staffSlotNumber+(i+1), true, null);
            cp1.addParkingSlot(ps);  
            button = new JButton(ps.toString());
            staffFrame.add(button);
            i++;
        }

        while (j < visitorSlots)
        {
            //
            if (j <9) 
            {
                visitorSlotNumber = "V00";
            } 
            else if (j <99)
            {
                visitorSlotNumber = "V0";
            }
            else if (j <999)
            {
                visitorSlotNumber = "V";
            }
            else
            {
                JOptionPane.showMessageDialog(this,"No parks created. Exit and try again.",
                    "Massive error. Exit and try again.",JOptionPane.WARNING_MESSAGE );
            }
            //
            ParkingSlot ps = new ParkingSlot(visitorSlotNumber+(j+1), false, null);
            cp1.addParkingSlot(ps); 
            button = new JButton(ps.toString());
            visitorFrame.add(button);
            j++;
        }

        staffFrame.setLayout(new GridLayout(staffSlots,1));
        visitorFrame.setLayout(new GridLayout(visitorSlots,1));
        setSize(1200,600);
        setVisible(true);
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    } 
    
    public void addButtons()
    {
        but1 = new JButton("Add Car");
        but2 = new JButton("Remove Car");
        but3 = new JButton("Find Car");
        but4 = new JButton("Add Car Park");
        but5 = new JButton("Remove Car Park");
        but6 = new JButton("Exit");

        JPanel buttonPanel = new JPanel( );
        buttonPanel.setLayout(new GridLayout(2,3));
        buttonPanel.add(but1);
        buttonPanel.add(but2);
        buttonPanel.add(but3);
        buttonPanel.add(but4);
        buttonPanel.add(but5);
        buttonPanel.add(but6);

        add(buttonPanel, BorderLayout.SOUTH);
    }

    public void addListeners()
    {
        //add listeners
        but1.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    addCar();
                }
            });

        but2.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    removeCar();
                }
            });
        but3.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    findCar();
                }
            });
        but4.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    addPark();  

                }
            });
        but5.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    removePark();
                }
            });

        but6.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    exitApp();
                }
            });     

        button.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    button.setText(ps.toString());
                }
            });             
        pack();
    }

        public void addCar()
    {
        boolean staff;
        String staffStr;
        String carRego = "";
        do
        {
            carRego = JOptionPane.showInputDialog(this,
                "Please input a registration to add.\nUse format A12345", "Add Car - Registration", 3);
        } while (!Pattern.matches("[A-Z]{1}[0-9]{5}", carRego));

        String driverName = JOptionPane.showInputDialog(this,
                "What is the driver's name?", "Add Car - Driver's Name", 3);
        //send carRego to the CarPark class

        String slotId = "";
        do
        {
            slotId = JOptionPane.showInputDialog(this, 
                "Please input a slot ID.\nUse format S001", "Add Car - Slot ID", 3);
        } while (!slotId.matches("[SV][0-9][0-9][0-9]"));

        //if (slotId.charAt(0) == 'S')

        int choice = JOptionPane.showConfirmDialog(this,
                "Is this person a staff member?", "Staff Member?", JOptionPane.YES_NO_OPTION);

        if (choice == JOptionPane.YES_OPTION)
        {
            staff = true;
            staffStr = "They are a staff member.";
        } else 
        {
            staff = false;
            staffStr = "They are a visitor.";
        }

        JOptionPane.showMessageDialog(this,"You have entered the registration: " + carRego +
            "\nYou have entered the name: " + driverName +
            "\nYou have entered the slot ID: " + slotId +
            "\n" + staffStr,
            "Registration and Slot ID Confirmation",JOptionPane.INFORMATION_MESSAGE );

        Car car = new Car(carRego, driverName, staff);

        ParkingSlot ps;
        ps = cp1.findParkingSlot(slotId);  

        //staff-visitor check
        if (ps == null)
        {
            //System.out.println("Please pick an existing car space.");
            JOptionPane.showMessageDialog( 
                this, 
                "Please pick an existing car space.",
                "Park doesn't exist.",
                JOptionPane.PLAIN_MESSAGE);
        }
        else if (ps.hasCar())
        {
            //System.out.println("There is already a car in that place.");
            JOptionPane.showMessageDialog( 
                this, 
                "There is already a car in that place.",
                "Park doesn't exist.",
                JOptionPane.PLAIN_MESSAGE);
        }
        else if (ps.getStaffPark() == true && staff == false)
        {
            //System.out.println("You cannot put a visitor in a staff park.");
            JOptionPane.showMessageDialog( 
                this, 
                "You cannot put a visitor in a staff park.",
                "Park doesn't exist.",
                JOptionPane.PLAIN_MESSAGE);
        }
        else if (ps.getStaffPark() == false && staff == true)
        {
            //System.out.println("You cannot put staff in a visitor park.");
            JOptionPane.showMessageDialog( 
                this, 
                "You cannot put staff in a visitor park.",
                "Park doesn't exist.",
                JOptionPane.PLAIN_MESSAGE);
        }
        else
        {
            //successful details are stored and output.
            ps.setSlotNumber(slotId);
            ps.setStaffPark(staff);
            ps.parkCar(car);
            button.setText(ps.toString());
            revalidate();
            repaint();
            JOptionPane.showMessageDialog( 
                this, 
                "Success!\nYou added: " + carRego + " to park " + slotId + "." ,
                "Parking Spot Addition",
                JOptionPane.PLAIN_MESSAGE);

        }

    }

    public void removeCar()
    {

        String carRego = "";
        do
        {
            carRego = JOptionPane.showInputDialog(this,
                "Which registration? Use format A12345", "Remove Car", 3);
        } while (!carRego.matches("[A-Z][0-9]{5}"));

        ParkingSlot ps = cp1.findCar(carRego);

        if (ps != null)
        {
            ps.removeCar();
            JOptionPane.showMessageDialog(this,"You have REMOVED the registration: " + carRego,
                "Registration Removal Confirmation",JOptionPane.WARNING_MESSAGE );
        }
        else 
        {
            JOptionPane.showMessageDialog(this,"Car registration " + carRego + " does not exist.",
                "Registration Removal Failure",JOptionPane.WARNING_MESSAGE );
        }
    }

    public void findCar()
    {
        //declare variables
        String carRego = "";
        String slotNumber;
        ParkingSlot ps;

        //prompt user with registration format check
        do
        {
            carRego = JOptionPane.showInputDialog(this,
                "Please enter car registration (eg A12345):", "Find Car", 2);
        } while (!carRego.matches("[A-Z][0-9]{5}"));

        //find car rego in carpark array list
        ps = cp1.findCar(carRego);
        //check for incorrect format/inputs
        if(ps == null)
        {
            JOptionPane.showMessageDialog(this,"Car registration " + carRego + " does not exist.",
                "Find Car - Unsuccessful",JOptionPane.WARNING_MESSAGE );

        }
        else
        {
            JOptionPane.showMessageDialog(this, "Success, the car has been found!\nOwner: "+ ps.getCar().getName() 
                + "\nRegistration: " + ps.getCar().getRego() 
                + "\nCar park location: [" + ps.getSlotNumber() + "]",

                "Find Car - Successful",JOptionPane.WARNING_MESSAGE );

        }

    }

    public void addPark()
    {
        String slotNumber = "";
        do 
        {
            slotNumber = JOptionPane.showInputDialog(this, 
                "Please input a new car park ID to add to the car park eg S001", "Add a new slot ID", 2);
        } while (!slotNumber.matches("[SV]\\d\\d\\d"));
        JOptionPane.showMessageDialog(this,"You have ADDED to the car park: " + slotNumber,
            "Add a new parking spot",JOptionPane.INFORMATION_MESSAGE );

        ParkingSlot ps;
        Car car = null;

        boolean staff;
        if (slotNumber.toUpperCase().charAt(0) == 'S')
        {
            staff = true;
        }
        else
        {
            staff = false;
        }

        ps = cp1.findParkingSlot(slotNumber);

        if (ps != null)
        {
            JOptionPane.showMessageDialog(this,"This parking slot number already exists. Choose another." 
            + slotNumber,"Add a new parking spot",JOptionPane.INFORMATION_MESSAGE );
           
            return;
        }
        else
        {
            cp1.addParkingSlot(new ParkingSlot(slotNumber,staff, car));
            JOptionPane.showMessageDialog(this,"Sucess! You have added slot: " 
            + slotNumber,"Add a new parking spot",JOptionPane.INFORMATION_MESSAGE );
        }

        //System.out.println("New slot " + slotNumber + " has been added to the car park.");
        System.out.println(cp1.toString());

    }

    public void removePark()
    {
        String slotNumber;
        ParkingSlot ps;
       
        do 
        {
            slotNumber = JOptionPane.showInputDialog(this, 
                "Please input an existing parking spot to REMOVE from the car park", "Remove Park", 2);
            //System.out.println("Which park would you like to remove? Enter slot number");
            //slotNumber = input.nextLine();
        } while (!slotNumber.matches("[SV]\\d\\d\\d"));

        ps = cp1.findParkingSlot(slotNumber);

        if (ps != null) 
        {
            if (ps.hasCar())
            {
                JOptionPane.showMessageDialog(this,"The parking slot is occupied, you cannot remove it.",
            "Remove Park - Unsuccessful",JOptionPane.WARNING_MESSAGE );
                //System.out.println("The parking slot is occupied, you cannot remove it.");
            }
            else
            {
                cp1.removeParkingSlot(ps);
                JOptionPane.showMessageDialog(this,"Parking slot :" + slotNumber 
                + " was vacant, and has been removed.",
            "Remove park - Successful",JOptionPane.WARNING_MESSAGE );
                //System.out.println("Parking slot " + slotNumber + " was vacant, and has been removed.");
            }
        }
        else
        {
             JOptionPane.showMessageDialog(this,"The parking slot doesn't exist",
            "Remove Park - Unsuccessful",JOptionPane.WARNING_MESSAGE );
            //System.out.println("Unable to perform action. That parking slot does not exist");
        }
        if (cp1.numberOfparks() == 0)
        {
             JOptionPane.showMessageDialog(this,"All parks removed",
            "Remove Park - Successful",JOptionPane.WARNING_MESSAGE );System.out.println("All parks have been removed.");
        }
    }

    public void exitApp()
    {
        System.exit(0);
    }

}

import java.util.ArrayList; 

public class CarPark { 


     public ArrayList<ParkingSlot> parks;
    
    
    public CarPark() 
    {
        
        parks = new ArrayList<ParkingSlot>();   
    }

    
    public ArrayList<ParkingSlot> getParks()
    {
        return parks;
    }

    
    public String toString()
    {

        String parkingString = "";
        for (ParkingSlot parkingSlot : parks)
        {
            parkingString += parkingSlot.toString() + "\n";
        }
        if (parkingString.equals(""))
        {
            parkingString = "No parking spots exist.";
        }
        return parkingString;
    }

   
    public void addParkingSlot(ParkingSlot parkingSlot)
    {
        parks.add(parkingSlot);    
    }

   
    public void removeParkingSlot(ParkingSlot parkingSlot) 
    {
        parks.remove(parkingSlot);
    }

   
    public int numberOfparks() 
    {
        return parks.size();
    }

   
    public ParkingSlot findParkingSlot(String slotNumber)
    {
        for (ParkingSlot parkingSlot : parks) 
        {
            if (parkingSlot.getSlotNumber().equals(slotNumber))
            {
                return parkingSlot;
            }
        }
        return null;
    }
    
    
    public ParkingSlot findCar(String findRego)
    {
        ParkingSlot ps = null;
        for(int i = 0; i < parks.size(); i++)
        {
            ps = parks.get(i);
            
            // check to see if there's a car object in a park.
            Car car = ps.getCar();

            if(car != null && findRego.equals(car.getRego()))
                return ps;
        }
        return null;
    }
}

public class ParkingSlot
 {

    //variables required for parking slot.
    private String slotNumber;
    private boolean staffPark;
    private Car car; 

   
    public ParkingSlot(String slotNumber, boolean staffPark, Car car)
    {
        this.slotNumber = slotNumber;
        this.staffPark = staffPark;
        this.car = null;        
    }

    
    public String getSlotNumber()
    {
        return slotNumber;
    }

   
    public void setSlotNumber(String newSlotNumber)
    {
        slotNumber = newSlotNumber;
    }

   
    public boolean getStaffPark()
    {
        return staffPark;
    }

    
    public void setStaffPark(boolean newStaffPark)
    {
        staffPark = newStaffPark;
    }

    
    public Car getCar()
    {
        return car;
    }

    public void parkCar(Car car)
    {
        this.car = car;
    }

    public void removeCar()
    {
        car = null;
    }

   
    public boolean hasCar()
    {
        return this.car != null;
    }

    
    public String toString()
    { 
        //String staffOrVisitor = "] [ Staff Park ] ";
        String staffOrVisitor = "Park: ";
        String taken = "is taken";

        if (staffPark == false)
        {
            //staffOrVisitor = "] [Visitor Park] ";
            staffOrVisitor = "Park: ";
        }
        if (car == null)
        {
            taken = " [vacant]";
        }
        else
        {
            taken = "  contains vehicle, registration [" + car.getRego() + "]";
        }
        return staffOrVisitor + slotNumber + taken;
       // return "Park [" + slotNumber + staffOrVisitor + taken; 
    }    
}

public class Car {

    // instance variables 
    private String rego;
    private String name;
    private boolean staff;

    
    public Car(String rego, String name, boolean staff)
    {
        this.rego = rego;
        this.name = name;
        this.staff = staff;
    }

   
    public String toString() 
    {
        return "Registration " + rego + " - Name: " + name + " - Staff member: " + staff;    
    }

  
    public String getRego(){
        return rego;
    }

    
    public void setRego(String newRego){
        rego = newRego;
    }

   
    public String getName(){
        return name;
    }

    
    public void setName(String newName){
        name = newName;
    }

   
    public boolean getStaff(){
        return staff;
    }

  
    public void setStaff(boolean newStaff){
        staff = newStaff;
    }

}



person BRBCycling    schedule 22.05.2021    source источник
comment
Это много кода, совершенно не связанного с рассматриваемой проблемой. Подумайте о сокращении, упрощении, создании и публикации новой программы, которая компилируется и запускается, которая иллюстрирует, но не делает ничего другого, минимальный воспроизводимый пример. Иначе за деревьями здесь трудно увидеть лес. Пожалуйста, прочитайте ссылку, так как она объясняет детали этого полезного инструмента.   -  person Hovercraft Full Of Eels    schedule 22.05.2021
comment
Спасибо @HovercraftFullOfEels и извините. Я новичок в этом. Я попробую сделать то, что вы предложили.   -  person BRBCycling    schedule 22.05.2021
comment
Спасибо, также используйте самокомментирующие имена переменных, имена, которые делают ваш код более интуитивно понятным для других. Например, что имеет больше смысла и облегчает чтение кода: переменная с именем but2 или переменная с именем removeCarButton?   -  person Hovercraft Full Of Eels    schedule 22.05.2021
comment
Кроме того, вы, кажется, пытаетесь использовать структуру программы типа модель-представление, отличная идея, но ваша модель и ваше представление, похоже, не связаны значимым образом.   -  person Hovercraft Full Of Eels    schedule 22.05.2021
comment
Когда вы вызываете addCar(), вы изменяете состояние переменной button, которая ссылается на последнюю кнопку JButton, которую вы добавили на парковку. Зачем ты это делаешь? Разве вы не хотите изменить состояние кнопки, которая относится к соответствующему слоту? Опять же, ваша модель и ваше представление никак не связаны друг с другом.   -  person Hovercraft Full Of Eels    schedule 22.05.2021
comment
Кнопки — честно говоря, я планировал привести код в порядок и добавить комментарии ближе к концу проекта. Я раньше не слышал о подходе модель-представление, и поэтому я не совсем уверен, как сделать так, чтобы они осмысленно соотносились. addCar() - я хотел бы обновить соответствующий слот, но не знаю, как это сделать, и это была моя лучшая попытка. В этой теме есть много отдельных сценариев, но ничто не сосредоточено на том, как сделать хороший дизайн и как заставить все части головоломки работать вместе. Отсюда идут яично-молочные сливки и сахар, теперь вы знаете, как приготовить суфле.   -  person BRBCycling    schedule 22.05.2021
comment
Я планировал привести код в порядок и добавить комментарии ближе к концу проекта. -- нет, я не имею в виду комментарии, опять же я имею в виду полезные умные имена переменных, имена, которые самокомментируют. Это должно быть сделано с самого начала, а не в качестве уборки в конце.   -  person Hovercraft Full Of Eels    schedule 22.05.2021
comment
@HovercraftFullOfEels Я позабочусь о том, чтобы в будущем с самого начала использовать осмысленные имена переменных.   -  person BRBCycling    schedule 22.05.2021


Ответы (1)


Опять же, проблема заключается в создании модели и ее привязке к вашему представлению (графическому интерфейсу). Лучше всего создать и поддерживать хорошее разделение между этими двумя классами или группами классов, но для простоты в этом случае мы можем объединить их в графическом интерфейсе. Чтобы показать вам, что я имею в виду, рассмотрите это упрощение вашего кода, в котором используются очень простые классы Car и ParkingSlot:

public class Car {
    private String name;

    public Car(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Car: " + name;
    }
}
public class ParkingSlot {
    private Car car;
    private String name;

    public ParkingSlot(String name) {
        this.name = name;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public Car getCar() {
        return car;
    }

    public void clear() {
        car = null;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        String value = "Slot: " + name + "; ";
        if (car == null) {
            value += "empty";
        } else {
            value += car.toString();
        }
        return value;
    }
}

Мне нужна модель, которая связывает String с ParkingSlot, и для этого лучше всего использовать Map<String, ParkingSlot>. Это коллекция, которая содержит объекты ParkingSlot и делает их доступными по имени слота — String. Я бы часто инициализировал это как new HashMap<String, ParkingSlot>(), но я также хочу поддерживать порядок вставки на карте, чтобы, если я буду повторять его, он не был в каком-то случайном порядке (как это обычно бывает в HashMaps), и поэтому я бы инициализировал это с использованием LinkedHashMap<String, ParkingSlot>, так как это похоже на HashMap, но сохраняет порядок вставки:

private Map<String, ParkingSlot> slotMap = new LinkedHashMap<>();

Итак, если позже я захочу перебрать коллекцию, отобразить статус объектов ParkingSlot, я мог бы просто использовать цикл for:

for (Entry<String, ParkingSlot> entry : slotMap.entrySet()) {
    System.out.printf("%s%n", entry.getValue());
}

Итак, теперь при создании сетки JButton свяжите ее с коллекцией объектов ParkingSlot, используя строку, определяющую слот. Это может быть key для Map, а также может быть связано с JButton, используя его для установки actionCommand кнопки, строки, которую несет с собой каждая кнопка:

JPanel gridPanel = new JPanel(new GridLayout(0, 1));
for (int i = 0; i < slotCount; i++) {
    String slotName = String.format("V%03d", i);
    ParkingSlot slot = new ParkingSlot(slotName);
    slotMap.put(slotName, slot);

    JButton button = new JButton(slotName + ": Empty");
    button.setActionCommand(slotName);
    button.addActionListener(e -> parkingSlotButtonAction(e));
    gridPanel.add(button);
}

При нажатии любой из кнопок вызывается метод parkingSlotButtonAction(ActionEvent e), и он может получить исходную кнопку JButton, вызвав e.getSource() для параметра, и может получить actionCommand кнопки, вызвав e.getActionCommand() для того же параметра. Он может получить связанный объект ParkingSlot, используя slotMap:

private void parkingSlotButtonAction(ActionEvent e) {
    String slotName = e.getActionCommand();
    JButton source = (JButton) e.getSource();
    ParkingSlot slot = slotMap.get(slotName);
    
    // .....
}

Полный простой пример может выглядеть так:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.*;
import javax.swing.event.ChangeListener;

public class SimpleLotMain {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            LotGui gui = new LotGui(20);

            JFrame frame = new JFrame("Lot");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(gui);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

@SuppressWarnings("serial")
class LotGui extends JPanel {
    private Map<String, ParkingSlot> slotMap = new LinkedHashMap<>();

    public LotGui(int slotCount) {
        JPanel gridPanel = new JPanel(new GridLayout(0, 1));
        for (int i = 0; i < slotCount; i++) {
            String slotName = String.format("V%03d", i);
            ParkingSlot slot = new ParkingSlot(slotName);
            slotMap.put(slotName, slot);

            JButton button = new JButton(slotName + ": Empty");
            button.setActionCommand(slotName);
            button.addActionListener(e -> parkingSlotButtonAction(e));
            gridPanel.add(button);
        }

        JScrollPane scrollPane = new JScrollPane(gridPanel);
        scrollPane.getViewport().setPreferredSize(new Dimension(400, 400));

        JButton displaySlotsBtn = new JButton("Display Parking Spots");
        displaySlotsBtn.addActionListener(e -> displaySlots());

        JPanel bottomPanel = new JPanel();
        bottomPanel.add(displaySlotsBtn);

        setLayout(new BorderLayout());
        add(scrollPane);
        add(bottomPanel, BorderLayout.PAGE_END);
    }

    private void parkingSlotButtonAction(ActionEvent e) {
        String slotName = e.getActionCommand();
        JButton source = (JButton) e.getSource();
        ParkingSlot slot = slotMap.get(slotName);

        // JOptionPane to query whether to add/remove car

        String carName = JOptionPane.showInputDialog("Enter Name of Car to Add");

        // if the user cancels the dialog or enters only white-space text: exit
        if (carName == null || carName.trim().isEmpty()) {
            return;
        }

        // else, use the name
        Car car = new Car(carName);
        slot.setCar(car);

        String text = slotName + ": " + carName;
        source.setText(text);
    }

    private void displaySlots() {
        for (Entry<String, ParkingSlot> entry : slotMap.entrySet()) {
            System.out.printf("%s%n", entry.getValue());
        }
    }

}

//class SLot {
//  List<ParkingSlot> slots = new ArrayList<>();
//
//  public SLot(int carCount) {
//      for (int i = 0; i < carCount; i++) {
//          String name = String.format("S%03d", i);
//          slots.add(new ParkingSlot(name));
//      }
//  }
//
//  @Override
//  public String toString() {
//      return "SLot [slots=" + slots + "]";
//  }
//
//  public void addChangeListener(ChangeListener l) {
//
//  }
//}

class Car {
    private String name;

    public Car(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Car: " + name;
    }
}

class ParkingSlot {
    private Car car;
    private String name;

    public ParkingSlot(String name) {
        this.name = name;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public Car getCar() {
        return car;
    }

    public void clear() {
        car = null;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        String value = "Slot: " + name + "; ";
        if (car == null) {
            value += "empty";
        } else {
            value += car.toString();
        }
        return value;
    }
}
person Hovercraft Full Of Eels    schedule 22.05.2021
comment
Я многого там не понимаю, но я пойду читать! Я никогда не слышал о HashMap, похоже, он связан с ArrayList. Я также не знаком с @override и как/зачем его использовать. Я также не видел setActionCommand, и только что прочитал о лямбда-выражениях на прошлой неделе, у меня впереди кривая обучения. Столько всего нужно прочитать и проверить. Я не знаю, смогу ли я реализовать эти функции в своем задании, но это кажется более полезным, чем некоторый контент, с которым я столкнулся. Еще раз спасибо на воздушной подушке. - person BRBCycling; 23.05.2021