Vous êtes sur la page 1sur 17

Introduction

To keep track of date and time, there are many classes in Java containing date and
time functions, I am talking about Calendar, GrerogianCalendar, Timestamp... In this
tutorial, we will make a calendar with previous and next buttons to change month, and
a combo box to change the year. It covers the basics about GUIs, tables, events and
renderers. It is important you follow every step carefully and you understand before
proceeding. Let's get started.

Declaring the GUI components

The first step in every GUI (and in any program anyway) is declaring the variables. We
will need 8 visible components: the frame itself, the container, the next button, the
previous button, the month's label, the calendar itself (which is a JTable), the label to
choose the year and the year combo box itself. Why visible components? Well, there
are 2 more components we need to make: the table model and the scrollpane for the
table. Let's create our class called CalendarProgram:

public class calendarProgram{


public static void main (String args[]){

}
}
From now on, I assume you know what the above example means. If you don't, you
will not be able to follow this tutorial, I recommend you take a basics tutorial about it.
Now that our class is declared, we will declare static variables. This is done this way:

static type name = value;

The value field is optional, you could just declare the name. We will declare all our
components, I will explain something after. By the way, we need some packages
(declared in the following code):

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

public class calendarProgram{


static JLabel lblMonth, lblYear;
static JButton btnPrev, btnNext;
static JTable tblCalendar;
static JComboBox cmbYear;
static JFrame frmMain;
static Container pane;
static DefaultTableModel mtblCalendar; //Table model

1
static JScrollPane stblCalendar; //The scrollpane
static JPanel pnlCalendar; //The panel
static int realDay, realMonth, realYear, currentMonth, currentYear;

public static void main (String args[]){

}
}
This is quite easy to understand (for now). We imported the packages and we declared
the static variables (e.g. the GUI components). But there is a component,
DefaultTableModel, which is invisible but useful. It will be the model the table will use.
Every JTable must have a model in order to work. Make sure you understand fully the
above code.

Setting the Look and Feel

Every Java program using a GUI (unless you want the ugly Java theme) must have a
Look and Feel. This is a "theme" matching your operating system. Setting the theme is
quite easy, paste this in your main void:

try {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}
catch (ClassNotFoundException e) {}
catch (InstantiationException e) {}
catch (IllegalAccessException e) {}
catch (UnsupportedLookAndFeelException e) {}
Here you are done with the theme. This is a simple step to make your program nice-
looking. You will have your program matching your OS (OS stands for Operating
System).

Creating the components

You must understand the concept of "instantiating" an object. Instantiating an object is


the same as creating it. This is done with the "new" keyword. Example:

JLabel lblMonth = new JLabel ("January");


Every object has its own constructor (the method to create the object). Objects can
have more than one possible constructor. The JLabel object takes a String as a
parameter for the constructor, which will be the text to be displayed in the label. Let's
create all the GUI components:

frmMain = new JFrame("Calendar application");


lblMonth = new JLabel ("January");
lblYear = new JLabel ("Change year:");
cmbYear = new JComboBox();
btnPrev = new JButton ("<<");
btnNext = new JButton (">>");
mtblCalendar = new DefaultTableModel();
tblCalendar = new JTable(mtblCalendar); //Table using the above model

2
stblCalendar = new JScrollPane(tblCalendar); //The scrollpane of the above
table
pnlCalendar = new JPanel(null); //Create the "panel" to place components
Let's take a look at the constructors:
JFrame: String - The text to be shown in the window's title bar.
JLabel: String - The text to be shown in the label.
JComboBox: None
JButton: String - The text displayed in the button.
DefaultTableModel: None
JTable: DefaultTableModel - The model this table will use.
JScrollPane: Any component - The component using this scrollpane.
JPanel: Layout - The layout used in this panel.

We have not instantiated the Container object. You will find out why.

Preparing the frame

The objects are instantiated, but nothing is functional for now. We have a few steps
before. First, we must set the size of the window by invoking the setSize method of
JFrame:

frmMain.setSize(330, 375); //Two arguments: width and height


Now we will use our Container:

pane = frmMain.getConentPane();
We did not instantiate the Container, and we already use it. Why? Some objects cannot
be instantiated. This is weird but true. Next, we must set the layout of the frame. There
are plenty layouts, but we will simply use the null layout, best of all. Here you go:

pane.setLayout(null); //Apply the null layout


Finally (optional but recommended) we will tell the program to quit when we click the X
button:

frmMain.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); //Close when X is


clicked
So let's put all this together:

//Look and feel


try {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}
catch (ClassNotFoundException e) {}
catch (InstantiationException e) {}
catch (IllegalAccessException e) {}
catch (UnsupportedLookAndFeelException e) {}

//Prepare frame
frmMain = new JFrame ("Gestionnaire de clients"); //Create frame

3
frmMain.setSize(330, 375); //Set size to 330x375 pixels
pane = frmMain.getContentPane(); //Get content pane
pane.setLayout(null); //Apply null layout
frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Close when X is
clicked

//Create controls
lblMonth = new JLabel ("January");
lblYear = new JLabel ("Change year:");
cmbYear = new JComboBox();
btnPrev = new JButton ("<<");
btnNext = new JButton (">>");
mtblCalendar = new DefaultTableModel();
tblCalendar = new JTable(mtblCalendar);
stblCalendar = new JScrollPane(tblCalendar);
pnlCalendar = new JPanel(null);
Setting the border of the panel

Every JPanel is a container and should have a border. You know, the panels with a
border around something... Well, this is done with a single statement:

pnlCalendar.setBorder(BorderFactory.createTitledBorder("Calendar")); //Set
border
The setBorder(border) method of all components does the job. BorderFactory is a class
that generated many different types of borders, up to you to find out!

Adding the components to the Container

We created all, and we are ready to build our GUI. We will first of all add the
components to a Container (pane). This is done with the add method of the container.

//Add controls to pane


pane.add(pnlCalendar);
pnlCalendar.add(lblMonth);
pnlCalendar.add(lblYear);
pnlCalendar.add(cmbYear);
pnlCalendar.add(btnPrev);
pnlCalendar.add(btnNext);
pnlCalendar.add(stblCalendar);
We added all the controls. Or alomst all. The table model and the table itself were not
added, but the scrollpane was. It is simple: by adding the scrollpane, we automatically
added the table contained in it and this also caused the model to be "added". All
components are now in place, we must position them.

Positionning the controls

The setBounds method of all components will be used to set their position in the
container (in this case, the container is pane). It takes four parameters: x, y, width,
height. Simple enough. You will find out in this code:

4
//Set bounds
pnlCalendar.setBounds(0, 0, 320, 335);
lblMonth.setBounds(160-lblMonth.getPreferredSize().width/2, 25, 100, 25);
lblYear.setBounds(10, 305, 80, 20);
cmbYear.setBounds(230, 305, 80, 20);
btnPrev.setBounds(10, 25, 50, 25);
btnNext.setBounds(260, 25, 50, 25);
stblCalendar.setBounds(10, 50, 300, 250);
All right, nothing new here except one thing: lblMonth.getPreferredSize().width. This
method returns the preferred size of a component (e.g. its default size). If the JLabel's
text changes, its preferred size is also altered. We want in centered in the center of the
calendar on the X axis so we get the middle point of the calendar on X (160) and we
substract half the label's size, causing the label to be perfectly aligned with the
calendar!

Making the frame visible

Add those two self-explanatory lines after your code:

frmMain.setResizable(false);
frmMain.setVisible(true);
Useless to explain what they do. They both take a boolean as an argument. Now let's
start the real fun!

Getting the real month and year

