Java: Date Picker for Swing

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Java: Date Picker for Swing

Post by Chris Corbyn »

This requires Java 5. I'm quite new to Java so be critical and teach me something new ;)

I'll tell you one bit I don't like: The locations of Model, Controller and View... but it's Swing and I struggle with that aspect.

I was looking around for a Java/Swing date picker and all I could find were ones you have to pay $100+ for. There is one free one but I don't like it because it was all buttons rather than a nice grid appearance. So, I did what any developer does when they can't find a tool for the job - I wrote my own :D If I make a few small changes to allow the appearance to be customized I'll probably release it free anyway.

Here it is (sorry for the long post):

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

import javax.swing.*;
import javax.swing.table.*;
import java.util.Calendar;
import java.awt.*;
import java.util.ArrayList;

/**
 * CalendarPanel is a container (JPanel) which holds the contents of the Calendar
 * It can be added to a Swing layout like any other JPanel
 * @author Chris Corbyn
 */
public class CalendarPanel extends JPanel
{
        /**
         * The controller layer
         */
        protected CalendarEventController controller;
        /**
         * The model
         */
        public CalendarModel model;
        /**
         * The combobox which holds the months of the year
         */
        protected JComboBox monthDropdown;
        /**
         * The spinner to choose a year
         */
        protected JSpinner yearSpinner;
        /**
         * The grid (JTable) containing the days of the month
         */
        protected CalendarTable grid;
        /**
         * A collection of event listeners which respond to changes in date selection
         */
        protected ArrayList<CalendarChangeListener> calendarChangeListeners;

