Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Swing's Little Helper

4.79/5 (5 votes)
2 Oct 2013CPOL7 min read 15.8K  
Description and usage with examples of a helper lib to create Swing applications

Introduction

Swing is the primary Java GUI widget toolkit. It is easy to use but there are things that can be improved , for example assumptions of common defaults or settings, also the use of certain types of collections when binding properties to objects.

I've find some of these improvement areas and created a solution called SwingHelper as a library. The goal of this library is to set commons defaults when using Swing components in order to re-use code and make faster and standard method invocations.

This article is created with the goals of learn basics about Swing and the usage of the SwingHelper open-source library.

Background

As written on the introduction, Swing is the primary Java GUI, but it is not the only one available for Java to create desktop applications, we can find AWT, SWT, SwingX, JavaFX, Apache Pivot, and many others.

AWT was the first Java GUI, and Swing is its successor. Swing was created to provide rich components completely written on Java, which means that they are not implemented by platform-specific code, it is also known as “lightweight” elements, the ability of Swing to render their own components by painting them using Java2D APIs and not depending of native user interface toolkits.

The reason why I choose Swing to work on my projects is because it is completely written on Java and it is included on the JVM so no extra libs are needed, and the main reason for me is that I can create OS independent applications using the Look and Feel that I want, that can be one of the Java's default that looks the same on all platforms, or my favorite, using the same as current OS, all in one pure jar that is executable in any platform, literally “write once, run anywhere”.

Using the code

What is SwingHelper?

It is an open-source library written on Java, it is a set of common invocations to components that reduce the complexity assuming default values. Also it implements some AbstractModel to bind data with components just in seconds.

Downloading the library

SwingHelper is open-source, it means you can download it for free and add it to your project. If you want to improve something you can download the source code and check how it works.

Source code are hosted at:
https://code.google.com/p/sidereal-libraries/

Since Google Code recently changed
their download policy, the binary releases can be found at:
https://drive.google.com/folderview?id=0B_QgKAk4BATMaTUxNWNpVlNvcVU&usp=sharing

The current version is 1.1

 

The SwingHelper class and methods

Basically what you can do with this
class is:

-Set the Look and Feel of the whole application. Note: The System Look and Feel is set as default instead
of the Metal one. 

Examples:

Java
SwingHelper.setLookAndFeel(SwingHelper.LookAndFeel.NIMBUS);
//or
SwingHelper.setLookAndFeel(SwingHelper.LookAndFeel.MOTIF);
//or
SwingHelper.setLookAndFeel(SwingHelper.LookAndFeel.METAL);
//or
SwingHelper.setLookAndFeel(SwingHelper.LookAndFeel.SYSTEM);  

-Change the themes for Metal Look and Feel

Examples:

Java
SwingHelper.setMetalTheme(SwingHelper.MetalTheme.DEFAULT_METAL);
//or
SwingHelper.setMetalTheme(SwingHelper.MetalTheme.OCEAN);  


-Center a window

Example:

Java
SwingHelper.centerWindow(customerJDialog);  


-Display an error messages

Example:

Java
SwingHelper.showErrorMessage("Error title", "This is an error message.");  


-Display a warning messages

Example:

Java
SwingHelper.showWarningMessage("Warning title", "This is a warning message."); 


-Display an information messages

Example:

Java
SwingHelper.showInformationMessage("Information title", "This is an information message.");  


-Display an Input Dialog asking for a non-empty value

Example: 

Java
String result =
SwingHelper.askForRequiredTextUsingInputDialog("Text request", "Write your name:");  


-Display a Confirmation Dialog with Yes/No or Yes/No/Cancel or OK/Cancel buttons

Examples:

Java
String title = "Click on a button to confirm";
String message = "Click on YES button";
String result =
SwingHelper.showConfirmationDialogWithYesNoButtons(title, message);
if(result.equals("yes")){
    //write your logic
}  


-Display a File Chooser asking for a folder

Example:

Java
String title = "Choose a folder"
String startDirectory = "target/test-classes/com/diegohp/swing/";
File result = SwingHelper.chooseDirectory(title, startDirectory);
//do the logic using 'result' as your folder  


