• (3 Pages)
  • +
  • 1
  • 2
  • 3

Creating a calendar viewer application GUIs, renderers, JTable tutorial Rate Topic: ***** 3 Votes

#1 alpha02  Icon User is offline

  • Sexy DIC God
  • member icon

Reputation: 46
  • View blog
  • Posts: 803
  • Joined: 20-May 06

Posted 13 March 2007 - 05:53 PM

*
POPULAR

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
	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
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
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:

//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 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);


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){

}


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);
	}
}


Two for loops nested, and a new method: setValueAt. This takes 3 parameters: value, row and column. So the loop loops through all the cells and assigns a null value to all of them, causing the table to be cleared. Lastly, we are ready to draw the calendar, using this loop:

//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);
}


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{
	   	
}


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 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();
			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());}
		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);
		
		//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
		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));
			}
			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!

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!

This post has been edited by alpha02: 08 July 2007 - 11:29 AM


Is This A Good Question/Topic? 7
  • +

Replies To: Creating a calendar viewer application

#2 TheKingOfCodes  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 08-July 07

Posted 08 July 2007 - 10:41 AM

[size=2]think you so much for this amaizing codes, for this i have choosen this code to be my project in java, but
it there is something missing in this code which is you didn't make any sign or highlight the cell in jtable
to keep track on date, so i have been tring to solve this for four days and with out any gain so please complete the missing part and i'd be so appreciated if so, and thinks again.
Was This Post Helpful? 0
  • +
  • -

#3 alpha02  Icon User is offline

  • Sexy DIC God
  • member icon

Reputation: 46
  • View blog
  • Posts: 803
  • Joined: 20-May 06

Posted 08 July 2007 - 11:33 AM

View PostTheKingOfCodes, on 8 Jul, 2007 - 01:41 PM, said:

[size=2]think you so much for this amaizing codes, for this i have choosen this code to be my project in java, but
it there is something missing in this code which is you didn't make any sign or highlight the cell in jtable
to keep track on date, so i have been tring to solve this for four days and with out any gain so please complete the missing part and i'd be so appreciated if so, and thinks again.


The tutorial has been updated, now the current day is highlighted blue :)
Was This Post Helpful? 0
  • +
  • -

#4 zidane1845  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 27-July 07

Posted 18 September 2007 - 07:05 PM

seems this could help a lot...thanks, i'll let you know how it goes!
Was This Post Helpful? 0
  • +
  • -

#5 khatnuoc  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 10-March 09

Posted 10 March 2009 - 10:22 AM

Please tell me how to Add Calendar In Jtable?

Thanks a lot!
Was This Post Helpful? 0
  • +
  • -

#6 korpral  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 4
  • Joined: 24-March 09

Posted 24 March 2009 - 05:51 PM

Hi, thanks for the amazing code :)
How can i change the code so i can add a JButton with listener into a specific cell??
Was This Post Helpful? 1
  • +
  • -

#7 ts230  Icon User is offline

  • D.I.C Head

Reputation: 11
  • View blog
  • Posts: 225
  • Joined: 11-July 09

Posted 14 August 2009 - 11:12 PM

Is there any way on how to use this as a cell renderer in a JTable?
Was This Post Helpful? 0
  • +
  • -

#8 Guest_phreanz_44*


Reputation:

Posted 07 March 2010 - 10:01 PM

i just find hard to run your program..... i just try your codes above and follow your tutorial, but still,i can't make it.... i just run you code and it says:

--------------------Configuration: <Default>--------------------
\\Pc071\071\joey\CalendarProgram.java:148: cannot resolve symbol
symbol : method setValueAt (int,int,int)
location: class javax.swing.table.DefaultTableModel
mtblCalendar.setValueAt(i, row,column);
^
1 error

Process completed.


so i replaced i by null.... it works but there are no numbers on it.... aheheh.... :0?
Was This Post Helpful? 1

#9 Guest_guest me*


Reputation:

Posted 12 March 2010 - 10:27 PM

--------------------Configuration: <Default>--------------------
C:\Documents and Settings\Administrator\Desktop\JCreator LE\Java Documents\CalendarProgram.java:146: incompatible types
found : java.lang.Integer
required: int
int row =new Integer((i+som-2)/7);
^
C:\Documents and Settings\Administrator\Desktop\JCreator LE\Java Documents\CalendarProgram.java:148: cannot resolve symbol
symbol : method setValueAt (int,int,int)
location: class javax.swing.table.DefaultTableModel
mtblCalendar.setValueAt(i, row, column);
^
2 errors

Process completed.

this what i got when i compile your code. I hope u may fix it for better tutorial.
Was This Post Helpful? 0

#10 EnvXOwner  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 357
  • View blog
  • Posts: 2,319
  • Joined: 10-August 09

Posted 28 March 2010 - 09:01 AM

View Postphreanz_44, on 07 March 2010 - 09:01 PM, said:

i just find hard to run your program..... i just try your codes above and follow your tutorial, but still,i can't make it.... i just run you code and it says:

--------------------Configuration: <Default>--------------------
\\Pc071\071\joey\CalendarProgram.java:148: cannot resolve symbol
symbol : method setValueAt (int,int,int)
location: class javax.swing.table.DefaultTableModel
mtblCalendar.setValueAt(i, row,column);
^
1 error

Process completed.


so i replaced i by null.... it works but there are no numbers on it.... aheheh.... :0?

You should Eclipse when coding in Java. It has a compiler built in. Here the url. I hope you like it.

This post has been edited by VB.Terry: 29 March 2010 - 03:09 AM

Was This Post Helpful? 0
  • +
  • -

#11 leorayleigh  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 1
  • Joined: 29-March 10

Posted 29 March 2010 - 05:43 AM

Thank you so much~! I've been searching the interwebs for a calendar program to implement into my system. And the tutorial you wrote has helped me code my own little date selection interface~! Thank you so so much!

ps. registered an account just so I could show my gratitude~! ^^
This seems like a really helpful forum too. Might lurk around for abit~!
Was This Post Helpful? 1
  • +
  • -

#12 dipito31  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 22-April 10

Posted 22 April 2010 - 07:52 AM

Hey there...ive read your code and you do allow individual cell selection...but i dont know why...for some reason i cant select any of them....it would be really help if you could help me out as i need an event based calender that add an appointment if clicked on a date..
Was This Post Helpful? 0
  • +
  • -

#13 josko  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 04-May 10

Posted 05 May 2010 - 12:25 PM

very helpfull tutorial,very nice job
but do you have a tutorial or some link how to make iCalendar
Thanx
Josko
Was This Post Helpful? 0
  • +
  • -

#14 Guest_Metsis*


Reputation:

Posted 28 May 2010 - 12:18 AM

I got the code working in Netbeans easily and the result is nice looking calendar... except there is one major flaw in it. Week do begin at Monday allmost everywhere in the world. For some inexplicable reason, Java has other opinion.

Therefore you need to add following correcting code just before filling the calendar in the for loop in the method refreshCalendar:

if (startOfMonth == GregorianCalendar.SUNDAY){
startOfMonth = 7;
}
else {
startOfMonth--;
} // if startOfMonth

Have a nice day!
Was This Post Helpful? 0

#15 josko  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 04-May 10

Posted 28 May 2010 - 04:22 AM

Can you post that code here or send to me on email if that's not a problem,and if you can do it.
Thanx.
Was This Post Helpful? 0
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3