        /**
         * Create an instance of CalendarPanel with a titled border
         * @param title The title to show in a titled border
         */
        public CalendarPanel(String title)
        {
                super(new GridBagLayout());

                this.calendarChangeListeners = new ArrayList<CalendarChangeListener>();

                this.setModel(new CalendarModel());

                this.setController(new CalendarEventController());
                this.getController().setUI(this);


                this.setBorder(BorderFactory.createTitledBorder(title));
                GridBagConstraints c = new GridBagConstraints();

                c.gridx = 0;
                c.gridy = 0;
                c.fill = GridBagConstraints.HORIZONTAL;
                c.anchor = GridBagConstraints.WEST;
                this.addMonths(c);

                c.gridx = 1;
                c.anchor = GridBagConstraints.EAST;
                c.fill = GridBagConstraints.NONE;
                this.addYears(c);

                c.gridx = 0;
                c.gridy = 1;
                c.gridwidth = 2;
                this.addTable(c);
        }
        /**
         * Set the model which this View in rendered from
         * @param model The CalendarModel
         */
        public void setModel(CalendarModel model)
        {
                this.model = model;
        }
        /**
         * Get the current model
         * @return CalendarModel
         */
        public CalendarModel getModel()
        {
                return this.model;
        }
        /**
         * Set the controller which modifies the model of the calendar
         * @param controller The event listening layer/controller
         */
        protected void setController(CalendarEventController controller)
        {
                this.controller = controller;
        }
        /**
         * Get the event listening object which acts as a controller
         * @return CalendarEventController
         */
        protected CalendarEventController getController()
        {
                return this.controller;
        }
        /**
         * Add the month combo box to the layout
         * @param GridBagConstraints To position the combobox on the overall layout
         */
        protected void addMonths(GridBagConstraints c)
        {
                String[] months = this.getModel().getMonthNames();
                if (this.monthDropdown == null)
                        this.monthDropdown = new JComboBox(months);

                int monthNow = this.getModel().getCalendarMonth();
                this.monthDropdown.setSelectedIndex(monthNow);
                this.getController().addMonthDropdown(this.monthDropdown);
                this.add(this.monthDropdown, c);
        }
        /**
         * Get the months combobox component
         * @return JComboBox, containing the months
         */
        public JComboBox getMonthDropdown()
        {
                return this.monthDropdown;
        }
        /**
         * Get the years component
         * @return JSpinner, containing the date model
         */
        public JSpinner getYearSpinner()
        {
                return this.yearSpinner;
        }
        /**
         * Add the years spinner to the layout
         * @param GridBagConstraints To position the spinner on the overall layout
         */
        protected void addYears(GridBagConstraints c)
        {
                this.yearSpinner = new JSpinner(this.getModel().getYearSpinnerModel());
                this.yearSpinner.setEditor(new JSpinner.DateEditor(this.yearSpinner, "yyyy"));
                this.getController().addYearSpinner(this.yearSpinner);
                this.add(this.yearSpinner, c);
        }
        /**
         * Add the Grid to the layout
         * @param GridBagConstraints To position the grid in the overall layout
         */
        protected void addTable(GridBagConstraints c)
        {
                JPanel box = new JPanel(new GridBagLayout());
                GridBagConstraints myC = new GridBagConstraints();
                myC.gridx = 0;
                myC.gridy = 0;
                this.grid = new CalendarTable(new DefaultTableModel());
                this.getModel().addObserver(
                        new CalendarCellDisabler(this.getGrid()));
                this.getGrid().setModel(this.getModel().getTableModel());
                this.getController().addGrid(this.getGrid());
                this.configureTable();

                box.add(this.getGrid().getTableHeader(), myC);

                myC.gridy = 1;
                box.add(this.grid, myC);

                this.add(box, c);
        }
        /**
         * Get the Grid (JTable) which shows the days
         * @return JTable, containing the days of the month
         */
        public CalendarTable getGrid()
        {
                return this.grid;
        }
        /**
         * Set up the renderer and feel of the Grid
         */
        protected void configureTable() //Disable cells which are not used????  We have to read the TableModel here
        {
                this.grid.setDragEnabled(false);
                this.grid.getTableHeader().setReorderingAllowed(false);
                this.grid.getTableHeader().setResizingAllowed(false);
                this.grid.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

                CalendarCellRenderer renderer = new CalendarCellRenderer();
                renderer.setParentUI(this);

                TableColumn col = null;
                for (int i = 0; i < 7; i++)
                {
                        col = this.grid.getColumnModel().getColumn(i);
                        col.setPreferredWidth(27);
                        col.setCellRenderer(renderer);
                }
                this.grid.setSelectionBackground(new Color((float)0.7, (float)0.86, (float)1.0));
                this.grid.setSelectionForeground(Color.black);
                this.grid.setShowGrid(false);
                this.grid.setRowHeight(22);

                int r = this.getModel().getSelectedGridRow();
                this.grid.setRowSelectionInterval(r, r);
                int c = this.getModel().getSelectedGridColumn();
                this.grid.setColumnSelectionInterval(c, c);
        }
        /**
         * Redraw the UI - overridden to add some functionality for redrawing the grid
         */
        public void redraw()
        {
                this.configureTable();
                this.getGrid().updateUI();
                super.updateUI();
        }
        /**
         * Fire a new CalendarChangeEvent
         * @param e The event being fired
         */
        public void fireCalendarChangeEvent(CalendarChangeEvent e)
        {
                for (int i = 0, len = this.calendarChangeListeners.size(); i < len; i++)
                {
                        CalendarChangeListener l = this.calendarChangeListeners.get(i);
                        l.calendarChanged(e);
                }
        }
        /**
         * Add a new listener for CalendarChangeEvent - the controller triggers this event
         * @param listener The event listener to add
         */
        public void addCalendarChangeListener(CalendarChangeListener l)
        {
                this.calendarChangeListeners.add(l);
        }
}

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

import java.util.GregorianCalendar;
import java.util.Calendar;
import java.util.Date;
import javax.swing.table.DefaultTableModel;
import javax.swing.*;
import java.util.Observable;

/**
 * The Model for the Date picker calendar
 * Provides and manipulate dates, contains Swing and AWT models.
 * @author Chris Corbyn
 */
