Search code examples
javaswingfor-loopactionlistener

JAVA I use a JButton[] Array in a method to add multiple buttons - method works in class constructor but not when used as a pressed button action


I have a problem and I can't get past it... I am writing a program in Java using swing. That program will be used to to chose a day from a displayed calendar and put an hours of Your work (e.g 8:00 - 16:00) then the program will calculate how many hours You have worked in month and will calculate Your salary.

I've written some code so when starting the program you see a representation of current month. I wanted to add an ActionListenerto a button which will rearrange look of calendar to previous month. I wanted to use the same method that generates the current month but sending a different argument (previous month date).

To test it I used that method on the ActionListener (so when I start it I see blank form and after pressing that button it will show me the current method) and the problem is that nothing at all is happening... That method works fine when I put it in the constructor of my class but doesn't work when it is used as action performed and I don't know why.

I hope You will help me to figure it out and maybe tell me where I made a mistake and what I can do about it. This is a hobby for me I don't have any professional experience in programming.

My code:

package zadanie;

import javax.swing.*;
import java.awt.*;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

class Panel extends JPanel {

    private JButton[] buttonArray = new JButton[42];
    private JButton nextButton, previousButton;
    private JLabel monthYear;
    private Color buttonColor = new Color(116, 185, 255);
    private Color buttonColorInactive = new Color(255,255,255);
    private Color sundey = new Color(0, 184, 148);
    private Color saturday = new Color(85, 239, 196);
    private Color labelColor = new Color(255, 211, 42);
    private LocalDate dateNow = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());

    Panel(){
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
        add(getMonthLabel());
        add(getWeekDaysPanel());
        add(Box.createRigidArea(new Dimension(0,5)));
        add(getMonthPanel());
        calendarGenerator();
        getWeekDaysPanel().setAlignmentX(Component.CENTER_ALIGNMENT);
        getMonthPanel().setAlignmentX(Component.CENTER_ALIGNMENT);
    }

    private JComponent getMonthPanel(){
        JPanel monthPanel = new JPanel();
        monthPanel.setLayout(new GridLayout(6,7));
        monthPanel.setMaximumSize(new Dimension(710,460));
        monthPanel.setPreferredSize(new Dimension(710,460));
        monthPanel.setMaximumSize(new Dimension(710,460));

        //Loop that in every iteration creates a "b" button set it properties and to a "p" panel and a buttonArray.
        for (int i=0; i<42; i++){
            JButton b = new JButton();
                b.setMaximumSize(new Dimension(95,70));
                b.setPreferredSize(new Dimension(95,70));
                b.setMaximumSize(new Dimension(95,70));
                b.setBorderPainted(false);
                b.setRolloverEnabled(false);
                b.setVisible(true);
            JPanel p = new JPanel();
            p.add(b);
            buttonArray[i] = b;
            monthPanel.add(p);
        }
        return monthPanel;
    }
    // Similar to getMonthPanel method - it adds a 7 labels with the names of the days
    private JComponent getWeekDaysPanel(){
        JPanel daysPanel = new JPanel();
            daysPanel.setBackground(labelColor);
            daysPanel.setMinimumSize(new Dimension(700,35));
            daysPanel.setPreferredSize(new Dimension(700,35));
            daysPanel.setMaximumSize(new Dimension(700,35));
        String[] daysList = {"pn.", "wt.", "śr.", "czw.", "pt.", "sob.", "niedz."};

        for (int i = 0; i < 7; i++){
            JLabel e = new JLabel("", JLabel.CENTER);
                e.setMinimumSize(new Dimension(95,25));
                e.setPreferredSize(new Dimension(95,25));
                e.setMaximumSize(new Dimension(95,25));
                e.setLayout(new GridLayout(1,7));
                e.setText(daysList[i]);
                daysPanel.add(e);
        }
        return daysPanel;
    }
    // a method that adds a two buttons (to switch to previous and next month) and a label that displays the displayed month and year
    private JComponent getMonthLabel(){
        JPanel monthLabel = new JPanel();
            monthLabel.setMinimumSize(new Dimension(700,45));
            monthLabel.setPreferredSize(new Dimension(700,45));
            monthLabel.setMaximumSize(new Dimension(700,45));
            monthLabel.setBackground(buttonColorInactive);
            monthLabel.revalidate();
        nextButton = new JButton();
            ImageIcon nIcon = new ImageIcon("n.png");
            nextButton.setMinimumSize(new Dimension(25,25));
            nextButton.setPreferredSize(new Dimension(25,25));
            nextButton.setMaximumSize(new Dimension(25,25));
            nextButton.setIcon(nIcon);
            nextButton.setBorderPainted(false);
            nextButton.setBackground(new Color(255,255,255));
//            nextButton.addActionListener();
        previousButton = new JButton();
            ImageIcon pIcon = new ImageIcon("p.png");
            previousButton.setMinimumSize(new Dimension(25,25));
            previousButton.setPreferredSize(new Dimension(25,25));
            previousButton.setMaximumSize(new Dimension(25,25));
            previousButton.setIcon(pIcon);
            previousButton.setBorderPainted(false);
            previousButton.setBackground(new Color(255,255,255));

        monthYear = new JLabel("MIESIĄC_ROK", JLabel.CENTER);
            monthYear.setMinimumSize(new Dimension(620,25));
            monthYear.setPreferredSize(new Dimension(620,25));
            monthYear.setMaximumSize(new Dimension(620,25));

        monthLabel.add(previousButton);
        monthLabel.add(monthYear);
        monthLabel.add(nextButton);

        return monthLabel;
    }
    // A method that change the appearance of the buttons in the "buttonArray" so the whole thing looks like calendar of the month
    private void calendarGenerator(){
        int noOfDays = dateNow.lengthOfMonth(); /// getting number of days in a month
        int firstDayIndex = (dateNow.getDayOfWeek().getValue() - 1); // gettin the value (number) of the first day of month (it is decreased because getValue starts with 1 and buttonArray with 0)
        int dayNo = 1; // variable that is used to set number of day in the setText() method of button
        int month = (dateNow.getMonth().getValue() - 1); // variable that has a number of the previous month, that is why I decreased it by 1
        int year = dateNow.getYear(); // getting current year

            if (month == 0){ // safety - when the month variable hits 0 it is set for December (no 12) and year is decreased by 1
                month = 12;
                year --;
            }

        LocalDate previousMonthDate = LocalDate.of(year, month, 1); // a new variable for the previous month
        int dayNo2 = previousMonthDate.lengthOfMonth() - (firstDayIndex - 1);  // getting number of days of the previous mont (similar to dayNo but it responsible for the previous month during displaying

        for (int i = 0; i < firstDayIndex; i++){ // loop that fill days in buttons that represent previous month
            buttonArray[i].setText(""+dayNo2);
            buttonArray[i].setVisible(true);
            buttonArray[i].setEnabled(false);
            buttonArray[i].setBackground(buttonColorInactive);
            dayNo2++;
        }


        for (int i = firstDayIndex; i < noOfDays + firstDayIndex; i++){ // loop that fill days in buttons that represent current month
            buttonArray[i].setText(""+dayNo);
            buttonArray[i].setVisible(true);

            if (i == 6 || i == 13 || i == 20 || i == 27 || i == 34 || i == 41){

                buttonArray[i].setBackground(sundey);
            }
            else if (i == 5 || i == 12 || i == 19 || i == 26 || i == 33 || i == 40){
                buttonArray[i].setBackground(saturday);
            }
            else{
                buttonArray[i].setBackground(buttonColor);
            }
            monthYear.setText(""+translate(dateNow.getMonth().getValue())+" "+year); // "translate()" method is used for translating month names from English to my native language
            dayNo++;
        }

        dayNo = 1; // setting dayNo 1 because next month always starts with 1

        for (int i = (noOfDays + firstDayIndex); i < 42; i++){ // loop that fills the rest, empty buttons that represent next month
            buttonArray[i].setText(""+ dayNo);
            buttonArray[i].setVisible(true);
            buttonArray[i].setEnabled(false);
            buttonArray[i].setBackground(buttonColorInactive);
            dayNo++;
        }
    }

    // Method for translating English names to my native Language
    private String translate(int a){
        String monthInPolish = "";
        switch (dateNow.getMonth()){
            case JANUARY: monthInPolish = "Styczeń"; break;
            case FEBRUARY: monthInPolish = "Luty"; break;
            case MARCH: monthInPolish = "Marzec"; break;
            case APRIL: monthInPolish = "Kwiecień"; break;
            case MAY: monthInPolish = "Maj"; break;
            case JUNE: monthInPolish = "Czerwiec"; break;
            case JULY: monthInPolish = "Lipiec"; break;
            case AUGUST: monthInPolish = "Sierpień"; break;
            case SEPTEMBER: monthInPolish = "Wrzesień"; break;
            case OCTOBER: monthInPolish = "Październik"; break;
            case NOVEMBER: monthInPolish = "Listopad"; break;
            case DECEMBER: monthInPolish = "Grudzień"; break;
        }
        return monthInPolish;
    }
}

