Validasi JTextField dengan DocumentFilter dan CaretListener


Fiuuuh,, baru saja selesai mengoprek bagaimana melakukan validasi masukan pada TextField dengan bahasa pemgrograman Java secara on the fly. Nantinya fungsi ini akan digunakan pada aplikasi perangkat lunak yang saat ini sedang saya bangun. Untuk mengimplementasi fungsi ini, saya menggunakan 2 buah kelas bawaannya javax.swing yaitu DocumentFilter dan CaretListener. Ini hanya salah satu solusi saja. Mungkin ada cara lain yang lebih mangkus.

Pada bahasa Java, terdapat kelas JTextField (salah satu komponen visual bagian dari Swing) yang jika diinstansiasi akan menampilkan bentuk visual dari textfield. JTextField hanya dapat menerima masukan dari user dalam tipe data String, yang berarti sebenarnya dapat menerima data dalam bentuk apapun baik itu numerik maupun karakter (karena String tidak memperdulikan hal tersebut). Untuk mendapatkan tipe data yang kita inginkan, perlu pengolahan data selanjutnya yang berupa konversi dari tipe String ke tipe data tertentu. Kali ini, saya menginginkan sebuah JTextField yang hanya dapat menerima bilangan Integer antara 0 … 255. Gimana caranya kita tahu bahwa masukan berupa Integer padahal JTextField hanya menerima berupa tipe String?

Pertama-tama, yang dibutuhkan adalah sebuah kelas yang meng-extend kelas DocumentFilter. DocumentFilter berperan sebagai listener yang dapat menangkap beberapa event yang dilakukan terhadap JTextField. Pada kasus ini, event-event yang ditangkap adalah penambahan karakter  dan penghapusan karakter pada TextField. Jika terjadi entri karakter pada JTextField oleh seorang user melalui keyboard, maka fungsi yang di-trigger adalah fungsi replace(). Sedangkan, jika terjadi penghapusan karakter atau user menekan tombol delete/backspace pada textfield yang masih berisi teks, maka fungsi yang di-trigger adalah remove(). Di dalam fungsi replace() inilah nantinya kita akan cek apakah masukan dari user valid atau tidak. Ketika masukan valid, maka fungsi replace harus dijalankan dengan cara memanggil method replace(offset, length, text, attr) yang dimiliki oleh kelas FilterBypass. Jika berjalan dengan baik, fungsi tersebut akan secara otomatis mengubah isi teks yang ada pada textfield. Sedangkan pada fungsi remove(), akan dipanggil remove(offset, length) yang juga kepunyaan dari kelas FilterBypass untuk memastikan teks benar-benar hilang pada textfield.

Memasukkan teks maupun menghapus teks pada TextField semuanya sudah ditangani oleh DocumentFilter. Namun ada 1 hal yang belum ditangani yaitu mengenali teks/substring yang sedang di-block/select (dengan cara mouse drag & drop) oleh user yang nantinya akan di-replace/update. Hal tersebut memerlukan sebuah kelas interface tambahan bernama CaretListener yang harus di-implements. Tanpa kelas ini, teks/substring pada TextField tidak akan bisa di-replace dengan masukkan dari keyboard.

Untuk memudahkan pengelolaan, saya menggabungkan 2 buah kelas di atas dengan membuat sebuah kelas baru bernama ToleranceFilter. Kelas tersebut meng-extend kelas DocumentFilter dan meng-implements kelas CaretListener. Berikut source code dari kelas ToleranceFilter:

package components.imagehandlers;

import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

/**
*
* @author Muhammad Ghifary
*/
public class ToleranceFilter extends DocumentFilter implements CaretListener{
/**
* ATTRIBUTES
*/
private String valueStr;
private String prevValueStr;
private int dot;
private int mark;

/**
* METHODS
*/
//Constructor
public ToleranceFilter(){
valueStr = "";
prevValueStr = "";
dot = 0;
mark = 0;
}

//Setter
public void setValueStr(String str){
this.valueStr = str;
}

//Getter
public String getValueStr(){
return this.valueStr;
}

@Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length,
String text, AttributeSet attr) throws BadLocationException {

if(offset >= valueStr.length()){//insert last
valueStr = valueStr.concat(text);
}else{
if(dot != mark){//replace selected substring between {dot, mark} or {mark, dot}
StringBuffer strBuf = new StringBuffer(valueStr);
if(dot < mark) strBuf.replace(dot,mark,text);
else strBuf.replace(mark,dot,text);
valueStr = strBuf.toString();

}
else{//insert first or insert middle
if(offset == 0) valueStr = text.concat(valueStr);
else valueStr = valueStr.substring(0,offset) + text + valueStr.substring(offset,valueStr.length());
}
}
boolean isValid = false;
try{
int value = Integer.parseInt(text);
if(valueStr.length() <=3 ){
if(valueStr.length() == 1){
isValid = true;
}
if((valueStr.length() == 2)){
isValid = true;
}
if((valueStr.length() == 3)){
int val0 = Integer.parseInt(Character.toString(valueStr.charAt(0)));
int val1 = Integer.parseInt(Character.toString(valueStr.charAt(1)));
if((val0 < 2) ||
((val0 == 2) && (val1 < 5)) ||
((val0 == 2) && (val1==5) && (value<=5))
){
isValid = true;
}
}
}
}
catch(NumberFormatException ex){

}
if(isValid){
//update text in the TextField
fb.replace(offset, length, text, attr);
}else{
valueStr = prevValueStr;
}
prevValueStr = valueStr;

}
@Override
public void remove(DocumentFilter.FilterBypass fb, int offset, int length)
throws BadLocationException {
if(valueStr.length()>0) valueStr = valueStr.substring(0,valueStr.length()-1);
else valueStr = "";
fb.remove(offset, length);
}

public void caretUpdate(CaretEvent e) {
//get location in the text
dot = e.getDot();
mark = e.getMark();
}
}

Agar kelas ToleranceFilter dapat dimanfaatkan pada JTextField tertentu hanya perlu 3 baris kode. Perhatikan contoh di bawah ini:


.....

//asumsi: telah ada objek JTextField bernama textField

ToleranceFilter tf = new ToleranceFilter();

((AbstractDocument)toleranceTF.getDocument()).setDocumentFilter(tf);

textField.addCaretListener(tf);
.....

Sekali lagi ini hanyalah salah satu solusi yang telah berhasil saya oprek😀

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s