public class CalendarModel extends Observable
{
        /**
         * The calendar storing all the time data which changes the appearance of the calendar
         */
        protected GregorianCalendar calendar;
        /**
         * The currently selected day
         */
        protected Integer selectedDay = null;
        /**
         * The currently selected month - not strictly the same date as the calendar says
         */
        protected Integer selectedMonth = null;
        /**
         * The currently selected year - not strictly the same date as the calendar says
         */
        protected Integer selectedYear = null;
        /**
         * The currently selected row in the calendar
         */
        protected Integer selectedGridRow = null;
        /**
         * The currently selected column in the calendar
         */
        protected Integer selectedGridColumn = null;
        /**
         * The days of the current month in a 2-dimensional array format
         */
        protected Integer[][] days;
        /**
         * The days of the week as an array
         */
        protected String[] dayNames;
        /**
         * The months in the combo box
         */
        protected String[] monthNames;

        /**
         * Get a new instance of the CalendarModel
         */
        public CalendarModel()
        {
                String[] weekdayNames = { "S", "M", "T", "W", "T", "F", "S" };
                String[] monthNames = {
                        "January", "February", "March", "April", "May", "June",
                        "July", "August", "September", "October", "November", "December" };
                this.setMonthNames(monthNames);
                this.setDayNames(weekdayNames);
                this.days = new Integer[6][7];
                this.setCalendar(new GregorianCalendar());
                this.getCalendar().set(Calendar.HOUR, 0);
                this.getCalendar().set(Calendar.MINUTE, 0);
                this.getCalendar().set(Calendar.SECOND, 0);
                this.setSelectedDay(this.getCalendar().get(Calendar.DAY_OF_MONTH));
                this.setSelectedMonth(this.getCalendar().get(Calendar.MONTH));
                this.setSelectedYear(this.getCalendar().get(Calendar.YEAR));
        }
        /**
         * Get the calendar object used to render the current view
         * @return GregorianCalendar, which is responsible for rendering the grid
         */
        public GregorianCalendar getCalendar()
        {
                return this.calendar;
        }
        /**
         * Set the calendar in the Model
         * @param calendar The calendar the GUI is modelled on
         */
        public void setCalendar(GregorianCalendar calendar)
        {
                this.calendar = calendar;
        }
        /**
         * Get the names of all the months
         * @return String[], containing the month names
         */
        public String[] getMonthNames()
        {
                return this.monthNames;
        }
        /**
         * Set the months used in the combo box
         * @param months The months in the list
         */
        public void setMonthNames(String[] months)
        {
                if (months.length > 12)
                {
                        throw new RuntimeException("You cannot set more than 12 months");
                }
                this.monthNames = months;
        }
        /**
         * Get the number of days in the current month
         * @return int, days in the current month
         */
        public int getDaysInMonth()
        {
                int[] daysInMonths = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
                int month = this.getCalendar().get(Calendar.MONTH);
                int ret = daysInMonths[month];
                if (month == 1 && this.getCalendar().isLeapYear(this.getCalendar().get(Calendar.YEAR))) ret += 1;
                return ret;
        }
        /**
         * Get the heading for the table
         * @return String[], names of the days in the headings
         */
        public String[] getDayNames()
        {
                return this.dayNames;
        }
        /**
         * Set the heading for the weekdays
         * @param days The days of the week
         */
        public void setDayNames(String[] days)
        {
                if (days.length != 7)
                {
                        throw new RuntimeException("Only 7 days can be set in the heading.");
                }
                this.dayNames = days;
        }
        /**
         * Get the model that makes the table
         * @return DefaultTableModel
         */
        public DefaultTableModel getTableModel()
        {
                String[] headings = this.getDayNames();
                Object[][] data = this.getDays();
                DefaultTableModel model = new DefaultTableModel(data, headings) {
                        public boolean isCellEditable(int row, int col)
                        {
                                return false;
                        }
                };
                return model;
        }
        /**
         * Get the Date model for the Year Spinner
         * @return SpinnerDateModel
         */
        public SpinnerDateModel getYearSpinnerModel()
        {
                Date now = this.getCalendar().getTime();
                int year = this.getCalendar().get(Calendar.YEAR);
                this.getCalendar().add(Calendar.YEAR, -1000);
                Date earliest = this.getCalendar().getTime();
                this.getCalendar().add(Calendar.YEAR, 2000);
                Date latest = this.getCalendar().getTime();
                this.getCalendar().set(Calendar.YEAR, year);
                SpinnerDateModel model = new SpinnerDateModel(now, earliest, latest, Calendar.YEAR);
                return model;
        }
        /**
         * Set the row in the grid which is currently selected
         * @param row The selected row
         */
        public void setSelectedGridRow(int r)
        {
                this.selectedGridRow = r;
        }
        /**
         * Get the row in the grid which is currently selected
         * @return Integer
         */
        public Integer getSelectedGridRow()
        {
                return this.selectedGridRow;
        }
        /**
         * Set the column in the grid which is currently selected
         * @param column The selected column
         */
        public void setSelectedGridColumn(int c)
        {
                this.selectedGridColumn = c;
        }
        /**
         * Get the column in the grid which is currently selected
         * @return Integer
         */
        public Integer getSelectedGridColumn()
        {
                return this.selectedGridColumn;
        }
        /**
         * Get the month which is currently selected - not the same as the one in the calendar
         * @return int
         */
        public int getSelectedMonth()
        {
                return this.selectedMonth;
        }
        /**
         * Set the currently selected month
         * @param month The selected month
         */
        public void setSelectedMonth(int m)
        {
                this.selectedMonth = m;
                this.getCalendar().set(Calendar.DAY_OF_MONTH, 1);
                this.getCalendar().set(Calendar.MONTH, m);
                this.restoreDayOfMonth();
        }
        /**
         * Sets the day of the month back to its original (or next highest) value after a change
         */
        protected void restoreDayOfMonth()
        {
                int daysInMonth = this.getDaysInMonth();
                int lastSelectedDay = this.getSelectedDay();
                if (lastSelectedDay > daysInMonth)
                {
                        this.setSelectedDay(daysInMonth);
                }
                else
                {
                        this.setSelectedDay(lastSelectedDay);
                }
        }
        /**
         * Get the year which as currently selected - not the same as the calendar
         * @return int
         */
        public int getSelectedYear()
        {
                return this.selectedYear;
        }
        /**
         * Set the year which is currently selected
         * @param year The selected year
         */
        public void setSelectedYear(int year)
        {
                this.selectedYear = year;
                this.getCalendar().set(Calendar.DAY_OF_MONTH, 1);
                this.getCalendar().set(Calendar.YEAR, year);
                this.restoreDayOfMonth();
        }
        /**
         * Get the current month in the calendar - maybe not the selected month
         * @return int
         */
        public int getCalendarMonth()
        {
                int currentMonth = this.getCalendar().get(Calendar.MONTH);
                return currentMonth;
        }
        /**
         * Get the last day which was selected in the calendar
         * @return int, day of month
         */
        public Integer getSelectedDay()
        {
                return this.selectedDay;
        }
        /**
         * Set the last selected day in the calendar
         * @param dayOfMonth
         */
        public void setSelectedDay(Integer dayOfMonth)
        {
                this.selectedDay = dayOfMonth;
                this.getCalendar().set(Calendar.DAY_OF_MONTH, dayOfMonth);
        }
        /**
         * Get the days in the current month as a 2-dimensional array
         * @return String[][]
         */
        public Integer[][] getDays()
        {
                int currDay = this.getCalendar().get(Calendar.DAY_OF_MONTH);
                this.getCalendar().set(Calendar.DAY_OF_MONTH, 1);
                int firstDayOfMonthAsDayOfWeek = this.getCalendar().get(Calendar.DAY_OF_WEEK);
                this.getCalendar().set(Calendar.DAY_OF_MONTH, currDay);
                int daysInMonth = this.getDaysInMonth();
                this.getCalendar().add(Calendar.MONTH, -1);
                int daysInLastMonth = this.getDaysInMonth();
                this.getCalendar().add(Calendar.MONTH, 1);
                int row = 0;
                int col = 0;
                Integer dayToAdd = 0;
                Integer lastMonthDayToAdd = 0;
                Integer dayNextMonthToAdd = 0;
                Integer[] disabledCell = { 0 , 0 };

                for (int k = 1; k <= 42; k++)
                {
                        if (k < firstDayOfMonthAsDayOfWeek)
                        {
                                lastMonthDayToAdd = (daysInLastMonth - (firstDayOfMonthAsDayOfWeek - k - 1));
                                this.days[row][col] = lastMonthDayToAdd;
                                disabledCell[0] = row;
                                disabledCell[1] = col;
                                this.setChanged();
                                this.notifyObservers(disabledCell);
                                this.clearChanged();
                        }
                        else if (dayToAdd >= daysInMonth)
                        {
                                dayNextMonthToAdd++;
                                this.days[row][col] = dayNextMonthToAdd;
                                disabledCell[0] = row;
                                disabledCell[1] = col;
                                this.setChanged();
                                this.notifyObservers(disabledCell);
                                this.clearChanged();
                        }
                        else
                        {
                                dayToAdd++;
                                this.days[row][col] = dayToAdd;
                                //Select the currently chosen day
                                if (dayToAdd == this.getSelectedDay())
                                {
                                        this.setSelectedGridRow(row);
                                        this.setSelectedGridColumn(col);
                                }
                        }
                        col++;
                        if (col == 7)
                        {
                                col = 0;
                                row++;
                        }
                }
                return this.days;
        }
}

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.util.Calendar;
import java.util.GregorianCalendar;

