2 Replies - 15433 Views - Last Post: 27 March 2014 - 07:31 PM

#1 CasiOo   User is offline

  • D.I.C Lover
  • member icon

Reputation: 1578
  • View blog
  • Posts: 3,551
  • Joined: 05-April 11

Java 8 - Swing example

Posted 19 March 2014 - 09:48 AM

Java 8 got officially released yesterday, and I'm sure some of us are excited about it :)

This example program takes advantage of some of the new features found in Java 8
The Swing example shows how lambdas, method reference, and the stream API can be put together to make Swing more pleasant to work with
It also shows how to wrap an existing interface into a @FunctionalInterface when only one method is needed

Try out the application! :)
Apply a filter to the list of names
Add new names
Remove existing names found in the list

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.stream.Stream;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;


public class AppFrame extends JFrame {
	private ArrayList<String> namesList = new ArrayList<>();
	
	private JTextField filterField;
	private JList<String> dataList;
	private DefaultListModel<String> listDataModel;
	
	public AppFrame() {
		//Add a stream of names as initial data
		Stream.of("Jeremy Clarkson", "James May", "Richard Hammond").forEach(namesList::add);
		constructLayout();
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setSize(500, 500);
		setVisible(true);
	}
	
	private void constructLayout() {
		add(createNorth(), BorderLayout.NORTH);
		add(createCenter(), BorderLayout.CENTER);
		add(createSouth(), BorderLayout.SOUTH);
	}
	
	private JComponent createNorth() {
		filterField = new JTextField();
		//Update the list data when the filter changes
		//We can use lambdas because of our FunctionalDocumentListener wrapper
		filterField.getDocument().addDocumentListener((FunctionalDocumentListener) (e) -> updateListData());
		return filterField;
	}
	
	private JComponent createCenter() {
		listDataModel = new DefaultListModel<>();
		namesList.stream().forEach(listDataModel::addElement); //Add initial data to the list model
		dataList = new JList<>(listDataModel);
		dataList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		return dataList;
	}
	
	private JComponent createSouth() {
		JPanel container = new JPanel(new FlowLayout(FlowLayout.RIGHT));
		
		JButton addBtn = new JButton("Add");
		addBtn.addActionListener(this::onAddClicked); //Method reference
		container.add(addBtn);
		
		JButton removeBtn = new JButton("Remove");
		removeBtn.addActionListener(this::onRemoveClicked); //Method reference
		container.add(removeBtn);
		return container;
	}
	
	private void onAddClicked(ActionEvent e) {
		String name = JOptionPane.showInputDialog("Enter name of person");
		
		if (name != null) {
			namesList.add(name);
			updateListData();
		}
	}
	
	private void onRemoveClicked(ActionEvent e) {
		String selected = dataList.getSelectedValue();
		
		if (selected != null) {
			//Remove only if the instances are the same
			namesList.removeIf((name) -> name == selected);
			updateListData();
		}
	}
	
	private void updateListData() {
		listDataModel.clear();
		String filterText = filterField.getText().toLowerCase();
		
		//Filter away non matching names
		namesList.stream()
			.filter((name) -> filterText.isEmpty() || name.toLowerCase().contains(filterText))
			.forEach(listDataModel::addElement);;
	}
	
	/**
	 *	A wrapper around the DocumentListener interface
	 *	Allows lambdas and method reference to be used when the document changes
	 */
	@FunctionalInterface
	public interface FunctionalDocumentListener extends DocumentListener {
		default void changedUpdate(DocumentEvent e) { onDocumentChanged(e); }
		default void insertUpdate(DocumentEvent e) 	{ onDocumentChanged(e); }
		default void removeUpdate(DocumentEvent e) 	{ onDocumentChanged(e); }
		
		public void onDocumentChanged(DocumentEvent e);
	}
	
	public static void main(String[] args) {
		SwingUtilities.invokeLater(AppFrame::new); 
	}
}



Is This A Good Question/Topic? 4
  • +

Replies To: Java 8 - Swing example

#2 Dogstopper   User is offline

  • The Ninjaducky
  • member icon

Reputation: 2972
  • View blog
  • Posts: 11,223
  • Joined: 15-July 08

Re: Java 8 - Swing example

Posted 26 March 2014 - 07:29 AM

Wow. Java looks very different than I thought. When they said they were adding Lambdas, I had NO idea how much would change. But it looks sweet!
Was This Post Helpful? 0
  • +
  • -

#3 Flukeshot   User is offline

  • A little too OCD
  • member icon

Reputation: 417
  • View blog
  • Posts: 1,030
  • Joined: 14-November 12

Re: Java 8 - Swing example

Posted 27 March 2014 - 07:31 PM

I love the new syntax for listeners which have only one method (such as ActionListeners). I like the method::reference approach, but my favourite way to write an ActionListener by far is now with the lambda approach:
x.addActionListener((e)-> {
   doThis();
   doThat();
   ...
}


Especially in simple Swing Timers such as a repainter:
new Timer(20, (e) -> repaint(); );


This post has been edited by Flukeshot: 27 March 2014 - 07:34 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1