I have never used tableview before and I am quite new to with Java and JavaFX. I tried to mirror an example but since the data is coming from a db client created in house I couldn't copy it exactly. Anyway, my data is going into the table but its entering as what looks like a csv data and each column is not getting put into its respective column. Here is a screenshot to clarify my question:
Getting columns here
for (Column col : drs.getColumns()){
TableColumn tblCol = new TableColumn(col.getName());
tblCol.setCellValueFactory(new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> p) {
return new SimpleStringProperty(p.getValue().toString());
}
});
table.getColumns().addAll(tblCol);
}
Getting the rows here:
while (drs.hasNextRow()) {
ObservableList<String> row = FXCollections.observableArrayList();
for (int i = 0; i < drs.getColumns().length; i++) {
row.add(drs.getNextRow().getItem(i) + "");
}
data.add(row);
}
And here is where I fail at sending the data to the table.
table.setItems(data);
System.out.println("dis is data: " +data);
the data prints like so:
dis is data: [[data, data, data....], [data, data, data....], [data, data, data....]]
It takes each [row] and puts it into each column for each record. I am assuming I need the data to look like:
[[data], [data], [data]....[data]], [[data], [data], [data]....[data]], [[data], [data], [data]....[data]]
} catch(Exception e){
e.printStackTrace();
System.out.println("everything is broken");
}
}
So, I am lost. I don't know what I am doing and I'd appreciate any help that you can offer me.
In TableView all the data in a row is associated with a item. The TableColumn.cellValueFactory is used to select the "part" of a item that should be shown in the column. Therefore you should use it to select the value:
TableView<ObservableList<String>> table = ...
int index = 0;
for (Column col : drs.getColumns()) {
final int columnIndex = index++;
TableColumn<ObservableList<String>, String> tblCol = new TableColumn(col.getName());
tblCol.setCellValueFactory(new Callback<CellDataFeatures<ObservableList<String>, String>, ObservableValue<String>>(){
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> p) {
return Bindings.stringValueAt(p.getValue(), columnIndex);
}
});
table.getColumns().add(tblCol);
}
Here the Bindings.stringValueAt is used to select the element form the ObservableList.
Also you need to use one row per row:
while (drs.hasNextRow()) {
ObservableList<String> row = FXCollections.observableArrayList();
Row sourceRow = drs.getNextRow();
for (int i = 0; i < drs.getColumns().length; i++) {
row.add(Objects.toString(sourceRow.getItem(i)));
}
data.add(row);
}
Related
Good afternoon guys, i'm trying to learn java programming and then i'm encountering some problem that i don't know why with my code when I'm learning about JTable.
So, what I'm trying to do is when i double clicked the row in JTable named TableGejala, the row that i double clicked will transfered into the other JTable named TableAturan and after that the row that i double clicked in TableGejala will be removed. For the part of transferring row from TableGejala to TableAturan successfully transferred when i double clicked the row, but it doesn't delete the correct row in TableGejala. Instead of deleting the row that i clicked, it delete the row below it.
For more details, this is my code to create TableGejala :
private void getTableGejala() {
while(tabel2.getRowCount() > 0){
for(int i=0;i < tabel2.getRowCount();i++){
tabel2.removeRow(i);
}
}
tabel2.addColumn("ID Gejala");
tabel2.addColumn("Nama Gejala");
TabelGejala.setModel(tabel2);
TabelGejala.setAutoResizeMode(TabelGejala.AUTO_RESIZE_ALL_COLUMNS);
}
And then this is my code to get data for my table from MySQL :
private void loadDataGejala(Boolean baru){
tabel2.getDataVector().removeAllElements();
try {
java.sql.Connection konek = (Connection) Koneksi.KoneksiDB.getConnection();
java.sql.Statement konek_statement = konek.createStatement();
String query_bukaTabel = "";
if(baru){
query_bukaTabel = "select id_gejala,nama_gejala from gejala";
}
else{
String idPkt = FieldID.getText();
query_bukaTabel = "select gejala.id_gejala,gejala.nama_gejala from gejala where gejala.id_gejala not in(select id_gejala from aturan2 where id_penyakit='"+idPkt+"')";
}
java.sql.ResultSet line_result = konek_statement.executeQuery(query_bukaTabel);
while (line_result.next()) {
Object[] getO = new Object[2];
getO[0] = line_result.getString("id_gejala");
getO[1] = line_result.getString("nama_gejala");
tabel2.addRow(getO);
}
line_result.close();
konek_statement.close();
}catch (Exception e) {}
}
This is my code to transfer the row and delete the row :
private void TabelGejalaMousePressed(java.awt.event.MouseEvent evt) {
if (evt.getClickCount()>=2){
int col = 0;
int row = 0;
row = TabelGejala.rowAtPoint(evt.getPoint());
col = TabelGejala.columnAtPoint(evt.getPoint());
String col1 = (String)TabelGejala.getValueAt(row, 0);
String col2 = (String)TabelGejala.getValueAt(row, 1);
DefaultTableModel model = (DefaultTableModel) TabelAturan.getModel();
DefaultTableModel old = (DefaultTableModel) TabelGejala.getModel();
old.removeRow(row);
model.addRow(new Object[]{col1, col2, 0});
TabelAturan.requestFocus();
TabelAturan.setRowSelectionInterval(TabelAturan.getRowCount()-1,TabelAturan.getRowCount()-1);
TabelAturan.editCellAt(TabelAturan.getRowCount()-1,2);
}
}
And this is the screenshot of my problem :
Before Double Clicked
After Double Clicked
Which part that makes my output get the wrong row to be deleted? please help me, and thank you in advance for any helps, even for reading my question :)
Firstly disable cell editable property in your first table(TabelGejala) to ensure proper deleting of row. I achieved this using the following code :-
//instance table model
DefaultTableModel tableModel = new DefaultTableModel(new Object[][]{},
new String[]{
"ID Gejala", "Nama Gejala"
}) {
#Override
public boolean isCellEditable(int row, int column) {
//all cells false
return false;
}
};
TabelGejala.setModel(tableModel);
then use jtable.getselectedrow() and jtable.getselectedcolumn() to get values from table. after addition of desired values to second table, simply delete the selected row. here is the code, derived from your code :-
private void TabelGejalaMousePressed(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
if (evt.getClickCount() >= 2) {
DefaultTableModel model = (DefaultTableModel) TabelAturan.getModel();
DefaultTableModel old = (DefaultTableModel) TabelGejala.getModel();
model.addRow(new Object[]{TabelGejala.getValueAt(TabelGejala.getSelectedRow(), 0), TabelGejala.getValueAt(TabelGejala.getSelectedRow(), 1), 0});
old.removeRow(TabelGejala.getSelectedRow());
TabelAturan.requestFocus();
TabelAturan.setRowSelectionInterval(TabelAturan.getRowCount() - 1, TabelAturan.getRowCount() - 1);
TabelAturan.editCellAt(TabelAturan.getRowCount() - 1, 2);
}
}
Is it possible to edit a cell value in a dynamic TableView (dynamic rows and dynamic columns)?
All I found on the internet was some editable TextFields over the cells.
However, I want to edit the value in the table and then update my List with the new data.
I'm using IntelliJ IDEA 13.1.4 , JavaFX Scene Builder 2.0 and the newest JavaFX version.
Here is the code, where I create the dynamic rows and columns:
public List<String[]> jdata = new LinkedList<>(); //Here is the data
private TableView<String[]> sourceTable;
private ObservableList<String[]> srcData;
.
.
.
int clms;
public void showTable(Convert cnv) {
clms = cnv.getColums(); //number of the columns
for (int i = 0; i < clms; i++) {
TableColumn<String[], String> firstNameCol = new TableColumn<>("\tC"+(i+1)+" \t");
firstNameCol.setMinWidth(20);
int index = i ;
firstNameCol.setCellValueFactory(cellData -> {
String[] rowData = cellData.getValue();
if (index >= rowData.length) {
return new ReadOnlyStringWrapper("");
} else {
String cellValue = rowData[index];
return new ReadOnlyStringWrapper(cellValue);
}
});
sourceTable.getColumns().add(firstNameCol);
}
srcData = FXCollections.observableList(jdata);
sourceTable.getItems().addAll(srcData);
}
Just do
firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
firstNameCol.setOnEditCommit(event -> {
String[] row = event.getRowValue();
row[index] = event.getNewValue();
});
This code will make the firstNameCol column editable. When you click on any cell under this column, you will get a TextField where you can enter value. When you hit enter, the value gets saved in the table.
UPDATE:
Let us say you have created a model class for your Table, and lets assume its name is TestCasesModel, this is how the above code would look.
firstNameCol.setCellFactory(TextFieldTableCell.<TestCasesModel>forTableColumn());
firstNameCol.setOnEditCommit(
new EventHandler<CellEditEvent<TestCasesModel, String>>() {
#Override
public void handle(CellEditEvent<TestCasesModel, String> t) {
((TestCasesModel) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setObjectName(t.getNewValue());
}
}
);
It is always a good practice to work with POJO classes instead of String arrays.
CellEditEvent must be imported like this:
import javafx.scene.control.TableColumn.CellEditEvent;
I need help in a routine I've written to dump the content of a class (which represent a database table) to a new database table in MS Access. My code is the following:
public void dumpDB() throws IOException, Exception {
// for each table
for (String tableName : this.DB.getTablesNames()) {
System.out.println(tableName);
int nColumns = 0;
ModelDatabaseTable table = this.DB.getTable(tableName);
// create a tablebuilder
TableBuilder DBTableBuilder = new TableBuilder(tableName);
// get datatypes of columns
Map<String, DataType> columns = table.getColumns();
// for each column
for (String columnName : columns.keySet()) {
System.out.println(columnName);
// get its datatype
DataType dt = columns.get(columnName);
// create a column with correspondent datatype and max length and add it
// to the table builder
ColumnBuilder cb = new ColumnBuilder(columnName).setType(dt).setMaxLength();
DBTableBuilder.addColumn(cb);
nColumns += 1;
}
// if table has columns
if (nColumns > 0) {
// save it to the actual database: Exception rises here
Table DBTable = DBTableBuilder.toTable(this.DBConnection);
// copy all table's rows
for (ModelDatabaseRow row : table.getRows()) {
List<String> values = new ArrayList<String>();
for (String columnName : columns.keySet()) {
String columnValue = row.getColumn(columnName);
values.add(columnValue);
}
DBTable.addRow(values.toArray());
}
}
}
}
When I try to save the table to the actual database, I get the exception:
java.lang.IllegalArgumentException: invalid fixed length size
at com.healthmarketscience.jackcess.ColumnBuilder.validate(ColumnBuilder.java:361)
at com.healthmarketscience.jackcess.impl.TableCreator.validate(TableCreator.java:207)
at com.healthmarketscience.jackcess.impl.TableCreator.createTable(TableCreator.java:130)
at com.healthmarketscience.jackcess.impl.DatabaseImpl.createTable(DatabaseImpl.java:954)
at com.healthmarketscience.jackcess.TableBuilder.toTable(TableBuilder.java:223)
at modelDatabase.AccessModelDatabaseBuilder.dumpDB(AccessModelDatabaseBuilder.java:153)
at modelDatabase.AccessModelDatabaseBuilder.main(AccessModelDatabaseBuilder.java:37)
DataTypes were saved before using the same database I am writing (I am basically updating the database), using the code:
for (Column column : DBTable.getColumns()) {
table.addColumn(column.getName(), column.getType(), "");
}
What am I doing wrong?
From the Jackcess forum thread, the solution is to wrap the call to setMaxLength() method:
if(dt.isVariableLength()) {
cb.setMaxLength();
}
Since the program is too large I'll just paste the important parts of code. Here's the problem:
I have two JTables. First one collects data from DB and displays the list of all invoices stored in DB. The purpose of the second table is when you click on one row from the table, event handler needs to collect integer from column ID. Using this ID the second table will then display all the contest of that invoice (all the products stored in it).
First and second table work perfectly. The problem is that I have no idea how can I collect certain data (I basically just need ID column) from a selected row and then through a method I already made update the second JTable with new info. Here's my code if it helps:
(PS: once I learn how to do that, will the list on the left change every time by default when I select different row, or do I need to use validate/revalidate methods?)
public JPanel tabInvoices() {
JPanel panel = new JPanel(new MigLayout("", "20 [grow, fill] 10 [grow, fill] 20", "20 [] 10 [] 20"));
/** Labels and buttons **/
JLabel labelInv = new JLabel("List of all invoices");
JLabel labelPro = new JLabel("List of all products in this invoice");
/** TABLE: Invoices **/
String[] tableInvTitle = new String[] {"ID", "Date"};
String[][] tableInvData = null;
DefaultTableModel model1 = new DefaultTableModel(tableInvData, tableInvTitle);
JTable tableInv = null;
/** Disable editing of the cell **/
tableInv = new JTable(model1){
public boolean isCellEditable(int r, int c) {
return false;
}
};
/** Load the invoices from DB **/
List<Invoice> listInv = is.getAllInvoices();
for (int i = 0; i < listInv.size(); i++) {
model1.insertRow(i, new Object[] {
listInv.get(i).getID(),
listInv.get(i).getDate()
});
}
/** TABLE: Invoice Info **/
String[] tableInfTitle = new String[] {"ID", "Name", "Type", "Price", "Quantity"};
String[][] tableInfData = null;
DefaultTableModel model2 = new DefaultTableModel(tableInfData, tableInfTitle);
JTable tableInf = null;
/** Disable editing of the cell **/
tableInf = new JTable(model2){
public boolean isCellEditable(int r, int c) {
return false;
}
};
/** Load the products from DB belonging to this invoice **/
List<Product> listPro = is.getInvoiceInfo(1); // Here's where I need the ID fetched from selected row. For now default is 1.
for (int i = 0; i < listPro.size(); i++) {
model2.insertRow(i, new Object[] {
listPro.get(i).getID(),
listPro.get(i).getName(),
listPro.get(i).getType(),
listPro.get(i).getPrice(),
listPro.get(i).getQuantity()
});
}
/** Scroll Panes **/
JScrollPane scrollInv = new JScrollPane(tableInv);
JScrollPane scrollPro = new JScrollPane(tableInf);
panel.add(labelInv);
panel.add(labelPro, "wrap");
panel.add(scrollInv);
panel.add(scrollPro);
return panel;
}
For now, the right table only displays content of the first invoice:
With the help of following code you can get the value of selected clicked cell, so you just have to click on ID cell value (the Invoicee ID whose Products you want to see in second table) and with the help of following event handler you will get the value and then you can get data based on that ID and set to second table. (In the code below, table is the object of your first table)
(Off-course you will have to apply some validation too, to check that the selected (and clicked) cell is ID not the DATE)
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int row = table.rowAtPoint(e.getPoint());
int col = table.columnAtPoint(e.getPoint());
Object selectedObj = table.getValueAt(row, col);
JOptionPane.showMessageDialog(null, "Selected ID is " + selectedObj);
}
});
I'm trying to populate a table with data from a database however i am having some issues with it. Could someone provide me with an example? (so the table takes in an Object[][] parameter for the data). I have the following basic code to display a table ;
class table extends JFrame
{
JTable table;
public table()
{
setLayout(new FlowLayout());
String[] columnNames = {"test","test","test"};
Object[][] data= {{"test","test","test"},{"test","test","test"}};
table = new JTable(data,columnNames);
table.setPreferredScrollableViewportSize(new Dimension(500,100));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
}
Two years ago, during my time in technical school, I wrote a little library help solve some of the problems proposed by the exercises, which included a a DatabaseTableModel.
The class extends from AbstractTableModel, which means you can set it as the your JTable's data source.
Here's the algorithm that constructs a model from a ResultSet:
public final void constructModel(ResultSet rs) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
rs.last();
rowCount = rs.getRow();
int columnCount = rsmd.getColumnCount();
// DatabaseColumn simply holds a name and a Class<?>.
columns = new DatabaseColumn[columnCount];
// This is the Object[][] array that you were talking about.
// It holds all the data from the ResultSet.
data = new Object[columnCount][rowCount];
for (int i = 0; i < columnCount; ++i) {
// Figure out the column name and type.
int j = i + 1;
String colName = rsmd.getColumnLabel(j);
Class<?> colClass = String.class;
try {
colClass = Class.forName(rsmd.getColumnClassName(j));
} catch (ClassNotFoundException ex) {
colClass = String.class;
}
columns[i] = new DatabaseColumn(colName, colClass);
// Get the data in the current column as an Object.
rs.beforeFirst();
for (int k = 0; rs.next(); ++k) {
data[i][k] = rs.getObject(j);
}
}
// Notify listeners about the changes so they can update themselves.
fireTableStructureChanged();
}
The class worked when I used it in school, but it isn't exactly production code. When I look at it today, I start to see problems.
One problem is that it is loading the entire contents of the ResultSet into memory. Could get ugly pretty quickly.
Also, the algorithm isn't exactly optimal. It loops around with the database cursor as if it was nothing; I suppose that it would be less costly for the database if it had retrieved all the objects in the current row first and assigned them to their appropriate columns before moving on to the next row.
Nevertheless, I think it is a good enough starting point.