/**
 * The event handling layer for the Calendar.
 * This is what I would consider the Controller in MVC.
 * Attaches event listeners to Swing components
 * @author Chris Corbyn
 */
public class CalendarEventController
{
        /**
         * The user interface as a Swing component (Container)
         */
        protected CalendarPanel ui;

        /**
         * Set the user interface component containing the calendar
         * @param CalendarPanel The user interface of the Swing component
         */
        public void setUI(CalendarPanel cal)
        {
                this.ui = cal;
        }
        /**
         * Put the month combobox under the control of the controller
         * @param monthComboBox JComboBox for months
         */
        public void addMonthDropdown(JComboBox months)
        {
                months.addItemListener(new ItemListener() {
                        public void itemStateChanged(ItemEvent e)
                        {
                                if (e.getStateChange() == ItemEvent.SELECTED)
                                {
                                        int monthSelected = ui.monthDropdown.getSelectedIndex();
                                        ui.getModel().setSelectedMonth(monthSelected);
                                        ui.getGrid().resetCellStates();
                                        ui.getGrid().setModel(ui.getModel().getTableModel());
                                        ui.redraw();
                                }
                        }
                });
        }
        /**
         * Put the year Spinner under the control of this controller
         * @param yearSpinner The year spinner (with a SpinnerDateModel)
         */
        public void addYearSpinner(JSpinner years)
        {
                years.addChangeListener(new ChangeListener() {
                        public void stateChanged(ChangeEvent e)
                        {
                                Calendar t = Calendar.getInstance();
                                t.setTime(((SpinnerDateModel)ui.getYearSpinner().getModel()).getDate());
                                ui.getModel().setSelectedYear(t.get(Calendar.YEAR));
                                ui.getGrid().resetCellStates();
                                ui.getGrid().setModel(ui.getModel().getTableModel());
                                ui.redraw();
                        }
                });
        }
        /**
         * Put the grid under the control of this controller
         * @param table The table containing the grid
         */
        public void addGrid(CalendarTable table)
        {
                table.addCellSelectionListener(new CalendarTableCellSelectionListener() {
                        public void cellSelectionChanged(CalendarTableCellSelectionEvent e)
                        {
                                ui.getModel().setSelectedDay((Integer)e.getValue());
                                ui.fireCalendarChangeEvent(
                                        new CalendarChangeEvent(ui.getModel().getCalendar()));
                        }
                });
        }
}

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import java.util.HashMap;
import java.util.ArrayList;

