I'm able to create a JTable with cells rendered to use JList. What I don't know to do is to create different lists to add to cells.
This is my code right now
Vector<String> categoryReportColumnNames = new Vector<>();
categoryReportColumnNames.add("Categorías");
categoryReportColumnNames.add("Ítems");
Vector<Vector<String>> categoryReportVector = controller.getCategoryReportVector();
VectorTableCellRenderer renderer = new VectorTableCellRenderer();
DefaultTableModel tableModel = new DefaultTableModel(categoryReportVector, categoryReportColumnNames);
jCategoryReportTable.setModel(tableModel);
jCategoryReportTable.setEnabled(false);
for (int i = 0 ; i < categoryReportVector.size() ; i++){
Vector<String> categoryItems = controller.getCategoryItems(i);
renderer.setListData(categoryItems);
jCategoryReportTable.getColumnModel().getColumn(i).setCellRenderer(renderer);
}
jCategoryReport.setVisible(true);
Where should I send a Vector, for example, to change JList items for each row?
Thanks
It can do better way as follows. You should not set the renderer within a loop. Only thing you should create the data vector correctly.
Modifications of your code
//create table columns
Vector<String> categoryReportColumnNames = new Vector<>();
categoryReportColumnNames.add("Categorías");
categoryReportColumnNames.add("Ítems");
//create table data
Vector<Vector> categoryReportVector = controller.getDataVector();
//setting the tabel model
DefaultTableModel tableModel = new DefaultTableModel(categoryReportVector, categoryReportColumnNames);
jCategoryReportTable.setModel(tableModel);
//setting the table renderer
VectorTableCellRenderer renderer = new VectorTableCellRenderer();
jCategoryReportTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
//additional modifications
jCategoryReportTable.setEnabled(false);
jCategoryReportTable.setRowHeight(100);
Create Data Vector as follows.
Use loops and create your own code referring this
public Vector<Vector> getDataVector() {
Vector rowOne = new Vector<String>();
rowOne.add("Row1-Column1");
Vector rowOneCategories = new Vector();
rowOneCategories.add("Row1-Column2-Line1");
rowOneCategories.add("Row1-Column2-Line2");
rowOneCategories.add("Row1-Column2-Line3");
rowOne.add(rowOneCategories);
Vector rowTwo = new Vector<String>();
rowTwo.add("Row2-Column1");
Vector rowTwoCategories = new Vector();
rowTwoCategories.add("Row2-Column2-Line1");
rowTwoCategories.add("Row2-Column2-Line2");
rowTwoCategories.add("Row2-Column2-Line3");
rowTwo.add(rowTwoCategories);
Vector<Vector> rowData = new Vector<Vector>();
rowData.add(rowOne);
rowData.add(rowTwo);
return rowData;
}
Related
I have a simple Java Desktop application that show a JTable with a custom TableModel.
In base of a boolean variables, I want to show a Table with different column.
But I'm not able to do this.
This is my code:
static String[] ColName = { "Cod.Articolo","Nome Articolo","Cod.Barre", "Qtà.iniziale","Scontrini(-)","Bolla(-)","Fattura(-)","DDT(-)","NC(+)","Carico(+)"};
static String[] ColNameNero = { "Cod.Articolo","Nome Articolo","Cod.Barre", "Qtà.iniziale","Scontrini(-)","Scontrini Nero(-)","Bolla(-)","Fattura(-)","DDT(-)","NC(+)","Carico(+)"};
public void creaTabellaMerci(boolean isNero){
try{
if(isNero)
tableMovimentiMagazzinoMerci = new MyTableModelMovimentiMagazzinoMerci(ColNameNero,isNero);
else
tableMovimentiMagazzinoMerci = new MyTableModelMovimentiMagazzinoMerci(ColName,isNero);
tableMovimentiMerci = new DefaultTableCustom(tableMovimentiMagazzinoMerci);
sorter = new TableRowSorter<MyTableModelMovimentiMagazzinoMerci>(tableMovimentiMagazzinoMerci);
tableMovimentiMerci.setRowSorter(sorter);
jScrollPaneAmministrazione = new javax.swing.JScrollPane();
jScrollPaneAmministrazione.setViewportView(tableMovimentiMerci);
jScrollPaneAmministrazione.setPreferredSize(dTabella2);
jScrollPaneAmministrazione.getViewport().add(tableMovimentiMerci);
tableMovimentiMagazzinoMerci.fireTableDataChanged();
tableMovimentiMerci.repaint();
}catch(Exception e){
log.logStackTrace(e);
}
}
Now at first time, I call the method with variables isNero = true. At the second time, I call the same method with variables isNero = false but the columns not changes.
How can I fix it ?
jScrollPaneAmministrazione = new javax.swing.JScrollPane();
You create a new JScrollPane, but you never add the scroll pane to the frame. Changing the value of the reference variable does NOT add the component to the frame.
Don't create a new JTable or JScrollPane!
Instead you can just update the TableModel of the table that is currently display on the frame:
//tableMovimentiMerci = new DefaultTableCustom(tableMovimentiMagazzinoMerci);
tableMovimentiMerci.setModel( tableMovementiMagazzinoMerci );
sorter = new TableRowSorter<MyTableModelMovimentiMagazzinoMerci>(tableMovimentiMagazzinoMerci);
tableMovimentiMerci.setRowSorter(sorter);
//jScrollPaneAmministrazione = new javax.swing.JScrollPane();
//jScrollPaneAmministrazione.setViewportView(tableMovimentiMerci);
//jScrollPaneAmministrazione.setPreferredSize(dTabella2);
//jScrollPaneAmministrazione.getViewport().add(tableMovimentiMerci);
//tableMovimentiMagazzinoMerci.fireTableDataChanged();
//tableMovimentiMerci.repaint();
I created a JTable and inserted the column header and data into the table.
data is vector of vectors
column_header is vector of string
This is the code:
Vector<Diagnosis_data> Arraylist_object = new Vector<Diagnosis_data>();
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
Diagnosis_data d1 = new Diagnosis_data("92992","1",1422-09-09,1422-09-18,E11.9,"Type 2 diabetes mellitus without complications");
Diagnosis_data d2 = new Diagnosis_data("8199111","2",1415-09-09,1415-09-18,E11.622,"Type 2 diabetes mellitus with other skin ulcer");
Arraylist_object.add(d1);
Arraylist_object.add(d2);
int f = 0;
while(f < Arraylist_object.size())
{
Vector<Object> vector = new Vector<Object>();
for(; f < Arraylist_object.size() ; f++)
{
vector.add(Arraylist_object.get(f).patient_ID);
vector.add(Arraylist_object.get(f).Ad_ID);
vector.add(Arraylist_object.get(f).Ad_start);
vector.add(Arraylist_object.get(f).Ad_End);
vector.add(Arraylist_object.get(f).Diagnosis_code);
vector.add(Arraylist_object.get(f).Diagnosis_Des);
data.add(vector);
}
}
DefaultTableModel tableModel = new DefaultTableModel(data,column_header);
JTable table_2 = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(table_2);
scrollPane.setBounds(1, 1, 1050, 500);
panel_1.add(scrollPane);
The result is:
The code you posted is working given the correct data - the problem must be the data. Use a debugger to check it or, just for testing, print out the content of data.
Probably the same Vector is being added to data multiple times or the content of each Vector is same (maybe the Patient object is using static fields?)
Note: data I used to test your code - a new Vector must be created for each row:
Vector<Vector<?>> data = new Vector<>();
Vector<String> column_header = new Vector<>();
column_header.addAll(Arrays.asList("A", "B", "C"));
Vector<String> row;
row = new Vector<>();
row.addAll(Arrays.asList("11", "12", "13"));
data.add(row);
row = new Vector<>();
row.addAll(Arrays.asList("21", "22", "23"));
data.add(row);
row = new Vector<>();
row.addAll(Arrays.asList("31", "32", "33"));
data.add(row);
EDIT: After the generating data code has been added, it is clear that the problem is, as I suspected above: "the same Vector is being added".
Look at this part:
Vector<Object> vector = new Vector<Object>();
for(; f < Arraylist_object.size() ; f++)
{
vector.add(...);
data.add(vector);
}
The vector is created only once OUTSIDE the loop, but being added multiple time inside the loop.
Solution: create the vector INSIDE the loop
And there is no need for the additional while, actually the convention is to declare the variable in the for loop (and use i as counter):
for(int i = 0; i < Arraylist_object.size() ; i++)
{
Vector<Object> vector = new Vector<Object>();
vector.add(Arraylist_object.get(i).patient_ID);
...
data.add(vector);
}
or use foreach:
for (Diagnosis_data diagnosis : Arraylist_object)
{
Vector<Object> vector = ...
vector.add(diagnosis.patient_ID);
vector.add(diagnosis.Ad_ID);
...
}
Advice: spend some time learning to use a debugger, it will not be wasted if you want to do serious programming.
Advice2: as commented by Andrew Thompson, use LayoutManager's instead of using constant coordinates to layout your components. Tutorial: Laying Out Components Within a Container
I create the JTable with data contained in an ArrayList and then add the JTable to a JScrollPane
ArrayList<Product> stock = new ArrayList<Product>(s);
String[] col = {"Nombre", "Cantidad", "Descripci\u00F3n", "Contenido"};
DefaultTableModel tableModel = new DefaultTableModel(col,0);
JTable table = new JTable(tableModel);
Collections.sort(stock, new Comparator<Product>() {
public int compare(Product p1, Product p2) {
return p1.getNombre().compareTo(p2.getNombre());
}
});
for (int i = 0; i < stock.size(); i++){
String nombre = stock.get(i).getNombre();
String cantidad = stock.get(i).getCantidad();
String descripcion = stock.get(i).getDescripcion();
String contenido = stock.get(i).getContenido();
Object[] data = {nombre, cantidad, descripcion, contenido};
tableModel.addRow(data);
}
table.getColumnModel().getColumn(0).setPreferredWidth(width*3/18);
table.getColumnModel().getColumn(1).setPreferredWidth(width/9);
table.getColumnModel().getColumn(2).setPreferredWidth(width*8/18);
table.getColumnModel().getColumn(3).setPreferredWidth(width/9);
frame.getContentPane().setLayout(new BorderLayout(0, 0));
table.getTableHeader().setFont(new Font("Arial", Font.BOLD, f));
table.setFont(new Font("Arial", Font.PLAIN, f));
table.setBounds(1, 1, width*8/9, height);
table.setRowHeight(height/30);
table.setEnabled(false);
DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
centerRenderer.setHorizontalAlignment( JLabel.CENTER );
for(int i = 0; i<4; i++){
table.getColumnModel().getColumn(i).setCellRenderer( centerRenderer);
}
JScrollPane sp = new JScrollPane(table);
frame.getContentPane().add(sp, BorderLayout.CENTER);
And then through a JButton I modify the contents of the ArrayList, then tell the TableModel that changes have been made and then revalidate() and repaint() the JTable
JButton btnVender = new JButton("Vender");
btnVender.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String n = JOptionPane.showInputDialog("Qué producto quieres vender?");
int x=1;
for(Product p : stock){
if(p.getNombre().equals(n)){
x=0;
String numero = JOptionPane.showInputDialog("Cuántos quieres vender?");
int num = Integer.parseInt(numero);
p.decrementar(num);
tableModel.fireTableDataChanged();
table.revalidate();
table.repaint();
break;
}
}
if(x==1){
JOptionPane.showMessageDialog(null, "No existe ese producto");
}
}
});
The problem is that the JTable won't update but the information does change in the ArrayList
The data for the JTable is not held in the ArrayList but rather resides in the table model itself. Bottom line: don't update the ArrayList but rather the table model itself, here a DefaultTableModel, and your JTable should then display the new data. Fortunately this should be easy to do as the table model has methods that allow you to extract data with getValueAt(...) and update values in its cells with setValueAt(...) as well as addRow(...) if a new row needs to be added.
Note that if you make changes through the DefaultTableModel, there's no need to directly call fireTableDataChanged(), and in fact you shouldn't call this method -- it's the model's responsibility to do so. Likewise there's no need to revalidate() or repaint() your JTable.
Please check out the DefaultTableModel API for the gory details.
If on the other hand you absolutely need to use the ArrayList as a data nucleus for your JTable, then you shouldn't use a DefaultTableModel but rather create your own TableModel by extending AbstractTableModel and using your ArrayList as its data nucleus. If you do this, then your model's code should take care to call the appropriate fire...(...) method after changing the model's state.
The code below displays 2 JTables.
As they both will have exactly the same headers I wanted, for the sake of efficiency, to reuse the header from the first table.
However running the code results in the header appearing in the second table but not in the table it came from originally.
I am less interested in work-arounds, but - for the sake of learning and understanding - more interested in finding out why the header does not appear in the first table.
Here is the code:
public class HeaderTest1 {
public void doTheTest() {
JFrame testFrame = new JFrame("Header Test");
JPanel pane = new JPanel();
Container theContentPane = testFrame.getContentPane();
BoxLayout box = new BoxLayout(pane, BoxLayout.Y_AXIS);
pane.setLayout(box);
theContentPane.add(pane);
String theData[][]
= {
{"One", "two", "3"},
{"four", "5", "six"},
{"7", "8", "9.0"},
{"£10.00", "11", "twelve"}
};
String columnNames[] = {"Column 1", "Column 2", "Column 3"};
JTable firstTable = new JTable(theData, columnNames);
JScrollPane thisScrollPane = new JScrollPane(firstTable);
JTableHeader thisTableHeader = firstTable.getTableHeader();
pane.add(thisScrollPane);
buildTheSecondTable(thisTableHeader, firstTable, columnNames, pane);
testFrame.pack();
testFrame.setVisible(true);
}
private void buildTheSecondTable(JTableHeader headerFromTheFirstTable,
JTable firstTable, String[] columnNames, JPanel pane) {
JTable secondTable = new JTable();
int columnCount = columnNames.length;
JScrollPane thisScrollPane = new JScrollPane(secondTable);
secondTable.setTableHeader(headerFromTheFirstTable);
Object[][] emptyData = new Object[1][columnCount];
for (int n = 0; n < columnCount; n++) {
emptyData[0][n] = "";
}
DefaultTableModel thisTableModel = new DefaultTableModel();
thisTableModel.setDataVector(emptyData, columnNames);
secondTable.setModel(thisTableModel);
secondTable.setLayout(firstTable.getLayout());
secondTable.setCellEditor(firstTable.getCellEditor());
pane.add(thisScrollPane);
}
public static void main(String[] args) throws SQLException, ParseException {
HeaderTest thisTest = new HeaderTest();
thisTest.doTheTest();
}
Any advice would be appreciated
A Swing component can only have a single parent so you can't share the table header component.
You can however share the Array of column names:
JTable firstTable = new JTable(theData, columnNames);
In your buildTheSecondTable method you have access to the array of column names so just use:
//DefaultTableModel thisTableModel = new DefaultTableModel();
DefaultTableModel thisTableModel = new DefaultTableModel(columnNames);
Then you can add data to the model and the model to the table.
Then reorder the code to create the JScrollPane after you add the model to the table.
Also, get rid of the table.setLayout() code. You would never use a layout manager on a table. You don't add components to the table. The table renders the data itself without using real components.
I'm tinkering with JTables and Vectors for the first time in Java, and I've hit an interesting snag. My code compiles correctly, but when I go to run it, I get the following exception:
Exception in thread "main" java.lang.ClassCastException:
java.lang.String cannot be cast to java.util.Vector
I don't see anywhere where I'm casting, so I'm a bit confused.
Vector<String> columnNames = new Vector<String>();
columnNames.add("Tasks");
Vector<String> testing = new Vector<String>();
testing.add("one");
testing.add("two");
testing.add("three");
table = new JTable(testing, columnNames); // Line where the error occurrs.
scrollingArea = new JScrollPane(table);
My goal is to have a table of JPanels, but I have the same type of error when I try to use a Vector of < taskPanel > Here's the class that extends JPanel:
class taskPanel extends JPanel
{
JLabel repeat, command, timeout, useGD;
public taskPanel()
{
repeat = new JLabel("Repeat:");
command = new JLabel("Command:");
timeout = new JLabel("Timeout:");
useGD = new JLabel("Update Google Docs:");
add(repeat);
add(command);
add(timeout);
add(useGD);
}
}
You need to use a Vector of Vectors here:
Vector<Vector> rowData = new Vector<Vector>();
rowData.addElement(testing);
JTable table = new JTable(rowData, columnNames);
For a multi-column Vector table model, see this example.
Your testing vector should be vector of vectors as each row is supposed to contain data for all columns e.g.
Vector<Vector> testing = new Vector<Vector>();
Vector<String> rowOne = new Vector<String>();
rowOne.add("one");
Vector<String> rowTwo = new Vector<String>();
rowTwo.add("two");
Vector<String> rowThree = new Vector<String>();
rowThree.add("three");
testing.add(rowOne);
testing.add(rowTwo);
testing.add(rowThree);
table = new JTable(testing, columnNames); // should work now
scrollingArea = new JScrollPane(table);
The casting is the < String >. You can't have Vector Strings at the moment. Take a look at this.