Creating an Autocomplete Text Field in Java using SwingX
Again, my friend Iswi asked me a simple question, but a little bit hard to do. She asked me, how can she create an autocomplete jtextfield in java, maybe something like NetBean’s autocompletion feature. It took me a while to try several workarounds, before i found a very neat library, swingx. Let just say that this SwingX library helped me alot, and it have lots of other cool swing components. Really worth a try.
In this example, i try to create a simple application consist of 2 autocompletion components, 1 unrestricted jcombobox and 1 restricted jtextfield. Both components will connect to one table using Hibernate. Let’s give it a try.
First, a simple 2 column table.
CREATE DATABASE 'test' USE 'test' CREATE TABLE 'contoh' ( 'nama' varchar(30) NOT NULL, 'alamat' varchar(100) DEFAULT NULL, PRIMARY KEY ('nama') )
next step is creating a java bean and its hbm.xml for database mapping
package com.edw.bean; /** * Contoh generated by hbm2java */ public class Contoh implements java.io.Serializable { private String nama; private String alamat; public Contoh() { } public Contoh(String nama) { this.nama = nama; } public Contoh(String nama, String alamat) { this.nama = nama; this.alamat = alamat; } public String getNama() { return this.nama; } public void setNama(String nama) { this.nama = nama; } public String getAlamat() { return this.alamat; } public void setAlamat(String alamat) { this.alamat = alamat; } }
FYI, im using NetBeans’ Hibernate POJO and XML generator.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated Sep 1, 2010 10:10:38 AM by Hibernate Tools 3.2.1.GA --> <hibernate-mapping> <class catalog="test" name="com.edw.bean.Contoh" table="contoh"> <id name="nama" type="string"> <column length="30" name="nama"/> <generator class="assigned"/> </id> <property name="alamat" type="string"> <column length="100" name="alamat"/> </property> </class> </hibernate-mapping>
this is my hibernate.cfg.xml, for my default hibernate configuration
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property> <property name="hibernate.connection.username">admin</property> <property name="hibernate.connection.password">xxx</property> <mapping resource="com/edw/bean/Contoh.hbm.xml"/> </session-factory> </hibernate-configuration>
and my java class to load hibernate’s main xml configuration
package com.edw.hbm.util; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.SessionFactory; /** * Hibernate Utility class with a convenient method to get Session Factory object. * * @author edw */ public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { // Create the SessionFactory from standard (hibernate.cfg.xml) // config file. sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); } catch (Throwable ex) { // Log the exception. System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }
this is my main java class, you’ll see some imported SwingX’s classes.
package com.edw.swingx; import com.edw.bean.Contoh; import com.edw.hbm.util.HibernateUtil; import java.awt.Container; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JTextField; import org.apache.log4j.Logger; import org.hibernate.Session; import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator; import org.jdesktop.swingx.combobox.ListComboBoxModel; /** * * @author edw */ public class AutoCompletionTextField extends JFrame implements ActionListener { private JButton button = new JButton("tombol"); private JComboBox comboComplete = new JComboBox(); private JTextField textComplete = new JTextField(30); private Logger logger = Logger.getLogger(this.getClass()); private List<String> strings = new ArrayList<String>(); public void actionPerformed(ActionEvent e) { if(e.getSource() == button){ logger.debug(comboComplete.getSelectedItem().toString()); logger.debug(textComplete.getText().toString()); } } public AutoCompletionTextField() { try { Session session = HibernateUtil.getSessionFactory().openSession(); List<Contoh> contohs = (List<Contoh>)session.createCriteria(Contoh.class).list(); session.close(); for (Contoh contoh : contohs) { strings.add(contoh.getNama()); } Collections.sort(strings); // change true to false to enable string restriction comboComplete.setEditable(true); comboComplete.setModel(new ListComboBoxModel<String>(strings)); AutoCompleteDecorator.decorate(comboComplete); // change true to false to disable string restriction AutoCompleteDecorator.decorate(textComplete, strings, true); Container con = getContentPane(); con.setLayout(new FlowLayout()); con.add(comboComplete); con.add(textComplete); con.add(button); button.addActionListener(this); comboComplete.addActionListener(this); } catch (Exception ex) { logger.error(ex.getMessage(), ex); } } public static void main(String[] args) { AutoCompletionTextField autoCompletionTextField = new AutoCompletionTextField(); autoCompletionTextField.setVisible(true); autoCompletionTextField.pack(); autoCompletionTextField.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
this is my UI result,
this is NetBeans 6.9 project structure,
Again, thank you Iswi for your questions. Cheers, (B)