Posts Tagged ‘ JTable ’

Masalah baru Master-detail ! TableCellRenderer!

Salah satu teman saya yaitu si echo punya masalah dan telah berhasil menyelesaikannya. Kalau gak salah masalah yang dihadapi adalah master-detail di Java Swing nah kira-kira seperti dibawah ini hasil penyelesaian masalahnya.

Masalah diatas sudah diselesaikan oleh echo, tapi kok saya menemukan masalah baru. Antara lain :

  1. Tanggal lahir masih muncul secara komplit sampai ke detik-detiknya juga, bagaimana cara memperbaiki tampilan tanggal lahir agar sesuai dengan format yang diinginkan seperti 04-April-1990.
  2. Kolom Jenis kelamin juga baru menampilkan tampilan apa adanya seperti yang ada pada Enum JenisKelamin, bagaimana cara kita agar dapat menampilkan sesuai dengan keinginan.
  3. Bagaimana kalau data dari sebuah kolom bertipe double dan merupakan data berupa uang. Standar penulisan uang di Indonesia adalah simbol  “Rp.”, pemisah ribuan “.” dan koma “,” contohnya “Rp. 90.000,00”. Sedangkan default pada Java menggunakan standar amerika yaitu simbol “$”, pemisah ribuan “,” dan koma “.”.
  4. Apabila seorang mahasiswa mempunyai data berupa foto, bagaimana cara agar JTable dapat menampilkan data foto berupa gambar bukan hanya string.

Saya berfikir sejenak……………
Nah ketemu solusinya!!

Solusi tak lain dan tak bukan adalah TableCellRenderer yaitu Kelas yang digunakan untuk merender cell pada JTable sehingga kita bisa menentukan bagaimana format data dan komponen yang akan dimunculkan. Komponen yang dirender secara default oleh JTable adalah JLabel sehingga kita hanya perlu mengatur text yang tampil pada JTable, tetapi tidak menutup kemungkinan kita untuk merender komponen lain seperti JPanel.
TableCellRenderer didaftarkan pada JTable sesuai dengan type class pada setiap column, contoh TableCellRenderer untuk Date.class.

tabelMahasiswa.setDefaultRenderer(Date.class, new DateTableCellRenderer());
Source code diatas salah satu contoh pendaftaran TableCellRenderer dengan type Date.class. Oh iya untuk memastikan type dari column-column di JTable kita harus menambahkan sedikit kode program pada TableModel.

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
            case 0:
                return String.class;
            case 1:
                return String.class;
            case 2:
                return String.class;
            case 3:
                return Date.class;
            case 4:
                return Mahasiswa.JenisKelamin.class;
            case 5:
                return Image.class;
            default:
                return null;
        }
    }

Fungsi getColumnClass(int) merupakan hasil override dari kelas AbstractTableModel seperti halnya fungsi getColumnName(int). Pada NetBeans kita cukup menekan alt+insert, pilih ‘Override Method…’ kemudian pilih fungsi yang akan di override. Cara kerja fungsi getColumnClass(int) sama seperti fungsi getColumnName(int) kita harus menentukan secara manual type-type kolom sesuai dengan urutannya (ingat dimulai dari 0 bukan 1).

package org.jasoet.swing.cellrenderer;

import java.awt.Component;
import java.text.SimpleDateFormat;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;

/**
 *
 * @author Deny Prasetyo
 */
public class DateTableCellRenderer extends DefaultTableCellRenderer {

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd MMMM yyyy");

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        JLabel component = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        component.setHorizontalAlignment(SwingConstants.CENTER);
        component.setText(simpleDateFormat.format(value));

        return component;
    }
}