To show at startup the appropriate calendar, it would be great to know which month
and year we are in. Remember we imported java.util.* before? That's here we will find
its utility. The GregorianCalendar class contained in this package contains a big bunch
of date and time functions. We will create a GregorianCalendar and get the info. If we
instantiate (see definition above) this class without any parameters, the actual calendar
is created, and this is what we are looking for. Let's do it:

//Get real month/year


GregorianCalendar cal = new GregorianCalendar(); //Create calendar
realDay = cal.get(GregorianCalendar.DAY_OF_MONTH); //Get day
realMonth = cal.get(GregorianCalendar.MONTH); //Get month
realYear = cal.get(GregorianCalendar.YEAR); //Get year
currentMonth = realMonth; //Match month and year
currentYear = realYear;
Now, the four integers we declared above are now used. The realMonth and realYear
integers contain the real month and year. The currentYear and currentMonth variables
contain the actual month/year we are viewing the calendar. Now, let the fun begin! We
will populate the year combo box and show the calendar!

Populating the combo box

In this tutorial, we will be able to view the calendars from 100 years ago to 100 years

5
in the future, but changing this is quite easy. First, let's populate the combo box (I
assume you know how a for loop works):

//Populate combo box


for (int i=realYear-100; i<=realYear+100; i++){
cmbYear.addItem(String.valueOf(i));
}
Something I haven't explained is here: String.valueOf(i). This simply returns a String
which is equal to the String value of i. Simple enough. Test your application. The
calendar is simply a dark gray rectangle, but the combo box is populated. We will
prepare the calendar.

Preparing the calendar

Now the calendar is only a dark gray square, but let's make room for the numbers! We
need 6 rows and 7 columns, for every day of the week. We need a white background
(later we will make the week-end days appear red), a grid and headers for the week
days. Let's add the headers:

//Add headers
String[] headers = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
//All headers
for (int i=0; i<7; i++){
mtblCalendar.addColumn(headers[i]);
}
The loop will put all elements of the headers array (containing the days' names) as
column headers. Now, we need to set the white background:

tblCalendar.getParent().setBackground(tblCalendar.getBackground()); //Set
background
This is needed because the area not covered with the cells does not belong to the
JTable itself, so we can't just use tblCalendar.setBackground(color). This is very strange
but it must be done the above way. Next thing: disallow column resizing/reordering.
This is done a really simple way:

//No resize/reorder
tblCalendar.getTableHeader().setResizingAllowed(false);
tblCalendar.getTableHeader().setReorderingAllowed(false);
Pretty self-explanatory. Now, we need to be able to select only one cell at a time to
make it more realistic. Again, this is simple:

//Single cell selection


tblCalendar.setColumnSelectionAllowed(true);
tblCalendar.setRowSelectionAllowed(true);
tblCalendar.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

6
I do not really need to explain this one. Finally, let's prepare a 7x6 calendar:

//Set row/column count


tblCalendar.setRowHeight(38);
mtblCalendar.setColumnCount(7);
mtblCalendar.setRowCount(6);
These 3 methods do the job. Run your program. The only thing missing is the numbers!
Let's add them. But just before, the full preparation code:

//Add columns
String[] headers = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
//All headers
for (int i=0; i<7; i++){
mtblCalendar.addColumn(headers[i]);
}

tblCalendar.getParent().setBackground(tblCalendar.getBackground()); //Set
background

tblCalendar.getTableHeader().setResizingAllowed(false);
tblCalendar.getTableHeader().setReorderingAllowed(false);

tblCalendar.setColumnSelectionAllowed(true);
tblCalendar.setRowSelectionAllowed(true);
tblCalendar.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

tblCalendar.setRowHeight(38);
mtblCalendar.setColumnCount(7);
mtblCalendar.setRowCount(6);

//Prepare calendar
for (int i=realYear-100; i<=realYear+100; i++){
cmbYear.addItem(String.valueOf(i));
}
Please note: it is mendatory that you put the loop to populate the combo box after the
preparation of the table. Otherwise, the action listener of the combo box will be fired
and since the table is not prepared the program will throw an error. It would be much
better with the numbers! Let's go!

Refreshing the calendar

If you are still following this tutorial correctly (and I hope you do), you should have a
blank calendar, only the numbers are missing. Create a method outside your main void:

public static void refreshCalendar(int month, int year){

7
This will be called to refresh the calendar. In your main void, after your code, put:

refreshCalendar (realMonth, realYear); //Refresh calendar

Back in the method we just created, we start by declaring an array containing the
months' real names and we decide if the next/previous buttons should be enabled,
depending if we reached our capacity (100 years ago or in the future, remember). Also,
we create two integers, one to determine the number of days in that month and the
other to determine the day of week of the first day of that month.
public static void refreshCalendar(int month, int year){
String[] months = {"January", "February", "March", "April", "May",
"June", "July", "August", "September", "October", "November", "December"};
int nod, som; //Number Of Days, Start Of Month

btnPrev.setEnabled(true); //Enable buttons at first


btnNext.setEnabled(true);
if (month == 0 && year <= realYear-10){btnPrev.setEnabled(false);}
//Too early
if (month == 11 && year >=
realYear+100){btnNext.setEnabled(false);} //Too late
lblMonth.setText(months[month]); //Refresh the month label (at the
top)
lblMonth.setBounds(160-lblMonth.getPreferredSize().width/2, 25,
180, 25); //Re-align label with calendar
cmbYear.setSelectedItem(String.valueOf(year)); //Select the correct
year in the combo box
}
Make sure the previous example is fully understood before proceeding. Now, remember
the nod and som variables we declared, we will now assign values to them:

//Get first day of month and number of days


GregorianCalendar cal = new GregorianCalendar(year, month, 1);
nod = cal.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
som = cal.get(GregorianCalendar.DAY_OF_WEEK);

Remember what I said above: the constructor of GregorianCalendar with no arguments


is the actual date. But in this one we gave 3 arguments: the year, the month and the
day (first of the month). The get methods will get the required informations, this is self-
explanatory. Now, the refreshCalendar() method will be called more than once in the
code execution, so we must clear all the calendar every time in order to draw the new
one. This is done that way:

//Clear table
for (int i=0; i<6; i++){
for (int j=0; j<7; j++){
mtblCalendar.setValueAt(null, i, j);
}

8
}
Here's how your method should look by now:

public static void refreshCalendar(int month, int year){


String[] months = {"January", "February", "March", "April", "May",
"June", "July", "August", "September", "October", "November", "December"};
int nod, som; //Number Of Days, Start Of Month

//Prepare buttons
btnPrev.setEnabled(true); //Enable buttons at first
btnNext.setEnabled(true);
if (month == 0 && year <= realYear-10){btnPrev.setEnabled(false);}
//Too early
if (month == 11 && year >=
realYear+100){btnNext.setEnabled(false);} //Too late
lblMonth.setText(months[month]); //Refresh the month label (at the
top)
lblMonth.setBounds(160-lblMonth.getPreferredSize().width/2, 25,
180, 25); //Re-align label with calendar
cmbYear.setSelectedItem(String.valueOf(year)); //Select the correct
year in the combo box

//Get number of days and start of month


GregorianCalendar cal = new GregorianCalendar(year, month, 1);
nod = cal.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
som = cal.get(GregorianCalendar.DAY_OF_WEEK);

//Clear table
for (int i=0; i<6; i++){
for (int j=0; j<7; j++){
mtblCalendar.setValueAt(null, i, j);
}
}

for (int i=1; i<=nod; i++){


int row = new Integer((i+som-2)/7);
int column = (i+som-2)%7;
mtblCalendar.setValueAt(i, row, column);
}
}
Run the program. Nice! You got the calendar! As stated above, we will make the
weekend days appear red. This is now one of the most difficult things in Java
programming: writing custom renderers! Let's dig in (or at least try).

Writing the custom renderer

