Java swing jtable setvalueAt doesn't work - swing

i searched in differet questions from others. But i didn't succeed.
I want to make my table editable. But i dont know how, to call "setValueAt()".
I have the following files:
MovieManager.java
import java.util.*;
public class MovieManager
{
private static List<Movie> movieList = new ArrayList<Movie>();
public static void main(String args[])
{
final Director david = new Director("David", "Finch", Gender.MALE);
final Movie film1 = new Movie("Fightclub", 140, "Amerika", "Best Movie ever!", david);
final Movie film2 = new Movie("Panic Room", 115, "Amerika", "Good Movie", david);
final Movie film3 = new Movie("Seven", 120, "Amerika", "Headless", david);
movieList.add(film1);
movieList.add(film2);
movieList.add(film3);
// start GUI
new MovieUI();
}
public static List<Movie> getMovieList()
{
return movieList;
}
public static void setMovieList(List<Movie> movieList)
{
MovieManager.movieList = movieList;
}
}
MovieUI.java
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MovieUI extends JPanel
{
/**
*
*/
private static final long serialVersionUID = 1L;
public MovieUI()
{
//Create and set up the window.
final JFrame frame = new JFrame("Movie Manager");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
final Table newContentPane = new Table();
//newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
}
Table.java
import javax.swing.JPanel;
import javax.swing.JTable;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableRowSorter;
public class Table extends JPanel
{
/**
*
*/
private static final long serialVersionUID = 1L;
public Table()
{
super(new GridLayout(1,0));
final MovieTableModel model = new MovieTableModel();
final JTable table = new JTable(model);
final TableRowSorter<MovieTableModel> sorter = new TableRowSorter<MovieTableModel>();
table.setRowSorter(sorter);
sorter.setModel(model);
final JTableHeader header = table.getTableHeader();
setLayout(new BorderLayout());
add(header, BorderLayout.PAGE_START);
add(table, BorderLayout.CENTER);
}
}
and
MovieTableModel.java
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
class MovieTableModel extends AbstractTableModel
{
/**
*
*/
private static final long serialVersionUID = 1L;
private final List<String[]> daten = new ArrayList<String[]>();
private final List<Movie> datenMov = new ArrayList<Movie>();
private final String[] columnNames = {"Id", "Name", "Time", "Language", "Description", "Place"};
public MovieTableModel()
{
for (Movie movie: MovieManager.getMovieList())
{
String[] list = {String.valueOf(movie.getNumber()), movie.getTitle(), String.valueOf(movie.getTime()), "DE", movie.getDescription(), movie.getPlace()};
datenMov.add(movie);
daten.add(list);
}
}
public int getColumnCount()
{
return columnNames.length;
}
public int getRowCount()
{
return daten.size();
}
public String getColumnName(int col)
{
return columnNames[col];
}
public Object getValueAt(int row, int col)
{
return daten.get(row)[col];
}
public boolean isCellEditable(int row, int col)
{
if (col < 1)
{
return false;
}
else
{
return true;
}
}
public void setValueAt(String value, int row, int col)
{
System.out.println("Ich werde aufgerufen");
String[] list = daten.get(row);
list[col] = value;
daten.set(row, list);
System.out.println(daten.get(row)[col]);
List<Movie> movieliste = MovieManager.getMovieList();
Movie mov = (Movie) movieliste.get(row);
switch( col )
{
case 1:
mov.setTitle(value);
break;
case 2:
int foo = Integer.parseInt(value);
mov.setTime(foo);
break;
case 4:
mov.setDescription(value);
break;
case 5:
mov.setPlace(value);
break;
}
movieliste.set(row, mov);
MovieManager.setMovieList(movieliste);
}
}

You TableModel is too complex. All you need to do is store a List of Movies. Then you getValueAt() and setValueAt() method should access the List.
Your constructor should simply be:
public MovieTableModel(List movies)
{
datenMov = movies;
}
The getValueAt() should be something like:
public Object getValueAt(int row, int column)
{
Movie movie = datenMov.get(row);
switch(column)
{
case 0: return movie.getNumber();
case 1: return movie.getTitle();
...
default: return null;
}
}
and the setValueAt() method something like:
#Override
public void setValueAt(Object value, int row, int column)
{
Movie movie = get(row);
switch (column)
{
case 0: movie.setNumber((String)value); break;
case 1: movie.setTitle((String)value); break;
...
}
}
Edit:
Also, in the setValueAt() method you need to invoke:
fireTableCellUpdated(row, column);

I encountered similar situation, and I finally solved it.
I found that, when we double click on a cell, it go to:
JTable.getDefaultEditor(Class<?> columnClass) function.
In my case, it go to the line :
return getDefaultEditor(columnClass.getSuperclass());
Since I returned int.class when overriding the getColumnClass() in my Table Model, so it returned null for the editor.
In short, the solution is,
Don't return any Primitive Data Types when overriding getColumnClass() in your table model !

Related

Jtable show and hide column and save the configuration.

I'm using JXTable which has a setColumnControlVisible(true) which shows a button on the upper right corner above scroll, we can show and hide column by pressing it. I want to remember the changes when the app get close, but cannot figure it out yet, Here what I have tried so far. I check the src of JxTable, but didn't how to get the column index or column number which is hidden.
package paractice;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.table.AbstractTableModel;
import org.jdesktop.swingx.JXTable;
public class TableTest extends JFrame{
private static final long serialVersionUID = 1L;
private JXTable table;
public TableTest() {
setLayout(new BorderLayout());
table = new JXTable(new model());
//add(table.getTableHeader(), BorderLayout.NORTH);
add(new JScrollPane(table), BorderLayout.CENTER);
table.setColumnControlVisible(true);
setSize(700, 700);
}
public class model extends AbstractTableModel{
String[] columns = {"column1", "column2", "column3", "column4", "column5"};
#Override
public String getColumnName(int column) {
return columns[column];
}
#Override
public boolean isCellEditable(int arg0, int arg1) {
return super.isCellEditable(arg0, arg1);
}
#Override
public void setValueAt(Object arg0, int row, int col) {
super.setValueAt(arg0, row, col);
fireTableCellUpdated(row, col);
}
public int getColumnCount() {
return columns.length;
}
public int getRowCount() {
return 0;
}
public Object getValueAt(int arg0, int arg1) {
return null;
}
}
public static void main(String args[]) {
TableTest test = new TableTest();
test.setVisible(true);
}
}
but didn't how to get the column index or column number which is hidden.
Compare the TableModel with the JTableHeader.
Just create a simple loop to check all the columns name of the TableModel to see if the table contains that column. Something like:
for (int i = 0; i < model.getColumnCount(); i++)
{
Object name = model.getColumnName();
TableColumn column = table.getColumn( name );
if (column == null)
// column is hidden do your processing
}
Then the next time you display the table you can get the names of all hidden columns and then use:
table.removeColumn( table.getColumn( name ) );

Convert a Swing Progress bar to JavaFx progressBar

I have my Swing progress bar class as below:
public class MyProgessBar extends JDialog implements Runnable {
/**
* #param string
*/
private JProgressBar progressBar;
private boolean cancelled=false;
public static void main(String[] args) throws InterruptedException{
MyProgessBar p = new MyProgessBar("Test");
new Thread(p).start();
for(int i=0;i<500;i++){
p.setMsg("Its "+i+"%");
p.setDone(i);
Thread.sleep(200);
}
p.dispose();
}
public MyProgessBar(String title) {
setTitle(title);
progressBar = new JProgressBar();
progressBar.setValue(0);
progressBar.setStringPainted(true);
progressBar.setIndeterminate(true);
add(progressBar);
setSize(400, 50);
setLocationRelativeTo(null);
setModal(true);
SwingUtilities.invokeLater(this);
}
/**
* #param string
*/
public void setTaskName(String string) {
progressBar.setString(string);
setTitle(string);
}
/**
* #param string
*/
public void setMsg(String string) {
progressBar.setString(string);
}
/**
* #param rows
*/
public void setDone(int rows) {
progressBar.setValue(rows);
}
/**
*
*/
public void taskFinished() {
setVisible(false);
dispose();
}
public void run() {
setVisible(true);
progressBar.setVisible(true);
}
protected void processWindowEvent(WindowEvent e) {
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
this.cancelled = true;
}
super.processWindowEvent(e);
}
public boolean isCancelled(){
return cancelled;
}
}
and I am calling my progress bar using the methods defined
MyProgess bar = new MyProgess("Test");
bar.setMsg("Test");
I need a way to convert the above class to purely javafx. I am a newbie Java and javafx and would appreciate any help I can get.
The code for JavaFX ProgressBar is given below. I referred it from JavaFX docs.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
final Float[] values = new Float[] {-1.0f, 0f, 0.6f, 1.0f};
final Label [] labels = new Label[values.length];
final ProgressBar[] pbs = new ProgressBar[values.length];
final ProgressIndicator[] pins = new ProgressIndicator[values.length];
final HBox hbs [] = new HBox [values.length];
#Override
public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root, 300, 150);
scene.getStylesheets().add("progresssample/Style.css");
stage.setScene(scene);
stage.setTitle("Progress Controls");
for (int i = 0; i < values.length; i++) {
final Label label = labels[i] = new Label();
label.setText("progress:" + values[i]);
final ProgressBar pb = pbs[i] = new ProgressBar();
pb.setProgress(values[i]);
final ProgressIndicator pin = pins[i] = new ProgressIndicator();
pin.setProgress(values[i]);
final HBox hb = hbs[i] = new HBox();
hb.setSpacing(5);
hb.setAlignment(Pos.CENTER);
hb.getChildren().addAll(label, pb, pin);
}
final VBox vb = new VBox();
vb.setSpacing(5);
vb.getChildren().addAll(hbs);
scene.setRoot(vb);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I hope it helps you..