Source code diatas merupakan solusi untuk masalah nomor 1. Kita hanya perlu memformat data yang berupa date menggunakan kelas SimpleDateFormat. Pattern yang digunakan kali ini adalah “dd MMMM yyyy” yang akan menghasilkan format tanggal seperti “01 January 2010”, untuk pattern-pattern yang lain bisa dilihat di dokumentasi kelas SimpleDateFormat.
Hasil dari format kelas SimpleDateFormat cukup kita masukkan sebagai properti text pada komponen JLabel dan apabila perlu kita atur juga alignment agar rata tengah (Center).Oh iya untuk membuat custom TableCellRender kita hanya perlu membuat kelas turunan dari DefaultTableCellRenderer dan meng-override fungsi getTableCellRendererComponent.
Nah masalah nomor 1 sudah selesai sekarang kita lanjut ke nomor 2. Konsep untuk menyelesaikan nomor 2 hampir sama seperti pada nomor 1. Pada dasarnya Enum merupakan sebuah kelas sehingga kita hanya perlu membuat sebuah TableCellRenderer dan mendaftarkannya untuk type JenisKelamin.class.

tabelMahasiswa.setDefaultRenderer(JenisKelamin.class, new JenisKelaminTableCellRenderer());
package org.jasoet.swing.cellrenderer;

import java.awt.Component;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;
import khannedy.blogging.masterdetail.entity.Mahasiswa.JenisKelamin;

/**
 *
 * @author Deny Prasetyo
 */
public class JenisKelaminTableCellRenderer extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        JLabel component = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        component.setHorizontalAlignment(SwingConstants.CENTER);
        JenisKelamin jk = (JenisKelamin) value;
        if (jk == JenisKelamin.LakiLaki) {
            component.setText("Laki-Laki");
        } else {
            component.setText("Perempuan");
        }
        return component;
    }
}
 

Untuk menyelesaikan masalah nomor 3 dan 4 kita harus menambahkan beberapa field pada kelas Mahasiswa dan MataKuliah karena pada program yang dibuat echo tidak menyertakan contoh field berupa double dan image.

Tambahkan 1 field berupa String dengan mana urlFoto. Field ini nanti akan berisi nama file gambar yang dimaksudkan sebagai Foto.


private String urlFoto;
 public String getUrlFoto() {
 return urlFoto;
 }

 public void setUrlFoto(String urlFoto) {
 this.urlFoto = urlFoto;
 }

Tambahkan 2 field yaitu sks dan biaya pada kelas MataKuliah, Sks bertipe Integer dan Biaya bertipe Double.  Untuk 2 field ini sudah jelas kan kegunaannya.


private int sks;
private Double biaya;

public Double getBiaya() {
return biaya;
}

public void setBiaya(Double biaya) {
this.biaya = biaya;
}

public int getSks() {
return sks;
}

public void setSks(int sks) {
this.sks = sks;
}

Dengan bertambahnya 1 field pada kelas Mahasiswa dan 2 Field pada otomatis kita diharuskan untuk mengedit TableModelMahasiswa,TableModelMataKuliah dan MahasiswaService.

TableModelMahasiswa.java


package khannedy.blogging.masterdetail.model;

import java.awt.Image;
import java.util.Date;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import khannedy.blogging.masterdetail.entity.Mahasiswa;

public class TableModelMahasiswa extends AbstractTableModel {

private List<Mahasiswa> list;

public TableModelMahasiswa(List<Mahasiswa> list) {
this.list = list;
}

public List<Mahasiswa> getList() {
return list;
}

public int getRowCount() {
return list.size();
}

public int getColumnCount() {
return 6; //Edited by Jasoet
}

@Override
public String getColumnName(int column) {
switch (column) {
case 0:
return "Nim";
case 1:
return "Nama Depan";
case 2:
return "Nama Belakang";
case 3:
return "Tanggal Lahir";
case 4:
return "Jenis Kelamin";
//Added by Jasoet [start]
case 5:
return "Foto";
//Added by Jasoet [end]
default:
return null;
}
}

public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return list.get(rowIndex).getNim();
case 1:
return list.get(rowIndex).getNamaDepan();
case 2:
return list.get(rowIndex).getNamaBelakang();
case 3:
return list.get(rowIndex).getTanggalLahir();
case 4:
return list.get(rowIndex).getJenisKelamin();
//Added by Jasoet [start]
case 5:
return list.get(rowIndex).getUrlFoto();
//Added by Jasoet [end]
default:
return null;
}
}

