Home > Enterprise >  Can I make a for statement with the names of JButtons?
Can I make a for statement with the names of JButtons?

Time:12-27

I'm programming a calendar for only one year in NetBeans and for the GUI I plan to have the typical calendar a spinner for the year. This combination will determine in which day of the week does de first and last day of the month goes.

The problem I have with the code I made is with using the Calendar day button's names as variables. Maybe there is a way to prepare a statement for NetBeans to read as the buttons name?

For this calendar, I made a JPanel with 49 buttons (to have 7 rows of weeks that is the maximum a calendar has). I tried to name every button "N(number)" (the number being from 1 to 49). This is so I can make a for function that makes so that the position of the day after the last day of a month will be the position for the first day of the following month.

enter image description here

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

@SuppressWarnings("serial")
public class ButtonFoo01 extends JPanel {
    private static final String[] MONTHS = { 
            "January", "February", "March", "April", "May", 
            "June", "July", "August", "September", "October", 
            "November", "December" };
    
    public ButtonFoo01() {
        int gap = 3;
        setLayout(new GridLayout(0, 4, gap, gap));
        setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
        
        for (String month : MONTHS) {
            JButton button = new JButton(month);
            button.addActionListener(e -> monthButtonListener(e));
            add(button);
        }
    }
    
    private void monthButtonListener(ActionEvent e) {
        System.out.println("Button text: "   e.getActionCommand());
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            ButtonFoo01 mainPanel = new ButtonFoo01();

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

You also can see another example of mine that uses a 2-dimensional array of Strings to help create a GUI calculator,

enter image description here

in my answer here:

Java JComponent paint --Almost working


But...

Having answered the direct question, one also has to consider the overall problem, that of creating an accurate calendar representation using a Swing GUI, a problem that involves calendar logic that is well-suited to use of the relatively new DateTime Java library. This library makes it fairly easy to create a combo box for months since one can use the library's Month enum as the data nucleus of the JComboBox:

private JComboBox<Month> monthCombo = new JComboBox<>(Month.values());

The year could be represented by a JSpinner, one that uses a SpinnerNumberModel that has been set to the desired starting and ending year:

private JSpinner yearSpinner = new JSpinner(new SpinnerNumberModel(2022, 1900, 3000, 1));

I would also change the spinner's editor so that it doesn't display a thousands comma delimiter:

JSpinner.NumberEditor editor = new JSpinner.NumberEditor(yearSpinner, "#");
yearSpinner.setEditor(editor);

Also, we can add the same listener to the JComboBox as to the JSpinner, one that takes both values and finds the correct month for the selected year:

yearSpinner.addChangeListener(ce -> dateChanged());
monthCombo.addItemListener(ie -> dateChanged());

with the dateChanged() method:

private void dateChanged() {
    int year = (int) yearSpinner.getValue();
    Month month = (Month) monthCombo.getSelectedItem();
    LocalDate date = LocalDate.of(year, month, 1);
    
    // this notifies the JPanel that displays the dates of the selected month and year
    daysOfMonthPanel.setDate(date);
}

An example program could look something like:

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.Locale;
import javax.swing.*;

@SuppressWarnings("serial")
public class CalendarGui extends JPanel {
    public static final String LOCAL_DATE = "local date";
    private JSpinner yearSpinner = new JSpinner(new SpinnerNumberModel(2022, 1900, 3000, 1));
    private JComboBox<Month> monthCombo = new JComboBox<>(Month.values());
    private DaysOfTheMonthPanel daysOfMonthPanel = new DaysOfTheMonthPanel();

    public CalendarGui() {
        JSpinner.NumberEditor editor = new JSpinner.NumberEditor(yearSpinner, "#");
        yearSpinner.setEditor(editor);
        yearSpinner.addChangeListener(ce -> dateChanged());
        monthCombo.addItemListener(ie -> dateChanged());
        monthCombo.setRenderer(new MonthComboEditor());
        yearSpinner.setMaximumSize(yearSpinner.getPreferredSize());
        monthCombo.setMaximumSize(monthCombo.getPreferredSize());

        JPanel topPanel = new JPanel();
        topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.LINE_AXIS));
        topPanel.add(yearSpinner);
        topPanel.add(Box.createHorizontalGlue());
        topPanel.add(monthCombo);
        
        JPanel middlePanel = new JPanel(new BorderLayout());
        middlePanel.add(new DaysOfTheWeekPanel(), BorderLayout.PAGE_START);
        middlePanel.add(daysOfMonthPanel);        

        int gap = 3;
        setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
        setLayout(new BorderLayout(gap, gap));
        add(topPanel, BorderLayout.PAGE_START);
        add(middlePanel);
        
        LocalDate now = LocalDate.now();
        yearSpinner.setValue(now.getYear());
        monthCombo.setSelectedItem(now.getMonth());
    }
    