-Display a File Chooser asking for a file

Example: 

Java
String title = "Choose any file";
File result = SwingHelper.chooseFile(title);  


-Display a File Chooser asking for a file with certain extension

Java
String title = "Choose a text file";
String fileExtension = ".txt";
File result = SwingHelper.chooseFile(title, fileExtension);
//do your logic with 'result' as your text file  

All of these features have several parameters combinations (some of them didn't appear in the above examples), so you can choose the one that you need for each situation.

The most common parameters are: title (of the window), startDirectory (the folder that a file chooser opens as default), fileExtension (the extension of the file to be selected), startFile (the file that a file chooser selects as default), lookAndFeel (one of the options of an enum of the same name with all the needed information), metalTheme (one of the options of an enum of the same name with all the needed information), message (the message displayed on message window).

 

The ListComboBoxModel class

What you can do with this class is:

-Have a class that extends from AbstractListModel and implements MutableComboBoxModel. All methods are implemented, objects of this class are ready to use out of the box

- AbstractListModel gives to the class the ability to use a List as a container of data (in this case, an ArrayList with parametrized type)

- MutableComboBoxModel gives to the class the ability to change its data even after the UI component was displayed

 

Example:

We are going to create a window that asks to the user the selection of a language.

Let's declare a JDialog with a Combo Box and a button:  

Java
public class LanguageSelectorJDialog extends javax.swing.JDialog{
    private javax.swing.JComboBox jComboBoxLanguages;
    private javax.swing.JButton jButtonSelect;
}  

Now use ListComboBoxModel to create the model of the Combo Box: 

Java
private ListComboBoxModel<String> languagesListComboBoxModel;  

Note: in this case the parametrized type of the container was set to <String>, but it can be anything you want, Integer, Long, even your custom classes for example pojos that overrides the toString() method (what the component reads to put in the UI) to return something useful to the user. 

Next, in the constructor of the JDialog we are going to populate the model data:  

Java
this.languagesListComboBoxModel.addElement("English");
this.languagesListComboBoxModel.addElement("Español");  

Now we are going to implemented the logic of the click on the select button:

Java
private void jButtonSelectActionPerformed(java.awt.event.ActionEvent evt) {	
 
//note how easy is to get the selected object of the combo
String selected = (String) this.languagesListComboBoxModel.getSelectedItem();
	
	//then implement your logic
	if (selected.equals("English")){
		Locale.setDefault(Locale.ENGLISH);
		System.out.println("Language set to English");
		} else {
		Locale.setDefault(new
		Locale("es"));
		System.out.println("Language set to Spanish");
	}
	
	//at the end the JDialog is closed
	this.dispose();
}   


This is a pretty easy example of a usage of the ListComboBoxModel class, but remember the ability of the parametrized type. In a more complex example we need to use instead of a <String> a custom class called Language that has a name (English, Spanish) and a number of language (345, 874) and the list of languages are not limited to only 2, they can be more based on records of a data base. Fist you need to override the toString() method of the Language class to return for example just the name (since the user is not going to understand the number of language), then you just need to add all the list of languages to the model and when the user selects a language and click on select button, the model return you the whole object selected. With this feature you avoid to create an auxiliary list as an index of the objects that fits the old model limitations and start a search based on the value selected on the real objects list, saving you time, memory, processor time and unneeded code. 

What you can see with this is something like this:
 Image 1

The ListTableModel class  

As the ListComboBoxModel, this class shares the same objetives: 

-Have a class that extends from AbstractTableModel, it implements all the methods as much as it can, leaving just one method to be implemented, getValueAt(int row, int col), which is very easy, you just need to return the value of the corresponding column. When trying to implement an AbstractTableModel you get just a 40% of the class, using ListTableModel you get a 99% of the implementation with a flexible and mutable logic.  

-It has a List of Strings as variable to populate with the columns names, so you can change them even after the component was displayed 

- Implemented the usage of a List as a container of data (in this case, an ArrayList with parametrized type), very useful when displaying and editing information in a table 

 

Example:

For this scenario we are going to create a window with a table of costumers, when a costumer is clicked, a message is displayed with information and a count of views is incremented in the table. 

First, let's create an entity class of Customer: 

Java
public class Customer {
    private Long id;
    private String name;
    private Integer views;
    //all the setters an getter
} 

Now, let's create a JDialog with a table, a model and an object of Customer to keep the selected customer: 

Java
public class CustomerTableModelJDialog extends javax.swing.JDialog {
    private javax.swing.JTable jTableCustomers;
    private ListTableModel<Customer> customersListTableModel;
    private Customer customerSelected;
}   

Once declared the model, we need to create its instance by implementing the remaining method. In this case our first column will display the Id of the customers, the seconds displays the name and the third displays the numbers of views, so based on that we implement the method to return the respective value of the object: 

Java
this.customersListTableModel = new ListTableModel<Customer>() {
            @Override
            public Object getValueAt(int row, int col) {
                Customer customer = this.objects.get(row);
                if (col == 0) {
                    return customer.getId();
                }
                if (col == 1) {
                    return customer.getName();
                }
                if (col == 2) {
                    return customer.getViews();
                }
                return customer.getId() + " -> " + customer.getName();
            }
        };  

Now we need to declare the names of the headers of the table, following our order we set it on this way: 

Java
List<String> columnsNames = new ArrayList<String>();
columnsNames.add("Id");
columnsNames.add("Name");
columnsNames.add("Views");
this.customersListTableModel.setColumnNames(columnsNames);  

The next step is to create a listener to capture the value changed moment and implement some specific logic when a customer is selected: 

Java
this.jTableCustomers.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
  @Override
  public void valueChanged(ListSelectionEvent lse) {
               
    if(!lse.getValueIsAdjusting()){
      ListSelectionModel model = jTableCustomers.getSelectionModel();
      if(model.getLeadSelectionIndex() >= 0){
        customerSelected = ((ListTableModel<Customer>)jTableCustomers.getModel()).getObjectAt(model.getLeadSelectionIndex());
	//now we got the customer, let's implement our logic
        customerSelected.setViews(customerSelected.getViews() + 1);
	//now call  fireTableDataChanged so the table updates the data displayed
        customersListTableModel.fireTableDataChanged();
        //now display some information of the customer
                       
        SwingHelper.showInformationMessage("Clicked on a Customer",
        "Customer's Id is " + customerSelected.getId() + " and
        name is " + customerSelected.getName());
        }
       }
      }
    });

