XSwingTable uses javax.swing.JTable to display and edit regular two-dimensional tables of cells. This makes it easy to use your existing javax.swing.table.TableModel implementations within a JavaFX GUI. We also provide table model implementations for JavaFX sequences; these table models provide binding support to enable you to keep your model data in sync with the table.
Sample Code
Example 1: string sequence.
import org.jfxtras.ext.swing.XSwingTable;
import org.jfxtras.ext.swing.table.StringSequenceTableModel;
import javafx.ext.swing.SwingScrollPane;
var names = ["Joe", "Fred", "Jane"];
SwingScrollPane {
view: XSwingTable {
tableModel: StringSequenceTableModel {
sequence: bind names with inverse
columnLabel: "Names"
editable: true
}
}
}
Example 2: object sequence.
import org.jfxtras.ext.swing.XSwingTable;
import org.jfxtras.ext.swing.table.IntegerCell;
import org.jfxtras.ext.swing.table.Row;
import org.jfxtras.ext.swing.table.ObjectSequenceTableModel;
import org.jfxtras.ext.swing.table.StringCell;
import javafx.ext.swing.SwingScrollPane;
class Person {
var forename:String;
var surname:String;
var age:Integer;
}
var employees = [
Person {
forename: "Joe"
surname: "Bloggs"
age: 45
}
Person {
forename: "Fred"
surname: "Bloggs"
age: 60
}
];
SwingScrollPane {
view: XSwingTable {
tableModel: ObjectSequenceTableModel {
override function transformEntry(entry) {
def person:Person = entry as Person;
return Row {
cells: [
StringCell { value: bind person.forename }
StringCell {
value: bind person.surname with inverse
editable: true
}
IntegerCell { value: bind person.age }
]
}
}
columnLabels: ["Forename", "Surname", "Age"]
sequence: bind employees
}
}
}
Example 3: table with form.
import org.jfxtras.ext.swing.XSwingTable;
import org.jfxtras.ext.swing.table.ListSelectionMode;
import org.jfxtras.ext.swing.table.ObjectSequenceTableModel;
import org.jfxtras.ext.swing.table.Row;
import org.jfxtras.ext.swing.table.StringCell;
import org.jfxtras.ext.swing.table.TableResizeMode;
import org.jfxtras.ext.swing.table.TableSelectionMode;
import org.jfxtras.scene.layout.MigNodeLayoutInfo;
import org.jfxtras.scene.layout.MigLayout;
import org.jfxtras.scene.XScene;
import javafx.ext.swing.SwingButton;
import javafx.ext.swing.SwingLabel;
import javafx.ext.swing.SwingScrollPane;
import javafx.ext.swing.SwingTextField;
import javafx.stage.Stage;
class Person {
var forename:String;
var surname:String;
function copyTo(to:Person) {
to.forename = forename;
to.surname = surname;
}
}
var people = [
Person {
forename: "Joe"
surname: "Bloggs"
}
Person {
forename: "Jane"
surname: "Doe"
}
Person {
forename: "Fred"
surname: "Bloggs"
}
];
var selectedPerson:Person = null on replace {
if (selectedPerson == null) {
Person{}.copyTo(detailPerson);
} else {
selectedPerson.copyTo(detailPerson);
}
}
// unfortunatly we can't use selectedPerson directly because
// you can't bind with inverse to the property of a var
def detailPerson = Person {}
var editPanel:MigLayout;
var swingTable:XSwingTable;
Stage {
width: 350
height: 300
title: ##[app_title]"XSwingTable Demo"
scene: XScene {
content: MigLayout {
constraints: "wrap 1"
rows: "[]unrel[]"
content: [
SwingScrollPane {
view: swingTable = XSwingTable {
autoResizeMode: TableResizeMode.AUTO_RESIZE_OFF
tableModel: ObjectSequenceTableModel {
override function transformEntry(entry) {
def person:Person = entry as Person;
return Row {
cells: [
StringCell { value: bind person.forename }
StringCell { value: bind person.surname }
]
}
}
columnLabels: [##[forename_label]"Forename", ##[surname_label]"Surname"]
sequence: bind people
}
tableSelectionMode: TableSelectionMode.ROW;
rowSelectionMode: ListSelectionMode.SINGLE_SELECTION;
onSelectedRowChanged: function(selectedRowIndex) {
selectedPerson = if (selectedRowIndex == null)
then null
else people[selectedRowIndex];
}
}
}
editPanel = MigLayout {
constraints: "insets 0, wrap 2"
rows: "[]unrel[]"
content: [
SwingLabel {
text: ##[forename_label]"Forename"
}
SwingTextField {
text: bind detailPerson.forename with inverse
columns: 12
}
SwingLabel {
text: ##[surname_label]"Surname"
}
SwingTextField {
text: bind detailPerson.surname with inverse
columns: 12
}
SwingButton {
layoutInfo: MigNodeLayoutInfo {
constraints: "spanx 2, split 3"
}
disable: bind selectedPerson == null
text: ##[update_button]"Update"
action: function () {
detailPerson.copyTo(selectedPerson);
}
}
SwingButton {
text: ##[add_button]"Add"
action: function () {
def newPerson = Person {}
detailPerson.copyTo(newPerson);
insert newPerson into people;
// select new row
var newSelectionIndex = sizeof people - 1;
var jTable = swingTable.getJTable();
var selectionModel = jTable.getSelectionModel();
selectionModel.setSelectionInterval(newSelectionIndex, newSelectionIndex);
// scroll to new row
jTable.scrollRectToVisible(jTable.getCellRect(newSelectionIndex, 0, true));
}
}
SwingButton {
text: ##[delete_button]"Delete"
disable: bind selectedPerson == null
action: function () {
delete selectedPerson from people;
}
}
]
}
]
}
}
}