/**
 * CalendarTable is a JTable which does not allow empty cells to be selected
 * @author Chris Corbyn
 */
public class CalendarTable extends JTable
{
        /**
         * A matrix of the disabled cell positions
         */
        protected HashMap<Integer,HashMap<Integer,Boolean>> disabledRows;
        /**
         * Event listeners observing when a cell is selected
         */
        protected ArrayList<CalendarTableCellSelectionListener> cellSelectionListeners;

        /**
         * Ctor
         * @param model The table model to render
         */
        public CalendarTable(AbstractTableModel model)
        {
                super(model);
                this.disabledRows = new HashMap<Integer,HashMap<Integer,Boolean>>();
                this.cellSelectionListeners = new ArrayList<CalendarTableCellSelectionListener>();
        }
        /**
         * Disable a cell selection at the coordinates (row,col)
         * @param row The row of the cell
         * @param col The column of the cell
         */
        public void disableCellAt(int row, int col)
        {
                if (!this.disabledRows.containsKey(row))
                {
                        this.disabledRows.put(row, new HashMap<Integer,Boolean>());
                }
                this.disabledRows.get(row).put(col, true);
        }
        /**
         * Clear out disabled cell statuses
         */
        public void resetCellStates()
        {
                this.disabledRows.clear();
        }
        /**
         * Enable a cell if it has been disabled
         * @param row The row of the disabled cell
         * @param col The column of the disabled cell
         */
        public void enableCellAt(int row, int col)
        {
                if (this.isDisabledAt(row, col))
                        this.disabledRows.get(row).remove(col);
        }
        /**
         * Check if the cell at row,col is disabled
         * @param row The row to test
         * @param col The column to test
         * @return true, if the cell is disabled
         */
        public boolean isDisabledAt(int row, int col)
        {
                if (this.disabledRows.containsKey(row))
                {
                        if (this.disabledRows.get(row).containsKey(col) && this.disabledRows.get(row).get(col))
                        {
                                return true;
                        }
                }

                return false;
        }
        /**
         * Overridden to prevent empty cells from being selected
         */
        public void changeSelection(int row, int col, boolean toggle, boolean extend)
        {
                if (!this.isDisabledAt(row, col))
                        super.changeSelection(row, col, toggle, extend);
        }
        /**
         * Fire a CalendarCellSelectionEvent
         * @param event The event being fired
         */
        public void fireCellSelectionEvent(CalendarTableCellSelectionEvent e)
        {
                for (int i = 0, len = this.cellSelectionListeners.size(); i < len; i++)
                {
                        CalendarTableCellSelectionListener l = this.cellSelectionListeners.get(i);
                        l.cellSelectionChanged(e);
                }
        }
        /**
         * Register a new event listener for CalendarChangeEvent
         * @param listener The event listener
         */
        public void addCellSelectionListener(CalendarTableCellSelectionListener l)
        {
                this.cellSelectionListeners.add(l);
        }
}

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

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