    private void dateChanged() {
        int year = (int) yearSpinner.getValue();
        Month month = (Month) monthCombo.getSelectedItem();
        LocalDate date = LocalDate.of(year, month, 1);
        
        // this notifies the JPanel that displays the dates of the selected month and year
        daysOfMonthPanel.setDate(date);
    }

    public static void main(String[] args) {        
        SwingUtilities.invokeLater(() -> {
            CalendarGui mainPanel = new CalendarGui();

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

    private static class MonthComboEditor extends DefaultListCellRenderer {
        @Override
        public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
                boolean cellHasFocus) {
            String newValue = (value == null) ? "" : ((Month) value).getDisplayName(TextStyle.FULL, Locale.US);
            return super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus);

        }
    }
    
    private static class DaysOfTheWeekPanel extends JPanel {
        private static final float FONT_SZ = 24;
        public DaysOfTheWeekPanel() {
            setLayout(new GridLayout(1, 7));
            int numberDaysOfWk = DayOfWeek.values().length;
            for (int i = 0; i < numberDaysOfWk; i  ) {
                int sundayIsZero = (i   numberDaysOfWk - 1) % numberDaysOfWk;
                JLabel wkDayLabel = new JLabel(DayOfWeek.values()[sundayIsZero].getDisplayName(TextStyle.SHORT, getLocale()));
                wkDayLabel.setHorizontalAlignment(SwingConstants.CENTER);
                Font font = wkDayLabel.getFont().deriveFont(Font.BOLD, FONT_SZ);
                wkDayLabel.setFont(font);
                add(wkDayLabel);
            }
        }
    }
    
    private class DaysOfTheMonthPanel extends JPanel {
        public DaysOfTheMonthPanel() {
            int gap = 2;
            setLayout(new GridLayout(0, 7, gap, gap));
            setBorder(BorderFactory.createLineBorder(Color.BLACK, gap));
            setBackground(Color.BLACK);
        }
        
        public void setDate(LocalDate date) {
            removeAll();
            int year = date.getYear();
            Month month = date.getMonth();
            LocalDate firstOfMonth = LocalDate.of(year, month, 1);
            DayOfWeek dayOfWeek = firstOfMonth.getDayOfWeek();
            int daysInMonth = YearMonth.of(year, month).lengthOfMonth();
            
            // fill empty slots with empty JLabels
            for (int i = 0; i < dayOfWeek.getValue() % 7; i  ) {
                add(new JPanel());
            }
            
            for (int i = 1; i <= daysInMonth; i  ) {
                JLabel label = new JLabel(String.valueOf(i), SwingConstants.CENTER);
                JPanel panel = new JPanel(new GridBagLayout());
                final LocalDate localDate = LocalDate.of(year, month, i);
                panel.putClientProperty(LOCAL_DATE, localDate);
                panel.setBackground(Color.WHITE);
                int topBtm = 25;
                int side = 45;
                panel.setBorder(BorderFactory.createEmptyBorder(topBtm, side, topBtm, side));
                panel.add(label);
                panel.addMouseListener(new MouseAdapter() {
                    @Override
                    public void mouseClicked(MouseEvent e) {
                        String format = "MMMM dd, yyyy";
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
                        System.out.println("Date pressed: "   localDate.format(formatter));
                    }
                });
                add(panel);
            }
            
            // fill in w/ jpanels until end of month
            LocalDate lastDayOfMonth = LocalDate.of(year, month, daysInMonth);
            int lastDayOfWeek = lastDayOfMonth.getDayOfWeek().getValue();
            int daysLeft = (7   6 - lastDayOfWeek) % 7; 
            for (int i = 0; i < daysLeft; i  ) {
                add(new JPanel());
            }
            revalidate();
            repaint();
        }
    }
}

CodePudding user response:

Why do you not store the buttons in an array or ArrayList so you can access them via a loop? I strongly believe you would be creating them via a loop anyway.

  • Related