How to create new records directly in javafx TableView?

I am using JDBC and MySQL.
I can create Text Fields and have their contents entered as records in a MySQL table (and then populate the corresponding javafx TableView).
I would like to know if it is possible for the user to directly add new records to the TableView by clicking on TableView cells.
Would it be a good practice to do so? The TableView shows details of sale invoice like item name, quantity sold, rate etc.
I posted this example a while ago, but I can't find it now.
One way to do this is to put a "blank" item at the end of the table's list of items. Register a listener so that if the user edits that value a new blank item is added at the end.
Here's an example (it also has some editing features that are different to the default).
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableViewSingleClickEditTest extends Application {
#Override
public void start(Stage primaryStage) {
TableView<Person> table = new TableView<>();
table.setEditable(true);
TableColumn<Person, String> firstNameCol = createCol("First Name", Person::firstNameProperty, 150);
TableColumn<Person, String> lastNameCol = createCol("Last Name", Person::lastNameProperty, 150);
TableColumn<Person, String> emailCol = createCol("Email", Person::emailProperty, 200);
TableColumn<Person, Void> indexCol = new TableColumn<>("");
indexCol.setCellFactory(col -> {
TableCell<Person, Void> cell = new TableCell<>();
cell.textProperty().bind(Bindings.createStringBinding(() -> {
if (cell.getIndex() >= 0 && cell.getIndex() < table.getItems().size() - 1) {
return Integer.toString(cell.getIndex() + 1);
} else if (cell.getIndex() == table.getItems().size() - 1) {
return "*" ;
} else return "" ;
}, cell.indexProperty(), table.getItems()));
return cell ;
});
indexCol.setPrefWidth(32);
table.getItems().addAll(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
);
ChangeListener<String> lastPersonTextListener = new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> obs, String oldText, String newText) {
if (oldText.isEmpty() && ! newText.isEmpty()) {
Person lastPerson = table.getItems().get(table.getItems().size() - 1);
lastPerson.firstNameProperty().removeListener(this);
lastPerson.lastNameProperty().removeListener(this);
lastPerson.emailProperty().removeListener(this);
Person newBlankPerson = new Person("", "", "");
newBlankPerson.firstNameProperty().addListener(this);
newBlankPerson.lastNameProperty().addListener(this);
newBlankPerson.emailProperty().addListener(this);
table.getItems().add(newBlankPerson);
}
}
};
Person blankPerson = new Person("", "", "");
blankPerson.firstNameProperty().addListener(lastPersonTextListener);
blankPerson.lastNameProperty().addListener(lastPersonTextListener);
blankPerson.emailProperty().addListener(lastPersonTextListener);
table.getItems().add(blankPerson);
table.getColumns().add(indexCol);
table.getColumns().add(firstNameCol);
table.getColumns().add(lastNameCol);
table.getColumns().add(emailCol);
VBox root = new VBox(15, table);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableColumn<Person, String> createCol(String title,
Function<Person, ObservableValue<String>> mapper, double size) {
TableColumn<Person, String> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> mapper.apply(cellData.getValue()));
Callback<TableColumn<Person, String>, TableCell<Person, String>> defaultCellFactory
= TextFieldTableCell.forTableColumn();
col.setCellFactory(column -> {
TableCell<Person, String> cell = defaultCellFactory.call(column);
cell.setOnMouseClicked(e -> {
if (! cell.isEditing() && ! cell.isEmpty()) {
cell.getTableView().edit(cell.getIndex(), column);
}
});
return cell ;
});
col.setPrefWidth(size);
return col ;
}
public class Person {
private final StringProperty firstName = new SimpleStringProperty(this, "firstName");
private final StringProperty lastName = new SimpleStringProperty(this, "lastName");
private final StringProperty email = new SimpleStringProperty(this, "email");
public Person(String firstName, String lastName, String email) {
this.firstName.set(firstName);
this.lastName.set(lastName);
this.email.set(email);
}
public final StringProperty firstNameProperty() {
return this.firstName;
}
public final java.lang.String getFirstName() {
return this.firstNameProperty().get();
}
public final void setFirstName(final java.lang.String firstName) {
this.firstNameProperty().set(firstName);
}
public final StringProperty lastNameProperty() {
return this.lastName;
}
public final java.lang.String getLastName() {
return this.lastNameProperty().get();
}
public final void setLastName(final java.lang.String lastName) {
this.lastNameProperty().set(lastName);
}
public final StringProperty emailProperty() {
return this.email;
}
public final java.lang.String getEmail() {
return this.emailProperty().get();
}
public final void setEmail(final java.lang.String email) {
this.emailProperty().set(email);
}
}
public static void main(String[] args) {
launch(args);
}
}