/**
 * Styles the grid of the calendar to look beautiful across various L&Fs.
 * This is just a basic extension of the DefaultTableCellRender from the current L&F
 * @author Chris Corbyn
 */
public class CalendarCellRenderer extends DefaultTableCellRenderer
{
        /**
         * The current row being rendered
         */
        protected int row;
        /**
         * The current column being rendered
         */
        protected int col;
        /**
         * If this cell is part of the "selected" row
         */
        protected boolean isSelected;
        /**
         * The table being rendered
         */
        protected JTable tbl;
        /**
         * The GUI itself
         */
        protected CalendarPanel parentUI;

        /**
         * Set the object which renders the GUI of the calendar
         * @param CalendarPanel The Swing component which holds the calendar
         */
        public void setParentUI(CalendarPanel p)
        {
                this.parentUI = p;
        }
        /**
         * Fetch the component which renders the cell ordinarily
         * @param table The current JTable the cell is in
         * @param value The value in the cell
         * @param isSelected If the cell is in the selected row
         * @param isFocused If the cell is in focus
         * @param row The row number of the cell
         * @param column The column number of the cell
         * @return Component
         */
        public Component getTableCellRendererComponent(
                JTable tbl, Object v, boolean isSelected, boolean isFocused, int row, int col)
        {
                if (((CalendarTable)tbl).isDisabledAt(row, col))
                {
                        this.setEnabled(false);
                        isSelected = false;
                }
                else this.setEnabled(true);

                //Store this info for later use
                this.tbl = tbl;
                this.row = row;
                this.col = col;
                this.isSelected = isSelected;

                //and then allow the usual component to be returned
                return super.getTableCellRendererComponent(tbl, v, isSelected, isFocused, row, col);
        }
        /**
         * Set the contents of the cell to v
         * @param value The value to apply to the cell
         */
        protected void setValue(Object v)
        {
                super.setValue(v); //Set the value as requested

                //Set colors dependant upon if the row is selected or not
                if (!this.isSelected)
                {
                        if (!this.isEnabled()) this.setBackground(new Color(178, 204, 251, 110));
                        else this.setBackground(new Color(178, 204, 251));
                }
                else this.setBackground(new Color(160, 160, 180));

                //Set a special highlight color if this actual cell is focused
                if (this.isEnabled() && this.row == this.tbl.getSelectedRow() && this.col == this.tbl.getSelectedColumn())
                {
                        this.setBackground(new Color(127, 200, 120));
                        ((CalendarTable)this.tbl).fireCellSelectionEvent(new CalendarTableCellSelectionEvent((CalendarTable)this.tbl, v));
                }
        }
}

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