The method that I'm talking about is called calendarGenerator() Thanks for the effort!

This is how it looks when I use that method in the constructor

enter image description here

This is how it looks when I not use that method in the constructor

enter image description here

Edit: I've added pictures of how it looks when I use calendarGenerator() method in constructor and when that method is not used. Using that method in that form (as showed above) when the button is pressed, I wanted to see if my approach is correct (I know that I can send arguments and thus use it to switch months). So I removed the calendarGenerator() method from constructor (the second picture shows how the program looks like without it) and put it to ActionPerformed method for the button (that black arrow). I thought that when I press the button the window will change the look so it will look like on the first picture but only text on the label above is changing nothing else and I still don't know why.


Solution

  • Change calendarGenerator so it accepts an argument which is an arbitrary date in the month you want to generate:

    private void calendarGenerator(LocalDate dateInMonth){
        int noOfDays = dateInMonth.lengthOfMonth(); /// getting number of days in a month
        .........
    }
    

    To generate the current month call it by calendarGenerator(dateNow);
    To generate next month: calendarGenerator(dateNow.plusMonths(1));

    The following is an mre(1) demonstrating how to use the modified method:

    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.GridLayout;
    import java.time.LocalDate;
    import java.time.temporal.TemporalAdjusters;
    import javax.swing.Box;
    import javax.swing.BoxLayout;
    import javax.swing.JButton;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    class Panel extends JPanel {
    
        private JPanel monthPanel;
        private JLabel monthYear;
        private final static Color buttonColor = new Color(116, 185, 255), buttonColorInactive = new Color(255,255,255),
                      sundey = new Color(0, 184, 148),  saturday = new Color(85, 239, 196), labelColor = new Color(255, 211, 42);
        private final static int DAYS=7, WEEKS =6;
        private final LocalDate dateNow = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
        private LocalDate calendarDate;
        private final JButton[] buttonArray = new JButton[DAYS*WEEKS];
    
        Panel(){
            setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
            add(getMonthLabel());
            add(getWeekDaysPanel());
            add(Box.createRigidArea(new Dimension(0,5)));
            makeMonthPanel();
            add(monthPanel);
            calendarGenerator(dateNow);
        }
    
        private void makeMonthPanel(){
    
            monthPanel = new JPanel();
            monthPanel.setLayout(new GridLayout(WEEKS,DAYS));
            monthPanel.setPreferredSize(new Dimension(710,460));
            monthPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
            //Loop that in every iteration creates a "b" button set it properties and to a "p" panel and a buttonArray.
            for (int i=0; i< DAYS * WEEKS; i++){
                JButton b = new JButton();
                b.setPreferredSize(new Dimension(95,70));
                b.setBorderPainted(false);
                b.setRolloverEnabled(false);
                JPanel p = new JPanel();
                p.add(b);
                buttonArray[i] = b;
                monthPanel.add(p);
            }
        }
    
        // Similar to getMonthPanel method - it adds a 7 labels with the names of the days
        private JComponent getWeekDaysPanel(){
            JPanel daysPanel = new JPanel();
            daysPanel.setBackground(labelColor);
            daysPanel.setPreferredSize(new Dimension(700,35));
            String[] daysList = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
    
            for (int i = 0; i < daysList.length ; i++){
                JLabel e = new JLabel("", JLabel.CENTER);
                e.setPreferredSize(new Dimension(95,25));
                e.setText(daysList[i]);
                daysPanel.add(e);
            }
            return daysPanel;
        }
        // a method that adds a two buttons (to switch to previous and next month) and a label that displays the displayed month and year
        private JComponent getMonthLabel(){
    
            JPanel monthLabel = new JPanel();
            monthLabel.setBackground(buttonColorInactive);
    
            JButton nextButton = new JButton(">");;
            nextButton.setBorderPainted(false);
            nextButton.setBackground(new Color(255,255,255));
            nextButton.addActionListener(e -> calendarGenerator(calendarDate.plusMonths(1)));
    
            JButton previousButton = new JButton("<");
            previousButton.setBorderPainted(false);
            previousButton.setBackground(new Color(255,255,255));
            previousButton.addActionListener(e -> calendarGenerator(calendarDate.minusMonths(1)));
    
            monthYear = new JLabel("MIESIĄC_ROK", JLabel.CENTER);
            monthYear.setPreferredSize(new Dimension(620,25));
    
            monthLabel.add(previousButton);
            monthLabel.add(monthYear);
            monthLabel.add(nextButton);
    
            return monthLabel;
        }
    
        // A method that change the appearance of the buttons in the "buttonArray" so the whole thing looks like calendar of the month
        private void calendarGenerator(LocalDate dateInMonth){
            calendarDate = dateInMonth;
            int noOfDays = dateInMonth.lengthOfMonth(); /// getting number of days in a month
            int firstDayIndex = dateInMonth.getDayOfWeek().getValue() - 1; // gettin the value (number) of the first day of month (it is decreased because getValue starts with 1 and buttonArray with 0)
            int dayNo = 1; // variable that is used to set number of day in the setText() method of button
            int month = dateInMonth.getMonth().getValue() - 1; // variable that has a number of the previous month, that is why I decreased it by 1
            int year = dateInMonth.getYear(); // getting current year
    
            if (month == 0){ // safety - when the month variable hits 0 it is set for December (no 12) and year is decreased by 1
                month = 12;
                year --;
            }
    
            LocalDate previousMonthDate = LocalDate.of(year, month, 1); // a new variable for the previous month
            int dayNo2 = previousMonthDate.lengthOfMonth() - (firstDayIndex - 1);  // getting number of days of the previous mont (similar to dayNo but it responsible for the previous month during displaying
    
    
            for (int i = 0; i < firstDayIndex; i++){ // loop that fill days in buttons that represent previous month
                buttonArray[i].setText(""+dayNo2);
                buttonArray[i].setEnabled(false);
                buttonArray[i].setBackground(buttonColorInactive);
                dayNo2++;
            }
    
    
            for (int i = firstDayIndex; i < noOfDays + firstDayIndex; i++){ // loop that fill days in buttons that represent current month
                buttonArray[i].setText(""+dayNo);
                buttonArray[i].setVisible(true);
    
                if (i == 6 || i == 13 || i == 20 || i == 27 || i == 34 || i == 41){
    
                    buttonArray[i].setBackground(sundey);
                }
                else if (i == 5 || i == 12 || i == 19 || i == 26 || i == 33 || i == 40){
                    buttonArray[i].setBackground(saturday);
                }
                else{
                    buttonArray[i].setBackground(buttonColor);
                }
                monthYear.setText(""+dateInMonth.getMonth()+" "+year);
                dayNo++;
            }
    
            dayNo = 1; // setting dayNo 1 because next month always starts with 1
    
            for (int i = noOfDays + firstDayIndex; i < 42; i++){ // loop that fills the rest, empty buttons that represent next month
                buttonArray[i].setText(""+ dayNo);
                buttonArray[i].setVisible(true);
                buttonArray[i].setEnabled(false);
                buttonArray[i].setBackground(buttonColorInactive);
                dayNo++;
            }
    
            monthPanel.revalidate();
        }
    
        public static void main(String[] args) {
    
            JFrame frame=new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JPanel calendarPane = new Panel();
            frame.getContentPane().add(calendarPane);
            frame.pack();
            frame.setVisible(true);
        }
    }
    


    (1) Please consider mre when posting questions and answers. To achieve it remove every thing that is not essential (like translation in this case) to show the problem. mre should demonstrate the problem and not necessarily your application.