Once the model is ready, let's set it to the table: 

Java
this.jTableCustomers.setModel(this.customersListTableModel);  

In order to populate the table, we need to create some customer, add them to the table and update the changes:

Java
List<Customer> customers = new
ArrayList<Customer>();
Customer c1 = new Customer();
c1.setId(123456789L);
c1.setName("Harry Mason");
c1.setViews(0);
 
Customer c2 = new Customer();
c2.setId(987654321L);
c2.setName("James Sunderland");
c2.setViews(0);
customers.add(c1);
customers.add(c2);
       
this.customersListTableModel.addObjectList(customers);
this.customersListTableModel.fireTableDataChanged();  

And that's it. You will see something like this: 

Image 2

If you want to check all the code of these examples, download the source code and check out the test classes, they contain all the examples. The project was created with Maven so it should be easy to run the test when building the code.  

Points of Interest

-I was a teacher of Java and I used Swing to teach how to create desktop applications. Swing is easy to learn for my students and very useful. I've been creating desktop apps since then for personal and professional projects. Before that I had used other solutions for this, but after trying Swing I found it very interesting and easier in some way, and also the ability to create one executable that can run using the system interface in Windows, Mac and Linux at the same time with a single double click, was priceless. 

-Swing doesn't need of native libraries and doesn't need to be re-compilated for each OS, it makes it very portable, light and easy to distribute. Give it a try using Netbeans and test the visual designer, I bet you are going to found it intuitive. 

-SwingHelper is a library with code that I noticed I started to use frequently, so I put it on the same class and tried to optimized it. My goal with this library is to add more functionality that I will collect and publish in future releases. 

History

Oct 2 2013, Created the article using the SwingHelper 1.1 release 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)