How to create new records directly in javafx TableView? - mysql

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);
}
}

Related

Adding new User to a table from MYSQL database using JavaFX is not working

I searched but couldn't find a solution because the examples on google search does not with my programming stil.
edit: I solved the problem in the addUser method.
The date format in MySQL is YYY-MM-DD. In my DatePicker it's DD.MM.YYY. How can get this fixed?
Do I have to change something in my database or in my java file?
package application;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
public class Main extends Application {
private BorderPane root;
private Scene scene;
private GridPane grid;
private Label lblFirstName;
private Label lblLastName;
private Label lblDOB;
private TextField txtFirstName;
private TextField txtLastName;
private DatePicker txtDOB;
private Button btnAdd;
private Button btnCancel;
private Button btnUpdate;
private HBox hbox;
private ButtonBar buttonBar;
private TableView<User> table;
final ObservableList<User> data = FXCollections.observableArrayList();
Connection conn;
PreparedStatement pst = null;
ResultSet rs = null;
String url = "jdbc:mysql://localhost:3306/...";
String user = "root";
String password = "...";
#Override
public void start(Stage primaryStage) {
try {
CheckConnection();
root = new BorderPane();
grid = new GridPane();
// Create labels and textfields
lblFirstName = new Label("First Name");
lblFirstName.setFont(new Font("Times New Roman", 18));
lblFirstName.setPrefSize(100, 50);
lblLastName = new Label("Last Name");
lblLastName.setFont(new Font("Times New Roman", 18));
lblLastName.setPrefSize(100, 50);
lblDOB = new Label("DOB");
lblDOB.setFont(new Font("Times New Roman", 18));
lblDOB.setPrefSize(150, 50);
txtFirstName = new TextField();
txtLastName = new TextField();
txtDOB = new DatePicker();
// add to grid
grid.add(lblFirstName, 0, 0, 1, 1);
grid.add(txtFirstName, 1, 0, 1, 1);
grid.add(lblLastName, 0, 1, 1, 1);
grid.add(txtLastName, 1, 1, 1, 1);
grid.add(lblDOB, 0, 2, 1, 1);
grid.add(txtDOB, 1, 2, 1, 1);
grid.setHgap(10);
grid.setVgap(5);
grid.setPadding(new Insets(50, 10, 10, 30));
// Column constraints
ColumnConstraints column1 = new ColumnConstraints();
ColumnConstraints column2 = new ColumnConstraints();
grid.getColumnConstraints().add(column1);
grid.getColumnConstraints().add(column2);
column1.setPrefWidth(110);
column2.setPrefWidth(200);
// Buttons, Button Actions, ButtonBar
btnAdd = new Button("Add");
btnAdd.setPrefSize(40, 40);
btnAdd.setOnAction(e -> {
addUser();
});
btnCancel = new Button("Cancel");
btnCancel.setPrefSize(40, 40);
btnCancel.setOnAction(e -> {
clearFields();
});
btnUpdate = new Button("Update");
btnUpdate.setPrefSize(40, 40);
btnUpdate.setOnAction(e -> {
updateTable();
});
buttonBar = new ButtonBar();
buttonBar.getButtons().addAll(btnAdd, btnCancel, btnUpdate);
// add ButtonBar to HBox
hbox = new HBox();
hbox.getChildren().add(buttonBar);
hbox.setPadding(new Insets(10));
// create table
table = new TableView<>();
TableColumn<User, String> IDColumn = new TableColumn<User, String>("PersonID");
IDColumn.setPrefWidth(100);
IDColumn.setCellValueFactory(new PropertyValueFactory<>("personID"));
TableColumn<User, String> vornameColumn = new TableColumn<User, String>("First Name");
vornameColumn.setPrefWidth(100);
vornameColumn.setCellValueFactory(new PropertyValueFactory<>("firstName"));
TableColumn<User, String> nachnameColumn = new TableColumn<User, String>("Last Name");
nachnameColumn.setPrefWidth(100);
nachnameColumn.setCellValueFactory(new PropertyValueFactory<>("lastName"));
TableColumn<User, String> dobColumn = new TableColumn<User, String>("DOB");
dobColumn.setPrefWidth(100);
dobColumn.setCellValueFactory(new PropertyValueFactory<>("dob"));
table.getColumns().addAll(IDColumn, vornameColumn, nachnameColumn, dobColumn);
root.setCenter(table);
BorderPane.setMargin(table, new Insets(10, 10, 10, 10));
root.setLeft(grid);
root.setBottom(hbox);
scene = new Scene(root, 1000, 500);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public void CheckConnection() {
conn = DBConnection.DbConnector();
if (conn == null) {
System.out.println("Connection Not Successful");
System.exit(1);
} else {
System.out.println("Connection Successful");
}
}
public void updateTable() {
data.clear();
try {
String query = "SELECT * FROM persons ";
pst = conn.prepareStatement(query);
rs = pst.executeQuery();
while (rs.next()) {
data.add(new User(rs.getString("PersonID"), rs.getString("Firstname"), rs.getString("Lastname"),
rs.getString("DOB")
));
table.setItems(data);
}
pst.close();
rs.close();
} catch (Exception e1) {
System.err.println(e1);
}
}
public void addUser() {
try {
conn = DBConnection.DbConnector();
String query = "INSERT into persons (Firstname, Lastname, DOB) VALUES (?, ?, ?)";
pst = conn.prepareStatement(query);
pst.setString(1, txtFirstName.getText());
pst.setString(2, txtLastName.getText());
pst.setString(3, ((TextField)txtDOB.getEditor()).getText());
pst.executeUpdate();
pst.close();
} catch (Exception e2) {
System.err.println(e2);
}
}
public void clearFields() {
txtFirstName.clear();
txtLastName.clear();
txtDOB.setValue(null);
}
public static void main(String[] args) {
launch(args);
}
}
package application;
import javafx.beans.property.SimpleStringProperty;
public class User {
private SimpleStringProperty personID;
private SimpleStringProperty firstName;
private SimpleStringProperty lastName;
private SimpleStringProperty dob;
public User(String pID, String fName, String lName, String DOB) {
this.personID = new SimpleStringProperty(pID);
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.dob = new SimpleStringProperty(DOB);
}
// getter , setter
public String getPersonID() {
return personID.get();
}
public void setPersonenID(String pID) {
personID.set(pID);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lName) {
lastName.set(lName);
}
public String getDob() {
return dob.get();
}
public void setDob(String DOB) {
dob.set(DOB);
}
}
package application;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnection {
static String url ="jdbc:mysql://localhost:3306/...";
static String user ="root";
static String password="...";
public static Connection DbConnector(){
try{
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
} catch (SQLException ex) {
System.err.println(ex.getMessage());
}
return null;
}
}
I understand from your comment that the data type of column DOB, in database table persons is DATE. Hence the format is irrelevant because even though the documentation for DATE type includes the following:
The DATE type is used for values with a date part but no time part. MySQL retrieves and displays DATE values in 'YYYY-MM-DD' format. The supported range is '1000-01-01' to '9999-12-31'.
I think this is misleading because according to the storage requirements documentation, a DATE value is stored in three bytes. So the format is only for human-readable display.
So since the format is irrelevant, your problem is basically how to get the DatePicker value and insert it into DOB column of persons database table.
Method getValue(), in class DatePicker, returns a LocalDate.
If you are using MySQL Connector, then according to the documentation, the DATE data type maps to java class java.sql.Date.
Therefore you need to convert java.time.LocalDate to java.sql.Date. You can do this by calling static method valueOf() in class java.sql.Date. Refer to this SO question.
Here is my rewritten version of your addUser() method. It uses try-with-resources.
public void addUser() {
String query = "INSERT into persons (Firstname, Lastname, DOB) VALUES (?, ?, ?)";
try (conn = DBConnection.DbConnector();
pst = conn.prepareStatement(query)) {
pst.setString(1, txtFirstName.getText());
pst.setString(2, txtLastName.getText());
pst.setDate(3, java.sql.Date.valueOf(txtDOB.getValue()));
pst.executeUpdate();
}
catch (SQLException xSql) {
xSql.printStackTrace();
}
}
If you still also want to change the format of the date displayed by DatePicker, you can set its converter property. The below code demonstrates how to do this using an anonymous class.
DatePicker txtDOB = new DatePicker();
txtDOB.setConverter(new StringConverter<LocalDate>() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy", Locale.ENGLISH);
#Override
public String toString(LocalDate object) {
if (object != null) {
return object.format(formatter);
}
return null;
}
#Override
public LocalDate fromString(String string) {
if (string != null) {
return LocalDate.parse(string, formatter);
}
return null;
}
});

Get String in list in adapter (gson)

I have a problem with my adapter. I already succeeded to display some informations from my JSON (codeLieu and libelle) that looks like this:
[
{
"codeLieu": "OTAG",
"libelle": "50 Otages",
"distance": null,
"ligne": [
{
"numLigne": "2"
},
{
"numLigne": "C2"
},
{
"numLigne": "12"
},
{
"numLigne": "23"
}
]
},
...
]
Here is my model:
package material.romain.com.projentreprise.Adapter;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.List;
public class Response implements Serializable{
private String codeLieu;
private String libelle;
private String distance;
private List<LigneEntities> ligne;
public String getCode() {
return codeLieu;
}
public void setCode(String codeLieu) {
this.codeLieu = codeLieu;
}
public String getLibelle() {
return libelle;
}
public void setLibelle(String libelle) {
this.libelle = libelle;
}
public String getDistance() {
return distance;
}
public void setDistance(String distance) {
this.distance = distance;
}
public List<LigneEntities> getLigne() {return ligne;}
public void setLigne(List<LigneEntities> ligne) {
this.ligne = ligne;
}
public static class LigneEntities {
private String numLigne;
public String getLigne() {
return numLigne;
}
public void setLigne(String numLigne) {
this.numLigne = numLigne;
}
}
}
And finally this is my adapter :
package material.romain.com.projentreprise.Adapter;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.mikepenz.iconics.IconicsDrawable;
import java.util.ArrayList;
import de.hdodenhof.circleimageview.CircleImageView;
import material.romain.com.projentreprise.R;
import material.romain.com.projentreprise.Util.CircularTextView;
import material.romain.com.projentreprise.Util.ColorLigne;
public class ListAdapter extends BaseAdapter implements Filterable {
private ArrayList<Response> arret;
private Context context;
private LayoutInflater inflater;
private MyFilter mFilter;
private ArrayList<Response> mSearchArret;
public ListAdapter(Context mContext, ArrayList<Response> mArretItem) {
this.context = mContext;
this.arret = mArretItem;
this.mSearchArret = mArretItem;
getFilter();
}
#Override
public int getCount() {
return mSearchArret.size();
}
#Override
public Object getItem(int position) {
return mSearchArret.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Response item = (Response) getItem(position);
ColorLigne.ViewHolder holder = null;
if (convertView == null) {
holder = new ColorLigne.ViewHolder();
inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.each_list_item, parent, false);
holder.circleImage = (CircleImageView) convertView.findViewById(R.id.circleView);
holder.textArret = (TextView) convertView.findViewById(R.id.tvListArret);
holder.circle = (CircularTextView) convertView.findViewById(R.id.tvArretColor);
convertView.setTag(holder);
} else {
holder = (ColorLigne.ViewHolder) convertView.getTag();
}
Drawable color = new ColorDrawable(ContextCompat.getColor(context, R.color.tanVert));
Drawable image = new IconicsDrawable(context).icon(FontAwesome.Icon.faw_bus).color(Color.WHITE).sizeDp(48).paddingDp(10);
LayerDrawable ld = new LayerDrawable(new Drawable[]{color, image});
holder.circleImage.setImageDrawable(ld);
holder.textArret.setText(item.getLibelle());
return convertView;
}
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new MyFilter();
}
return mFilter;
}
class MyFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (prefix != null && prefix.length() > 0) {
ArrayList<Response> tempList = new ArrayList<>();
for (Response value : arret) {
if (value.getLibelle().toLowerCase().contains(prefix.toString().toLowerCase())) {
tempList.add(value);
}
}
results.count = tempList.size();
results.values = tempList;
} else {
results.count = arret.size();
results.values = arret;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
try {
mSearchArret = (ArrayList<Response>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
And I would like to get strings from "ligne" but it's in a list and I don't know how to access it. My goal is to put the strings into a circleTextView.
Edit:
I tried this in getView method
Response item = getItem(position);
for(Response value: arret){
value = item;
String ligneItem = value.getLigne().toString();
ColorLigne.setColorLigne(ligneItem, holder, context);
holder.circle.setText(ligneItem);
holder.circle.setStrokeWidth(0);
}
Add below method to your Response.java
public String getItems() {
StringBuilder builder = new StringBuilder();
for (LigneEntities entity : getLigne()) { //loop through every item from the list
builder.append(entity.getLigne() + ","); //add to StringBuilder
}
builder.replace(builder.length() - 1, builder.length(), "");//remove last ,(semicolon)
return builder.toString();
}
setting to your CircleTextView
holder.circle.setText(item.getItems());

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()));
}
}
}

Java swing jtable setvalueAt doesn't work

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 !

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.