import java.util.Observer;
import java.util.Observable;

/**
 * CalendarCellDisabler receives message from CalendarModel to prevent cell selections in the table
 * @author Chris Corbyn
 */
public class CalendarCellDisabler implements Observer
{
        /**
         * The table which this observer disables cells for
         */
        protected CalendarTable tbl;

        /**
         * Ctor
         * @param table The table to disable cells in
         */
        public CalendarCellDisabler(CalendarTable tbl)
        {
                this.tbl = tbl;
        }
        /**
         * Receive a message from an observer to disable a cell
         * @param observable The observable object
         * @param args The disabled cell represented by Integer[2]
         */
        public void update(Observable o, Object args)
        {
                Integer[] cell = (Integer[])args;
                this.tbl.disableCellAt(cell[0], cell[1]);
        }
}

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

import java.util.EventObject;

/**
 * CalendarTableCellSelectionEvent fires when a cell is selected in the table
 * @author Chris Corbyn
 */
public class CalendarTableCellSelectionEvent extends EventObject
{
        /**
         * The value at the selected cell
         */
        protected Object value;

        /**
         * Ctor
         * @param source The CalendarTable object
         * @param v The value at the selected cell
         */
        public CalendarTableCellSelectionEvent(CalendarTable source, Object v)
        {
                super(source);
                this.setValue(v);
        }
        /**
         * Set the value of the selected cell (copy, not reference)
         * @param v The value at the selected cell
         */
        public void setValue(Object v)
        {
                this.value = v;
        }
        /**
         * Get the value at the selected cell
         * @return Integer, usually, but it could be anything
         */
        public Object getValue()
        {
                return this.value;
        }
}

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */
 
package org.w3style.calendar;

import java.util.EventListener;

/**
 * CalendarTableCellSelectionListener is the interface which allows listening for
 * CalendarTableCellSelectionEvent objects being fired in CalendarTable
 * @author Chris Corbyn
 */
public interface CalendarTableCellSelectionListener extends EventListener
{
        /**
         * Runs every time a CalendarTableCellSelectionEvent is fired
         * @param e The event object
         */
        public void cellSelectionChanged(CalendarTableCellSelectionEvent e);
}

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

import java.util.EventObject;
import java.util.GregorianCalendar;