//Added by Jasoet [start]
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return String.class;
case 1:
return String.class;
case 2:
return String.class;
case 3:
return Date.class;
case 4:
return Mahasiswa.JenisKelamin.class;
case 5:
return Image.class;
default:
return null;
}
}
//Added by Jasoet [end]
}

TableModelMataKuliah.java


package khannedy.blogging.masterdetail.model;

import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import khannedy.blogging.masterdetail.entity.MataKuliah;

public class TableModelMataKuliah extends AbstractTableModel {

private List<MataKuliah> list = new ArrayList<MataKuliah>();

public void setList(List<MataKuliah> list) {
this.list = list;
fireTableDataChanged();
}

public int getRowCount() {
return list.size();
}

public int getColumnCount() {
return 4;//Edited by Jasoet
}

@Override
public String getColumnName(int column) {
switch (column) {
case 0:
return "Kode";
case 1:
return "Nama";
//Added by Jasoet [start]
case 2:
return "SKS";
case 3:
return "Biaya";
//Added by Jasoet [end]
default:
return null;
}
}

public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return list.get(rowIndex).getKode();
case 1:
return list.get(rowIndex).getNama();
//Added by Jasoet [start]
case 2:
return list.get(rowIndex).getSks();
case 3:
return list.get(rowIndex).getBiaya();
//Added by Jasoet [end]
default:
return null;
}
}

//Added by Jasoet [start]
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return String.class;
case 1:
return String.class;
case 2:
return Integer.class;
case 3:
return Double.class;
default:
return null;
}
}
//Added by Jasoet [end]
}

MahasiswaService.java


package khannedy.blogging.masterdetail.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import khannedy.blogging.masterdetail.entity.Mahasiswa;
import khannedy.blogging.masterdetail.entity.MataKuliah;

public class MahasiswaService {

 public List<Mahasiswa> getAllMahasiswa(Integer count) {
 List<Mahasiswa> mahasiswas = new ArrayList<Mahasiswa>();

 for (int i = 0; i < count; i++) {
 if (i % 4 == 0) {
 Mahasiswa mahasiswa = createMahasiswa("10106031", "Eko Kurniawan", "Khannedy", new Date(), Mahasiswa.JenisKelamin.LakiLaki,"p.png");
 mahasiswa.add(createMataKuliah("IF3456", "Sistem Informasi Geografis",3,90000));
 mahasiswa.add(createMataKuliah("IF3457", "Komputer Grafika",3,80000));
 mahasiswa.add(createMataKuliah("IF3458", "Rekayasa Perangkat Lunak",2,12000));
 mahasiswa.add(createMataKuliah("IF3459", "Pemrograman Berorientasi Objek",4,45000));
 mahasiswas.add(mahasiswa);
 } else if (i % 4 == 1) {
 Mahasiswa mahasiswa = createMahasiswa("10106032", "Tini", "Sumarni", new Date(), Mahasiswa.JenisKelamin.Perempuan,"7.png");
 mahasiswa.add(createMataKuliah("IF3413", "Algoritma dan Pemrograman Lanjutan",1,21000));
 mahasiswa.add(createMataKuliah("IF3489", "Kewirausahaan",3,23000));
 mahasiswa.add(createMataKuliah("IF3468", "Manajemen Proyek",4,45000));
 mahasiswa.add(createMataKuliah("IF3499", "Sistem Basis Data",3,16000));
 mahasiswas.add(mahasiswa);
 } else if (i % 4 == 2) {
 Mahasiswa mahasiswa = createMahasiswa("10106032", "Tono", "Sumarno", new Date(), Mahasiswa.JenisKelamin.LakiLaki,"8.png");
 mahasiswa.add(createMataKuliah("IF3412", "Algoritma dan Pemrograman",5,23000));
 mahasiswa.add(createMataKuliah("IF3457", "Komputer Grafika",2,40000));
 mahasiswa.add(createMataKuliah("IF3468", "Manajemen Proyek",1,50000));
 mahasiswa.add(createMataKuliah("IF3449", "Pengolahan Citra",2,23000));
 mahasiswas.add(mahasiswa);
 } else {
 Mahasiswa mahasiswa = createMahasiswa("10106022", "Rina", "Sholihat", new Date(), Mahasiswa.JenisKelamin.Perempuan,"12.png");
 mahasiswa.add(createMataKuliah("IF3412", "Algoritma dan Pemrograman",2,45000));
 mahasiswa.add(createMataKuliah("IF3489", "Kewirausahaan",3,25000));
 mahasiswa.add(createMataKuliah("IF3466", "Database Lanjut",4,40000));
 mahasiswa.add(createMataKuliah("IF3423", "Pengenalan Ilmu Komputer",2,29000));
 mahasiswas.add(mahasiswa);
 }
 }

 return mahasiswas;
 }

