Utils for working with Java Swing components via Java 8 streams.
Functionality of the library is provided by the static methods of class SwingStreamUtils
.
The methods may be divided into two categories: those which allow to iterate (or stream) over data items of Swing components
(e.g. SwingStreamUtils.stream
) and collectors which allow to create Swing components from a stream data (e.g. SwingStreamUtils.toTable
).
Example 1 (for JTable
, count how many times value "London"
appears in the selected cells of column "City"
):
import javax.swing.JTable;
import io.github.parubok.stream.SwingStreamUtils;
import io.github.parubok.stream.TableCellData;
JTable table = ...;
long count = SwingStreamUtils.stream(table)
.filter(TableCellData::isSelected)
.filter(cellData -> cellData.getColumnName().equals("City"))
.map(TableCellData::getValue)
.filter("London"::equals)
.count();
// or with for-each loop:
count = 0;
for (TableCellData<JTable> cellData: SwingStreamUtils.asIterable(table)) {
if (cellData.isSelected() && cellData.getColumnName().equals("City") && "London".equals(cellData.getValue())) {
count++;
}
}
Example 2 (create table with 'Name' and 'Size' columns from a list of File
objects):
import java.io.File;
import java.util.List;
import io.github.parubok.stream.ColumnDef;
import static io.github.parubok.stream.SwingStreamUtils.toTable;
List<File> files = ...;
/* FileTable is a subclass of JTable */
FileTable table = files.stream()
.collect(toTable(FileTable::new, new ColumnDef<>("Name", File::getName, 100, String.class),
new ColumnDef<>("Size", File::length, 70, Long.class)));
Example 3 (create a table with specific model class):
import java.io.File;
import java.util.List;
import io.github.parubok.stream.ColumnDef;
import static io.github.parubok.stream.SwingStreamUtils.toTable;
List<File> files = ...;
FileTable table = files.stream()
.collect(toTable(() -> new FileTable(), rowCount -> new FileTableModel(rowCount),
new ColumnDef<>("Name", File::getName, 100, String.class),
new ColumnDef<>("Size", File::length, 70, Long.class)));
For a table with fixed (i.e. predefined) columns, Java enum
provides a convenient way to define and access the column
definitions - for example, when a column index is required after the table was created.
Example:
import java.io.File;
import java.util.function.Supplier;
import io.github.parubok.stream.ColumnDef;
import static io.github.parubok.stream.SwingStreamUtils.toTable;
enum Column implements Supplier<ColumnDef<File>> {
NAME(new ColumnDef<>("Name", File::getName, 100, String.class)),
SIZE(new ColumnDef<>("Size", File::length, 70, Long.class));
final ColumnDef<File> def;
Column(ColumnDef<File> def) {
this.def = def;
}
@Override
public ColumnDef<File> get() {
return def;
}
}
List<File> files = ...;
// use enum values() method to get all column definitions:
JTable table = files.stream()
.collect(toTable(ColumnDef.get(Column.values())));
// use enum ordinal() method to obtain column index:
String name = (String) table.getValueAt(0, FileTableColumn.NAME.ordinal());
// translate column index to ColumnDef:
int columnIndex = ...;
ColumnDef<File> def = FileTableColumn.values()[columnIndex].get();
Example 4 (create combo box with file names from a list of File
objects):
import java.io.File;
import java.util.List;
import javax.swing.JComboBox;
import static io.github.parubok.stream.SwingStreamUtils.toComboBox;
List<File> files = ...;
JComboBox<String> = files.stream()
.map(File::getName)
.collect(toComboBox());
Example 5 (find all visible descendants of a container):
import java.util.List;
import java.util.stream.Collectors;
import java.awt.Component;
import java.awt.Container;
import static io.github.parubok.stream.SwingStreamUtils.streamDescendants;
Container container = ...;
List<Component> visibleDescendants = streamDescendants(container)
.skip(1) // skip the container itself
.filter(Component::isVisible)
.collect(Collectors.toList());
Example 6 (find all unselected combo box items which start with a letter "z"):
import io.github.parubok.stream.SwingStreamUtils;
JComboBox<String> comboBox = ...;
List<String> visibleDescendants = SwingStreamUtils.stream(comboBox)
.filter(comboBoxItem -> !comboBoxItem.isSelected())
.filter(comboBoxItem -> comboBoxItem.getItem().startsWith("z"))
.collect(Collectors.toList());
Example 7 (search for the first tree path with the specified node):
import java.util.Optional;
import javax.swing.JTree;
import javax.swing.tree.TreeNode;
import io.github.parubok.stream.KTreePath;
import io.github.parubok.stream.SwingStreamUtils;
import io.github.parubok.stream.TreeTraversalType;
JTree tree = ...;
TreeNode node = ...;
Optional<KTreePath> nodePath = SwingStreamUtils.stream(tree, TreeTraversalType.PRE_ORDER)
.filter(path -> path.isLastComponent(node))
.findFirst();
It is worth mentioning that in most cases (check JavaDoc) the utility ensures that the Swing component creation and configuration are performed on EDT, even when the streaming code runs on a different thread. So the following example code is valid:
import java.util.List;
...
import io.github.parubok.stream.ColumnDef;
import static io.github.parubok.stream.SwingStreamUtils.toTable;
// may be not EDT (for example, Swing worker background thread)
List<Server> servers = ...;
JTable table = servers.parallelStream() // OK to use parallel stream!
.collect(toTable(new ColumnDef<>("Name", Server::getName, 100, String.class),
new ColumnDef<>("Users", Server::getUserCount, 50, Integer.class),
new ColumnDef<>("Status", Server::getStatus, 200, String.class));
SimpleTableModel
(extends javax.swing.table.DefaultTableModel
) may be build from a stream as following:
import java.util.List;
...
import io.github.parubok.stream.ColumnDef;
import static io.github.parubok.stream.SwingStreamUtils.toTableModel;
// may be executed on any thread
List<User> users = ...;
SimpleTableModel<User> tableModel = users.parallelStream()
.collect(toTableModel(new ColumnDef<>("Name", User::getName, 100, String.class),
new ColumnDef<>("ID", User::getID, 50, Long.class),
new ColumnDef<>("Role", User::getRole, 200, String.class));
This project has no external dependencies (except JUnit 5, for testing).
Requires Java 8 or later.
This project is licensed under Apache License, version 2.0
Releases are available in Maven Central
Add this snippet to the pom.xml dependencies
section:
<dependency>
<groupId>io.github.parubok</groupId>
<artifactId>swing-stream-utils</artifactId>
<version>1.37</version>
</dependency>