JComboBox inside Jtable with GlazedLists AutocompleteSupport - getSelectedItem returns null

I'm using GlazedLists' AutoCompleteSupport to wrap a JComboBox used as cell editor for a JTable and am facing a problem to get selectedItem when I type a value in the editor that is not in the model.
The problem appears inside the stopCellEditing method, after you type something in the ComboBox that is not in the list. Even if something was typed in the editor, when invoking getItem() from stopCellEditing, null will be returned. Please see like 65 from the code below.
I would like to get the item from the editor to be able to add it to the ComboBox model.
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.TextFilterator;
import ca.odell.glazedlists.swing.AutoCompleteSupport;
import java.awt.Component;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.util.HashMap;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
public class TestComboBoxGlazedLists {
public static void main(String[] args) {
TestComboBoxGlazedLists test = new TestComboBoxGlazedLists();
test.go();
}
public void go() {
//create the frame
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// create and add a tabbed pane to the frame
JTabbedPane tabbedPane = new JTabbedPane();
frame.getContentPane().add(tabbedPane);
//create a table and add it to a scroll pane in a new tab
JTable table = new JTable(new DefaultTableModel(new Object[]{"A", "B"}, 5));
JScrollPane scrollPane = new JScrollPane(table);
tabbedPane.addTab("test", scrollPane);
// create a simple JComboBox and set is as table cell editor on column A
TestComboBoxGlazedLists.UserRepository rep = new TestComboBoxGlazedLists.UserRepository();
TestComboBoxGlazedLists.UserInfo[] comboElements = rep.getAllUsers();
DefaultComboBoxModel model = new DefaultComboBoxModel(comboElements);
JComboBox comboBox = new JComboBox(model);
// GlazedLists
DefaultCellEditor cellEditor = new DefaultCellEditor(comboBox) {
private Object originalValue;
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
originalValue = value;
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
#Override
public boolean stopCellEditing() {
JComboBox comboBox = (JComboBox) getComponent();
ComboBoxModel comboModel = comboBox.getModel();
// this value is null when the selected item is not from the list
Object editingValue = getCellEditorValue();
// Needed because your TableModel is empty
if (editingValue == null) {
return super.stopCellEditing();
}
int selectedIndex = -1;
int modelSize = comboModel.getSize();
for (int i = 0; i < modelSize; i++) {
if (editingValue.equals(comboModel.getElementAt(i))) {
selectedIndex = i;
}
}
// Selecting item from model
if (!(selectedIndex == -1)) {
return super.stopCellEditing();
}
if (!(editingValue instanceof TestComboBoxGlazedLists.UserInfo)) {
// Confirm addition of new value
int result = JOptionPane.showConfirmDialog(
comboBox.getParent(),
"Add (" + editingValue + ") to table?",
"Update Model",
JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
TestComboBoxGlazedLists.UserInfo newUser = new TestComboBoxGlazedLists.UserInfo(editingValue.toString(), null);
comboBox.addItem(newUser);
comboBox.setSelectedItem(newUser);
return super.stopCellEditing();
}
}
return false;
}
};
// needs to be invoked from Event Dispatch Thread
SwingUtilities.invokeLater(new TestComboBoxGlazedLists.AutocompleteComboRunnable(table, comboBox));
// end GlazedLists
table.getColumn("A").setCellEditor(cellEditor);
table.getColumn("A").setCellRenderer(new TestComboBoxGlazedLists.CustomTableCellRenderer());
// pack and show frame
frame.pack();
frame.setVisible(true);
}
public class AutocompleteComboRunnable implements Runnable {
private JTable mTable;
private JComboBox mComboBox;
public AutocompleteComboRunnable(JTable table, JComboBox comboBox) {
mTable = table;
mComboBox = comboBox;
}
#Override
public void run() {
TextFilterator textFilterator = GlazedLists.textFilterator("firstName");
// ComboBoxCellEditor cellEditor = new ComboBoxCellEditor(comboBox);
TestComboBoxGlazedLists.UserRepository rep = new TestComboBoxGlazedLists.UserRepository();
AutoCompleteSupport support = AutoCompleteSupport.install(mComboBox,
GlazedLists.eventListOf(rep.getAllUsers()),
textFilterator,
new TestComboBoxGlazedLists.UserInfoFormat());
support.setStrict(false);
}
}
public class CustomTableCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value != null) {
// this is used to extract the data you want to display in the table from your "custom model"
TestComboBoxGlazedLists.UserInfo user = (TestComboBoxGlazedLists.UserInfo) value;
return super.getTableCellRendererComponent(table, user.getFirstName(), isSelected, hasFocus, row, column);
} else {
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
}
}
public class UserInfo {
private String firstName;
private String lastName;
public UserInfo(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
public class UserRepository {
TestComboBoxGlazedLists.UserInfo[] comboElements;
HashMap<String, TestComboBoxGlazedLists.UserInfo> objectsMap;
public UserRepository() {
comboElements = new TestComboBoxGlazedLists.UserInfo[5];
comboElements[0] = new TestComboBoxGlazedLists.UserInfo("John", "Doe");
comboElements[1] = new TestComboBoxGlazedLists.UserInfo("Betty", "Doe");
comboElements[2] = new TestComboBoxGlazedLists.UserInfo("Elenor", "Smith");
comboElements[3] = new TestComboBoxGlazedLists.UserInfo("Helen", "Kelly");
comboElements[4] = new TestComboBoxGlazedLists.UserInfo("Joe", "Black");
objectsMap = new HashMap<>();
for (int i = 0; i < 5; i++) {
objectsMap.put(comboElements[i].getFirstName(), comboElements[i]);
}
}
public TestComboBoxGlazedLists.UserInfo getUserInfo(String name) {
return objectsMap.get(name);
}
public TestComboBoxGlazedLists.UserInfo[] getAllUsers() {
return comboElements;
}
}
private class UserInfoFormat extends Format {
#Override
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
if (obj != null) {
toAppendTo.append(((TestComboBoxGlazedLists.UserInfo) obj).getFirstName());
}
return toAppendTo;
}
#Override
public Object parseObject(String source, ParsePosition pos) {
TestComboBoxGlazedLists.UserRepository rep = new TestComboBoxGlazedLists.UserRepository();
return rep.getUserInfo(source.substring(pos.getIndex()));
}
}
}