 protected MataKuliah createMataKuliah(String code, String name,int sks,double biaya) {
 MataKuliah mataKuliah = new MataKuliah();
 mataKuliah.setKode(code);
 mataKuliah.setNama(name);
 mataKuliah.setSks(sks);
 mataKuliah.setBiaya(biaya);
 return mataKuliah;
 }

 protected Mahasiswa createMahasiswa(String nim, String namaDepan,
 String namaBelakang, Date tanggalLahir,
 Mahasiswa.JenisKelamin jenisKelamin,String urlFoto) {

 Mahasiswa mahasiswa = new Mahasiswa();
 mahasiswa.setJenisKelamin(jenisKelamin);
 mahasiswa.setNamaBelakang(namaBelakang);
 mahasiswa.setNamaDepan(namaDepan);
 mahasiswa.setNim(nim);
 mahasiswa.setTanggalLahir(tanggalLahir);
 mahasiswa.setUrlFoto(urlFoto);
 return mahasiswa;
 }
}

Setelah itu kita perlu membuat 2 buah TableCellRenderer lagi yaitu ImageTableCellRenderer dan DoubleTableCellRenderer.

ImageTableCellRenderer.java

package org.jasoet.swing.cellrenderer;

import java.awt.Component;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;

/**
 *
 * @author Deny Prasetyo
 */
public class ImageTableCellRenderer extends DefaultTableCellRenderer {

 private String imageLocation = "/org/jasoet/swing/images/";

 @Override
 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
 if (isSelected) {
 JLabel component = new JLabel();
 URL resource = getClass().getResource(imageLocation + value);
 ImageIcon imageIcon = new ImageIcon(resource);

 component.setIcon(imageIcon);
 component.setText("");
 component.setHorizontalAlignment(SwingConstants.CENTER);
 int currentHeight = table.getRowHeight(row);
 int currentRowWidth = table.getColumnModel().getColumn(column).getPreferredWidth();

 if (currentHeight < imageIcon.getIconHeight()) {
 table.setRowHeight(row, imageIcon.getIconHeight());
 }
 if (currentRowWidth < imageIcon.getIconWidth()) {
 table.getColumnModel().getColumn(column).setPreferredWidth(imageIcon.getIconWidth());
 }

 return component;
 } else {
 JLabel component = new JLabel();

 component.setText("" + value);
 component.setHorizontalAlignment(SwingConstants.CENTER);
 table.setRowHeight(row, 16);

 return component;
 }
 }
}

DoubleCellRenderer.java


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.jasoet.swing.cellrenderer;

import java.awt.Component;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;

/**
 *
 * @author Deny Prasetyo
 */
public class DoubleCellRenderer extends DefaultTableCellRenderer {

 private DecimalFormat decimalFormat;

 public DoubleCellRenderer() {
 Locale idLocale = new Locale("id");
 DecimalFormatSymbols dfs = new DecimalFormatSymbols(idLocale);
 dfs.setCurrencySymbol("Rp. ");
 decimalFormat = new DecimalFormat("\u00A4##,###.##", dfs);
 }

 @Override
 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
 JLabel component = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
 component.setHorizontalAlignment(SwingConstants.RIGHT);
 component.setText(decimalFormat.format(value));

 return component;
 }
}

Hasilnya kira-kira sperti ini.

Untuk kode program komplit  bisa di-checkout menggunakan Subversion di https://jasoet.googlecode.com/svn/tags/master-detail atau download file zipnya di sini.