This step is not mendatory but I recommend you learn it if you want to write other
kinds of renderers later. First, we need to declare (again) the renderer outside our
method:

static class tblCalendarRenderer extends DefaultTableCellRenderer{

9
}
I hope you understand the "extends" concept. Now that this is declared, we declare the
main method of it, which will apply the renderer:

static class lvwCalendarRenderer extends DefaultTableCellRenderer{


public Component getTableCellRendererComponent (JTable table,
Object value, boolean selected, boolean focused, int row, int column){
super.getTableCellRendererComponent(table, value, selected,
focused, row, column);
return this;
}
}
It is starting to make sense. As you have probably noticed, a few parameters can be
read: row, column, value, and so on. We will see if the column is either 0 or 6 (sunday
or saturday) and apply a red color. Also, the current day will appear blue:

static class tblCalendarRenderer extends DefaultTableCellRenderer{


public Component getTableCellRendererComponent (JTable
table, Object value, boolean selected, boolean focused, int row, int
column){
super.getTableCellRendererComponent(table, value,
selected, focused, row, column);
if (column == 0 || column == 6){ //Week-end
setBackground(new Color(255, 220, 220));
}
else{ //Week
setBackground(new Color(255, 255, 255));
}
if (value != null){
if (Integer.parseInt(value.toString()) ==
realDay && currentMonth == realMonth && currentYear == realYear){ //Today
setBackground(new Color(220, 220,
255));
}
}
setBorder(null);
setForeground(Color.black);
return this;
}
}
We finished our renderer! This was quite a simple one, now we need to apply it. In the
refreshCalendar method, at the end, write:

tblCalendar.setDefaultRenderer(tblCalendar.getColumnClass(0), new
tblCalendarRenderer()); //Apply renderer