/**
 * CalendarChangeEvent fires when a new date is selected in the calendar
 * @author Chris Corbyn
 */
public class CalendarChangeEvent extends EventObject
{
        /**
         * Ctor
         * @param source The GregorianCalendar containing the changed model
         */
        public CalendarChangeEvent(GregorianCalendar source)
        {
                super(source);
        }
}

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */
 
package org.w3style.calendar;

import java.util.EventListener;

/**
 * The interface which listener for calendar date changes via CalendarChangeEvent must implement
 * @author Chris Corbyn
 */
public interface CalendarChangeListener extends EventListener
{
        /**
         * Runs everytime a CalendarChangeEvent object is created
         * @param e The event object
         */
        public void calendarChanged(CalendarChangeEvent e);
}
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Here's a basic example of it's usage, looking like this:

Image

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

import org.w3style.calendar.CalendarPanel;
import org.w3style.calendar.CalendarChangeEvent;
import org.w3style.calendar.CalendarChangeListener;
import javax.swing.*;
import java.awt.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;

/**
 * A small demonstration of the calendar working in a basic Swing layout
 * @author Chris Corbyn
 */
class CalendarDemo implements CalendarChangeListener
{
        /**
         * The label which displays the currently selected date
         */
        protected JLabel selectedDateDisplay;

        /**
         * App entry point
         */
        public static void main(String[] args)
        {
                CalendarDemo me = new CalendarDemo();
                me.demo();
        }
        /**
         * Render the GUI in the event dispatching thread
         */
        public void demo()
        {
                SwingUtilities.invokeLater(new Runnable() {
                        public void run()
                        {
                                renderMe();
                        }
                });
        }
        /**
         * The change listener for the calendar.
         * Updates the JLabel showing the selected date
         * @param e The change event fired from the calendar
         */
        public void calendarChanged(CalendarChangeEvent e)
        {
                this.selectedDateDisplay.setText(this.getDateDisplayFieldName() +
                        this.getFormattedDate((Calendar)e.getSource()));
                this.selectedDateDisplay.updateUI();
        }
        /**
         * Get the name of the date field
         * @return String
         */
        public String getDateDisplayFieldName()
        {
                return "Date: ";
        }
        /**
         * Get the date from the calendar in a nice format
         * @param calendar The Calendar from CalendarModel
         * @return date, formatted as a human readable string
         */
        public String getFormattedDate(Calendar c)
        {
                SimpleDateFormat d = new SimpleDateFormat("EEE, MMM dd, yyyy");
                return d.format(c.getTime());
        }
        /**
         * Render this application's GUI.
         * This should be done in the appropriate thread
         */
        public void renderMe()
        {
                try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception e) {
                        System.out.println("L&F problem");
                }
                JFrame frame = new JFrame("Calendar Demo");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setResizable(false);

                //Create a new calendar component
                CalendarPanel calendar = new CalendarPanel("Example Calendar");

                JPanel panel = new JPanel(new GridBagLayout());
                GridBagConstraints c = new GridBagConstraints();
                c.gridx = 0;
                c.gridy = 0;
                c.insets = new Insets(4, 4, 4, 4);

                //Add the calendar
                panel.add(calendar, c);

                this.selectedDateDisplay = new JLabel(this.getDateDisplayFieldName() +
                        this.getFormattedDate(calendar.getModel().getCalendar()));
                this.selectedDateDisplay.setLabelFor(calendar);

                c.gridy = 1;
                c.anchor = GridBagConstraints.WEST;
                c.insets = new Insets(8, 8, 8, 8);
                panel.add(this.selectedDateDisplay, c);

                frame.getContentPane().add(panel);

                //Register ourseleves as an event listener for the calendar
                calendar.addCalendarChangeListener(this);

                frame.pack();
                frame.setVisible(true);
        }
}
Download: http://www.wstyle.co.uk/~d11wtq/calendar_demo.jar

Code: Select all

java -jar calendar_demo.jar
Post Reply