Swing: table cell rendering doesn't work right for JXTable?

I'm trying to override the highlight color of a JXTable based on the value of certain row items. Here's an example where the highlight is green if the row item value has getNumber() % 2 == 0.
It works fine for JTable, but for JXTable, it looks like the table cell renderer doesn't work unless the rows in question are selected. Why does it behave this way, and how do I fix it?
import java.awt.Color;
import java.awt.Component;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import org.jdesktop.swingx.JXTable;
import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.SortedList;
import ca.odell.glazedlists.gui.TableFormat;
import ca.odell.glazedlists.swing.EventTableModel;
public class TableRendererExample {
static public enum ItemKey {
NAME("name") {
#Override public String getStringFromItem(Item item) {
return item.getName();
}
},
NUMBER("#") {
#Override public String getStringFromItem(Item item) {
return Integer.toString(item.getNumber());
}
},
PARENT("parent") {
#Override public String getStringFromItem(Item item) {
Item p = item.getParent();
return (p == null) ? null : p.getName();
}
};
final private String name;
ItemKey(String name) { this.name = name; }
public String getName() { return this.name; }
abstract public String getStringFromItem(Item item);
static private ItemKey[] columns = { NAME, NUMBER, PARENT };
static public ItemKey[] getColumns() { return columns; }
}
static public class ItemTableFormat implements TableFormat<Item> {
#Override public int getColumnCount() {
return ItemKey.getColumns().length;
}
#Override public String getColumnName(int col) {
return ItemKey.getColumns()[col].getName();
}
#Override public Object getColumnValue(Item item, int col) {
return ItemKey.getColumns()[col].getStringFromItem(item);
}
}
static class Item {
final private String name;
final private int number;
final private Item parent;
private Item(String name, int number, Item parent) {
this.name=name; this.number=number; this.parent=parent;
}
static public Item create(String name, int number, Item parent) {
return new Item(name, number, parent);
}
public String getName() { return this.name; }
public int getNumber() { return this.number; }
public Item getParent() { return this.parent; }
}
static public void main(String[] args)
{
EventList<Item> items = new BasicEventList<Item>();
Item x1,x2,x3,x4;
x1 = Item.create("foo", 1, null);
items.add(x1);
x2 = Item.create("bar", 2, x1);
items.add(x2);
x3 = Item.create("baz", 1, x1);
items.add(x3);
x4 = Item.create("quux", 4, x2);
items.add(x4);
items.add(Item.create("wham", 3, x3));
items.add(Item.create("blam", 11, x3));
items.add(Item.create("shazaam", 20, x3));
items.add(Item.create("August", 8, x4));
items.add(Item.create("September", 9, x4));
items.add(Item.create("October", 10, x4));
items.add(Item.create("November", 11, x4));
items.add(Item.create("December", 12, x4));
EventList<Item> sortedItems = new SortedList<Item>(items, null);
final EventList<Item> displayList = sortedItems;
doit(new JTable(), "JTable cell renderer", displayList);
doit(new JXTable(), "JXTable cell renderer", displayList);
}
static public void doit(JTable table, String title,
final EventList<Item> displayList)
{
TableFormat<Item> tf = new ItemTableFormat();
EventTableModel<Item> etm =
new EventTableModel<Item>(displayList, tf);
table.setModel(etm);
if (table instanceof JXTable)
{
((JXTable)table).setColumnControlVisible(true);
}
TableColumnModel tcm = table.getColumnModel();
final Color selectedGreen = new Color(128, 255, 128);
final Color unselectedGreen = new Color(224, 255, 224);
TableCellRenderer tcr = new DefaultTableCellRenderer() {
#Override public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column)
{
Component c = super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
Item item = displayList.get(row);
Color color = null;
if (item != null && ((item.getNumber() % 2) == 0))
{
color = isSelected ? selectedGreen : unselectedGreen;
}
if (color == null)
{
color = isSelected
? table.getSelectionBackground()
: table.getBackground();
}
c.setBackground(color);
return c;
}
};
for (int i = 0; i < tcm.getColumnCount(); ++i)
{
tcm.getColumn(i).setCellRenderer(tcr);
}
JPanel panel = new JPanel();
panel.add(new JScrollPane(table));
JFrame frame = new JFrame(title);
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
}
I got a response from one of the SwingX folks who said that I needed to use a Highlighter (rather than a TableCellRenderer) for the renderers to behave properly.
There was a hacky workaround but he didn't recommend it.