The setDefaultRenderer method applies the renderer to the table. The first parameter
can be any class, it is not used (I don't even know why it exists). The second is the
renderer. Now run the program. What a nice looking calendar! But since nothing in life

10
is ever finished, we will create the actions for the buttons and the year combo.

Registering action listeners

Anywhere in the main void, add these self-explanatory lines:

//Register action listeners


btnPrev.addActionListener(new btnPrev_Action());
btnNext.addActionListener(new btnNext_Action());
cmbYear.addActionListener(new cmbYear_Action());

These are the events that will be triggered when the buttons will be clicked, or we will
select an item in the year combo. Pretty easy, no? Anyway, here is the action for the
prevous button:

static class btnPrev_Action implements ActionListener{


public void actionPerformed (ActionEvent e){
if (currentMonth == 0){ //Back one year
currentMonth = 11;
currentYear -= 1;
}
else{ //Back one month
currentMonth -= 1;
}
refreshCalendar(currentMonth, currentYear);
}
}
The code is simple: if we are in January (month 0), it goes to the month of December
of the previous year. Else, it goes back one year. Then, the calendar is refreshed. Now
here is the one for the next button, no explanation needed:

static class btnNext_Action implements ActionListener{


public void actionPerformed (ActionEvent e){
if (currentMonth == 11){ //Foward one year
currentMonth = 0;
currentYear += 1;
}
else{ //Foward one month
currentMonth += 1;
}
refreshCalendar(currentMonth, currentYear);
}
}
The opposite of the previous listener. Now let's do the one for the combo box:

static class cmbYear_Action implements ActionListener{


public void actionPerformed (ActionEvent e){
if (cmbYear.getSelectedItem() != null){
String b = cmbYear.getSelectedItem().toString();

11
currentYear = Integer.parseInt(b); //Get the numeric
value
refreshCalendar(currentMonth, currentYear);
//Refresh
}
}
}
Put these 3 action listeners outside your existing methond but in the main class. Run
the program. Fine! Double-click on a cell. Oops, it is editable. We do not want this. How
do we fix it? Find the line:

mtblCalendar = new DefaultTableModel();


Replace this line by:

mtblCalendar = new DefaultTableModel(){public boolean isCellEditable(int


rowIndex, int mColIndex){return false;}};

This is called method overriding. It simply overrides the exitsing method, making the
cells uneditable. Now all our code is written!

Putting it all together to work

If you followed this tutorial correctly, you should get this:

/*Contents of CalendarProgran.class */

//Import packages
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class CalendarProgram{


static JLabel lblMonth, lblYear;
static JButton btnPrev, btnNext;
static JTable tblCalendar;
static JComboBox cmbYear;
static JFrame frmMain;
static Container pane;
static DefaultTableModel mtblCalendar; //Table model
static JScrollPane stblCalendar; //The scrollpane
static JPanel pnlCalendar;
static int realYear, realMonth, realDay, currentYear, currentMonth;

public static void main (String args[]){


//Look and feel
try
{UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}

12
catch (ClassNotFoundException e) {}
catch (InstantiationException e) {}
catch (IllegalAccessException e) {}
catch (UnsupportedLookAndFeelException e) {}

//Prepare frame
frmMain = new JFrame ("Gestionnaire de clients"); //Create
frame
frmMain.setSize(330, 375); //Set size to 400x400 pixels
pane = frmMain.getContentPane(); //Get content pane
pane.setLayout(null); //Apply null layout
frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Close when X is clicked

//Create controls
lblMonth = new JLabel ("January");
lblYear = new JLabel ("Change year:");
cmbYear = new JComboBox();
btnPrev = new JButton ("<<");
btnNext = new JButton (">>");
mtblCalendar = new DefaultTableModel(){public boolean
isCellEditable(int rowIndex, int mColIndex){return false;}};
tblCalendar = new JTable(mtblCalendar);
stblCalendar = new JScrollPane(tblCalendar);
pnlCalendar = new JPanel(null);

//Set border

pnlCalendar.setBorder(BorderFactory.createTitledBorder("Calendar"))
;

//Register action listeners


btnPrev.addActionListener(new btnPrev_Action());
btnNext.addActionListener(new btnNext_Action());
cmbYear.addActionListener(new cmbYear_Action());

//Add controls to pane


pane.add(pnlCalendar);
pnlCalendar.add(lblMonth);
pnlCalendar.add(lblYear);
pnlCalendar.add(cmbYear);
pnlCalendar.add(btnPrev);
pnlCalendar.add(btnNext);
pnlCalendar.add(stblCalendar);

//Set bounds
pnlCalendar.setBounds(0, 0, 320, 335);
lblMonth.setBounds(160-lblMonth.getPreferredSize().width/2,
25, 100, 25);
lblYear.setBounds(10, 305, 80, 20);
cmbYear.setBounds(230, 305, 80, 20);
btnPrev.setBounds(10, 25, 50, 25);
btnNext.setBounds(260, 25, 50, 25);
stblCalendar.setBounds(10, 50, 300, 250);

13
//Make frame visible
frmMain.setResizable(false);
frmMain.setVisible(true);

//Get real month/year


GregorianCalendar cal = new GregorianCalendar(); //Create
calendar
realDay = cal.get(GregorianCalendar.DAY_OF_MONTH); //Get
day
realMonth = cal.get(GregorianCalendar.MONTH); //Get month
realYear = cal.get(GregorianCalendar.YEAR); //Get year
currentMonth = realMonth; //Match month and year
currentYear = realYear;

//Add headers
String[] headers = {"Sun", "Mon", "Tue", "Wed", "Thu",
"Fri", "Sat"}; //All headers
for (int i=0; i<7; i++){
mtblCalendar.addColumn(headers[i]);
}

tblCalendar.getParent().setBackground(tblCalendar.getBackground());
//Set background

//No resize/reorder
tblCalendar.getTableHeader().setResizingAllowed(false);
tblCalendar.getTableHeader().setReorderingAllowed(false);

//Single cell selection


tblCalendar.setColumnSelectionAllowed(true);
tblCalendar.setRowSelectionAllowed(true);

tblCalendar.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

//Set row/column count


tblCalendar.setRowHeight(38);
mtblCalendar.setColumnCount(7);
mtblCalendar.setRowCount(6);

//Populate table
for (int i=realYear-100; i<=realYear+100; i++){
cmbYear.addItem(String.valueOf(i));
}

//Refresh calendar
refreshCalendar (realMonth, realYear); //Refresh calendar
}

public static void refreshCalendar(int month, int year){


//Variables

14
String[] months = {"January", "February", "March",
"April", "May", "June", "July", "August", "September", "October",
"November", "December"};
int nod, som; //Number Of Days, Start Of Month

//Allow/disallow buttons
btnPrev.setEnabled(true);
btnNext.setEnabled(true);
if (month == 0 && year <= realYear-
10){btnPrev.setEnabled(false);} //Too early
if (month == 11 && year >=
realYear+100){btnNext.setEnabled(false);} //Too late
lblMonth.setText(months[month]); //Refresh the month label
(at the top)
lblMonth.setBounds(160-lblMonth.getPreferredSize().width/2,
25, 180, 25); //Re-align label with calendar
cmbYear.setSelectedItem(String.valueOf(year)); //Select the
correct year in the combo box

//Clear table
for (int i=0; i<6; i++){
for (int j=0; j<7; j++){
mtblCalendar.setValueAt(null, i, j);
}
}

//Get first day of month and number of days


GregorianCalendar cal = new GregorianCalendar(year, month,
1);
nod = cal.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
som = cal.get(GregorianCalendar.DAY_OF_WEEK);

//Draw calendar
for (int i=1; i<=nod; i++){
int row = new Integer((i+som-2)/7);
int column = (i+som-2)%7;
mtblCalendar.setValueAt(i, row, column);
}

//Apply renderers

tblCalendar.setDefaultRenderer(tblCalendar.getColumnClass(0), new
tblCalendarRenderer());
}

static class tblCalendarRenderer extends DefaultTableCellRenderer{


public Component getTableCellRendererComponent (JTable
table, Object value, boolean selected, boolean focused, int row, int
column){
super.getTableCellRendererComponent(table, value,
selected, focused, row, column);
if (column == 0 || column == 6){ //Week-end
setBackground(new Color(255, 220, 220));
}

15
else{ //Week
setBackground(new Color(255, 255, 255));
}
if (value != null){
if (Integer.parseInt(value.toString()) ==
realDay && currentMonth == realMonth && currentYear == realYear){ //Today
setBackground(new Color(220, 220,
255));
}
}
setBorder(null);
setForeground(Color.black);
return this;
}
}

static class btnPrev_Action implements ActionListener{


public void actionPerformed (ActionEvent e){
if (currentMonth == 0){ //Back one year
currentMonth = 11;
currentYear -= 1;
}
else{ //Back one month
currentMonth -= 1;
}
refreshCalendar(currentMonth, currentYear);
}
}
static class btnNext_Action implements ActionListener{
public void actionPerformed (ActionEvent e){
if (currentMonth == 11){ //Foward one year
currentMonth = 0;
currentYear += 1;
}
else{ //Foward one month
currentMonth += 1;
}
refreshCalendar(currentMonth, currentYear);
}
}
static class cmbYear_Action implements ActionListener{
public void actionPerformed (ActionEvent e){
if (cmbYear.getSelectedItem() != null){
String b =
cmbYear.getSelectedItem().toString();
currentYear = Integer.parseInt(b);
refreshCalendar(currentMonth, currentYear);
}
}
}
}

Run the program. Enjoy!

16
Conclusion

Well, we arrived at the end of this tutorial. This was a pretty complex one, do not worry
if you do not fully understand it. But sooner or later, you will need to work with
renderers. If you have any questions, contact me!

17

Vous aimerez peut-être aussi