I am working on netbeans and creating a swing application. I have created a JComboBox and a JTable. I am able to add value from JComboBox to JTable on a button click but if I repeat the same process the same value is again again added to the table. How to stop adding the existed value of JComboBox.
This is the code of JComboBox
private void populateCombo(){
organizationComboBox.removeAllItems();
for (Organization.Type type : Organization.Type.values()){
organizationComboBox.addItem(type);
}
}
This is the code of JTable
private void populateTable(){
DefaultTableModel model = (DefaultTableModel) organizationTable.getModel();
model.setRowCount(0);
for (Organization organization : organizationDirectory.getOrganizationList()){
Object[] row = new Object[2];
row[0] = organization.getOrganizationID();
row[1] = organization.getName();
model.addRow(row);
}
}
This is the code for my add button
Type type = (Type) organizationComboBox.getSelectedItem();
Organization o = organizationDirectory.createOrganization(type);
if(type.equals(Type.Receptionist)){
o.getSupportedRole().add(new ReceptionistRole());
}else
if(type.equals(Type.Doctor)){
o.getSupportedRole().add(new DoctorRole());
}else
if(type.equals(Type.VaccineManager)){
o.getSupportedRole().add(new VaccineManagerRole());
}else
if(type.equals(Type.LabAssistant)){
o.getSupportedRole().add(new LabAssistantRole());
}else
if(type.equals(Type.Donor)){
o.getSupportedRole().add(new DonorRole());
}else
if(type.equals(Type.Patient)){
o.getSupportedRole().add(new PatientRole());
}
populateTable();
Thanks in advance.
Don't use DefaultTableModel. This class is only for simple cases and demo applications. Simply look here for example of your own model.
So your model will looks like:
public class OrganizationModel extends AbstractTableModel {
protected String[] columnNames;
protected List<Organization> dataVector;
public OrganizationModel(String[] columnNames) {
this.columnNames = columnNames;
dataVector = new ArrayList<Organization>();
}
public String getColumnName(int column) {
return columnNames[column];
}
public boolean isCellEditable(int row, int column) {
return false;
}
public Class getColumnClass(int column) {
return String.class;
}
public Object getValueAt(int row, int column) {
return column == 0? dataVector.get(row).getOrganizationID() : dataVector.get(row).getName();
}
public void addRowWhenNotExist(Organization o) {
if (!dataVector.contains(o)) {
dataVector.add(o);
fireTableRowsInserted(dataVector.size() - 1, dataVector.size() - 1);
}
}
}
For correct working of this example you also need correct definition of methods equals and hashCode for your class Organization.
public class Organization {
// your stuff
public boolean equals(Object another) {
if (another instanceof Organization) {
return getOrganizationID() == ((Organization) another).getOrganizationID();
} else {
return false;
}
}
public int hashCode() {
return getOrganizationID();
}
}
Related
I would like to know how to set up a JComboBox in a particular cell in a JTable.
I have seen people using TableColumn setCellEditor(new DefaultCellEditor(comboBox)).
But this is for an entire column, I would like a specific cell.
So maybe I should do a custom TableCellEditor that would fit my needs, but I am a little lost on how to do it...
The goal of this is to manage filters on parameters. There are two kinds of filters:
The one that compares two values, for instance: number of balloons > 5
The one that will say is a value is inside a range of value, for instance: parameter name is inside {"one", "two", "three", "seven"}.
screenshot of my JTable:
As we can see in the picture, when there is the "comparator" "is among", we would need a JComboBox in cell[0][2] to choose the values of the range within a complete set of fields.
While cell[1][2] does not need a JComboBox, but just an editable cell.
I hope I have been clear and thank you for your help.
EDIT:
I was able to display a JComboBox only to realize, I couldn't select multiple values on it. So now I am trying to display a JList instead of a ComboBox.
But when I click on the cell, the JList is not displayed, I don't know why.
Here is my code:
JTable tableParametersFilter = new JTable(modelParametersFilter){
// Determine editor to be used by row
public TableCellEditor getCellEditor(int row, int column)
{
int modelColumn = convertColumnIndexToModel( column );
int modelRow = convertRowIndexToModel( row );
Parameter_Filter pf = view.listParameter_Filter.get(modelRow);
if(modelColumn == 2 && pf instanceof Parameter_Filter_To_List_Of_Fields) {
Parameter_Filter_To_List_Of_Fields pftlof = (Parameter_Filter_To_List_Of_Fields)pf;
JList<String> list = new JList<String>(pftlof.list_of_fields_total_names);
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
list.setLayoutOrientation(JList.VERTICAL_WRAP);
list.setVisibleRowCount(-1);
return new TableCellEditor() {
#Override
public boolean stopCellEditing() {
return false;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return false;
}
#Override
public void removeCellEditorListener(CellEditorListener l) {
}
#Override
public boolean isCellEditable(EventObject anEvent) {
return true;
}
#Override
public Object getCellEditorValue() {
return list.getSelectedValuesList().toString();
}
#Override
public void cancelCellEditing() {
}
#Override
public void addCellEditorListener(CellEditorListener l) {
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
return list;
}
};
}
return super.getCellEditor(row, column);
}
};
Any suggestions?
I have solved my problem.
I have not been able to add multiple choice JComboBox, or a displayable JList on the Cell of the Jtable.
Instead, I have used a JOptionPane that displayed a JList.
Here's the code:
tableParametersFilter.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
JTable target = (JTable)e.getSource();
int row = target.getSelectedRow();
int column = target.getSelectedColumn();
if(column == 2){
Parameter_Filter pf = view.listParameter_Filter.get(row);
if(pf instanceof Parameter_Filter_To_List_Of_Fields) {
Parameter_Filter_To_List_Of_Fields pftlof = (Parameter_Filter_To_List_Of_Fields) pf;
JList<String> jlist = new JList<String>(pftlof.list_of_fields_total_names);
String StringOfIntArray = (String) tableParametersFilter.getValueAt( row, 2);
int[] list_parameter_id = Statique.StringOfIntArrayToIntegerArray(StringOfIntArray);
if(list_parameter_id.length < jlist.getModel().getSize()) {
int[] list_places = pftlof.getPlaceOfParameters(list_parameter_id);
for(int i = 0; i < list_places.length; i++) {
jlist.setSelectedIndices(list_places);
}
}
JScrollPane scrollPane = new JScrollPane(jlist);
scrollPane.setPreferredSize( new Dimension( 500, 500 ) );
JOptionPane.showMessageDialog(
null, scrollPane, "Multi-Select Example", JOptionPane.PLAIN_MESSAGE);
int[] SelectedIndices = jlist.getSelectedIndices();
Integer[] listParametersId = new Integer[SelectedIndices.length];
for(int i = 0; i < SelectedIndices.length; i++) {
int id = pftlof.list_of_fields_Total[SelectedIndices[i]].id;
try {
Parameter p = Parameter.getParameter(
id,
Parameter_Filter_To_List_Of_Fields.getTotal_Parameter_In_Parameter_Filter_To_List_Of_Fields());
listParametersId[i] = p.id;
} catch (NoSuchFieldException e1) {
e1.printStackTrace();
}
}
System.out.println(Arrays.toString(listParametersId));
tableParametersFilter.setValueAt(Arrays.toString(listParametersId), row, 2);
}
}
}
}
I am trying to add a JButton as the first column on the table I created. I did make a research and couldn't find any solution for the tables that use abstract table model.
Here, I create an object array for each record that has texts and boolean variables to have the table render check boxes. Then those object arrays saved into an ArrayList
Here's my code to create my table data.
public ArrayList<Object[]> setTableData(){
/*
* ItemInfo fields
**********************
* line[0] - ReferenceNo
* line[1] - Quantity
* line[2] - ItemNameDescriptionSKU
* line[3] - Cube
*/
//Setting the data for the table
ArrayList<Object[]> itemList = new ArrayList<>();
for (int i=0; i<this.itemInfo.size();i++){
Object[] tempArray = new Object[7];
tempArray[0] = this.itemInfo.get(i)[1]; //Quantity
tempArray[1] = this.itemInfo.get(i)[2].toUpperCase(); //Item description
tempArray[2] = this.itemInfo.get(i)[3]; //Cube
//This adds charges if the payment type is COD
//To not to write the charge amount for every row
//checks the COD type only at the first record of items
if (i==0 && this.invoice[8].equals("COD"))
tempArray[3] = this.invoice[22]; //Charges if the invoice type is COD, null otherwise
else
tempArray[3] = " ";
tempArray[4] = new Boolean (false); //Loaded
tempArray[5] = new Boolean (false); //Delivered (Will be ignored if pickup)
itemList.add(tempArray);
}
return itemList;
Here's my table model
import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;
public class TicketTableModel extends AbstractTableModel {
private ArrayList<Object[]> data;
private boolean isDelivery;
private String[] columns;
public TicketTableModel(ArrayList<Object[]> itemInfo, boolean isDelivery){
super();
this.data = itemInfo;
this.isDelivery = isDelivery;
}
#Override
public String getColumnName(int i) {
return this.columns[i];
}
public void setColumns ( String[] columns1 ){
this.columns = columns1;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return columns.length;
}
#Override
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
if (col < 3)
return false;
else
return true;
}
#Override
public void setValueAt(Object value, int row, int col) {
data.get(row)[col] = value;
fireTableCellUpdated(row, col);
}
#Override
public Object getValueAt(int row, int col) {
return this.data.get(row)[col];
}
Take a look at Table Button Column.
This class implements the render/editor needed to make the button functional. You also provide the Action to invoke when the button is pressed.
The type of TableModel is irrelevant. If you want to "show" a button on a JTable, you supply a TableCellRenderer (and probably a TableCellEditor) for the column which is capable of rendering the button based on the values of the column it represents.
This will mean that your TableModel will need to support a column within it's model which represents the button.
Take a closer look at Using Custom Renderers, Using Other Editors and How to Use Tables
The example i have found:
http://www.java2s.com/Code/Java/Swing-Components/ButtonTableExample.htm
show how to create a JTable with specified column (button). It works properly, but the my problem is, that i need to use AbstractTableModel instead of DefaultTableModel (as at the example shows).
So i created my own TableModel, which extends AbstractTableModel:
public class TableModel extends AbstractTableModel {
//..
}
and replaced:
DefaultTableModel dm = new DefaultTableModel();
dm.setDataVector(new Object[][] { { "button 1", "foo" },
{ "button 2", "bar" } }, new Object[] { "Button", "String" });
JTable table = new JTable(dm);
for:
JTable table = new JTable(new TableModel());
And then nothing happens, when i will click button at some row. Any suggestions?
Make sure you override AbstractTableModel.isCellEditable method to return true for the column with the button otherwise the editor will not be triggered. This method by default returns false.
Also, make sure you override getColumnName() to return proper name since the sample that you linked tries to find a column with name "Button" to setup the editor.
You may find a Table Button Column implementation by #camickr useful.
This demo model works OK with the editor and the renderer from the linked sample:
public class DemoTableModel extends AbstractTableModel {
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return (columnIndex == 0);
}
#Override
public int getRowCount() {
return 2;
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public String getColumnName(int columnIndex) {
switch (columnIndex) {
case 0:
return "Button";
case 1:
return "Value";
}
return null;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return "Button";
case 1:
return "Value";
}
return null;
}
}
I've faced an issue in adding TableModelListener to AbstractTableModel. The program stops working and the JFrame doesn't response for any button-clicking or even closing the JFrame.
What I want is to make a JButton enabled iff the number of rows in myTable is equal or more than 2 rows.
Here is my code ...
My custom Table:
public class MyTable extends JPanel
{
public Main main;
public ArrayList<MyData> lstData;
public JTable table;
public MyTableModel model;
// ...
public MyTable(ArrayList<MyData> lstData, Main main)
{
this.lstData = lstData;
this.main = main;
model = new MyTableModel(lstData);
table = new JTable(model);
// ...
}
// ...
public int getTableSize()
{
return model.getRowCount();
}
public TableModel getModel()
{
return model;
}
public class MyTableModel extends AbstractTableModel
{
protected String[] columnNames = new String[ ] {"#","Name", "Phone Number"};
protected ArrayList<MyData> lstData;
protected Class[] types = new Class[]{String.class, String.class, String.class};
public MyTableModel(ArrayList<MyData> lstData)
{ this.lstData = lstData; }
public void SetData(ArrayList<MyData> lstData)
{ this.lstData = lstData; fireTableDataChanged(); }
#Override
public String getColumnName(int columnIndex)
{ return columnNames[columnIndex]; }
#Override
public Class getColumnClass(int columnIndex)
{ return types[columnIndex]; }
public Object getValueAt(int row, int column)
{
if (row < 0 || row > lstData.size()) return null;
MyData obj = lstData.get(row);
switch(column)
{
case 0: return obj.getID();
case 1: return obj.getName();
case 2: return obj.getPhoneNumber();
default: return null;
}
}
public int getRowCount() { return lstData.size(); }
public int getColumnCount() { return columnNames.length; }
}
}
Main class:
public class Main extends JFrame implements TableModelListener
{
public static ArrayList<myData> lstData;
public static MyTable table;
public static JButton myButton;
public Main()
{
// ...
table = new MyTable(lstData, this);
table.getModel().addTableModelListener(this);
myButton = new JButton();
myButton.setEnabled(false);
// ...
}
// ...
public void tableChanged(TableModelEvent e)
{
int firstRow = e.getFirstRow();
int lastRow = e.getLastRow();
int mColIndex = e.getColumn();
switch(e.getType())
{
case TableModelEvent.INSERT:
if(table.getTableSize() >= 2) myButton.setEnabled(true);
else myButton.setEnabled(false);
break;
case TableModelEvent.DELETE:
if(table.getTableSize() >= 2) myButton.setEnabled(true);
else myButton.setEnabled(false);
break;
}
}
}
Could you help me to solve this issue? Thanks in advance.
EDIT:
The GUI stop responding only if I add or delete elements from the table.
EDIT2:
No errors or exceptions are thrown after I add elements to the table, it's just freezing the gui with no response
basic tutorial about TableModelListener here or here or here
best would be camickr Table Cell Listener that implements deepest funcionalities for Listening in the TableCell
In your MyTableModel class, remove the following line:
protected TableModel model = this;
And also remove the following methods:
public void setModel(TableModel model){
this.model = model;
}
public TableModel getModel() {
return model;
}
You are already implementing a custom table model, there is no need to create that self reference inside of it. When your class is getting instantiated the this variable is not fully initialized and I suspect that is what is causing problems for you. But in any case the code is definitely not needed. Also, in your MyTable class I would recommend changing the getModel() function to defer to your wrapped table variable. Like so:
public TableModel getModel() {
return model.getModel();
}
Thank you guys for your help, I solve this issue by modifying the tableChanged method:
public void tableChanged(TableModelEvent e)
{
if(table.getTableSize() >= 2) myButton.setEnabled(true);
else myButton.setEnabled(false);
}
This is my first time asking here so forgive me if something isn't appropriate, and sorry if my English isn't very good.
Well, to make it short, currently I'm developing a Java desktop app with Swing and I have a problem using table. I have rows with each row have a button to delete the row. Everything is okay (i can delete rows with no problem) until i try to delete the last row. The last row can be deleted but apparently there is an exception, something like this:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 4 >= 4
at java.util.Vector.elementAt(Vector.java:427)
at javax.swing.table.DefaultTableModel.setValueAt(DefaultTableModel.java:648)
at javax.swing.JTable.setValueAt(JTable.java:2710)
at javax.swing.JTable.editingStopped(JTable.java:4712)
at javax.swing.AbstractCellEditor.fireEditingStopped(AbstractCellEditor.java:125)
From the stack trace, it seems that "4" is my previously deleted last row index, but i have no idea how to deal with this. I already search for solution but i still can't solve it. Note that there are still other rows when i delete the last row, and after that i can't delete the others rows. The same exception also resulted when i click the delete button.
Oh. and I use removeRow() from DefaultTableModel to delete the row. Any help will be appreciated. Thanks.
EDIT
These are the code I use.
public class ViewDetail extends JInternalFrame implements ActionListener {
...
String column[] = { "Aaa", "Bbb", "Delete This"};
tableModel = new DefaultTableModel();
Object row[][] = new Object[size][column.length];
//fill the data from db
int r = 0;
for (int i = 0; i < size; i++) {
row[r][0] = ...;
row[r][1] = ...;
row[r][2] = "Delete";
r++;
}
tableModel.setDataVector(row, column);
table = new JTable(tableModel);
tableColumn = table.getColumn("Aaa");
tableColumn.setPreferredWidth(75);
tableColumn = table.getColumn("Bbb");
tableColumn.setPreferredWidth(75);
tableColumn = table.getColumn("Delete This");
tableColumn.setPreferredWidth(75);
tableColumn.setCellRenderer(new ButtonRenderer());
tableColumn.setCellEditor(new ButtonEditor(new JCheckBox());
...
}
public class ButtonRenderer extends JButton implements TableCellRenderer {
public ButtonRenderer() {
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(UIManager.getColor("Button.background"));
}
setText((value == null) ? "" : value.toString());
return this;
}
}
public class ButtonEditor extends DefaultCellEditor {
protected JButton button;
private String label;
private boolean isPushed;
private JTable table;
public ButtonEditor(JCheckBox checkBox) {
super(checkBox);
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (isSelected) {
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
label = (value == null) ? "" : value.toString();
button.setText(label);
isPushed = true;
this.table = table;
return button;
}
public Object getCellEditorValue() {
if (isPushed) {
DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
tableModel.removeRow(table.getSelectedRow());
}
isPushed = false;
return new String(label);
}
public boolean stopCellEditing() {
isPushed = false;
return super.stopCellEditing();
}
protected void fireEditingStopped() {
super.fireEditingStopped();
}
}
Swing is trying to set the new value into the row you remove! Try moving the remove code into a Runnable and use invokeLater in the swing utility class to execute it.
could you post the code where you init, add elements and delete in your JTable?
My first guess is that you are either doing the classical mistake
"I have 4 elements in my table so to delete the last one I remove(4)" when you your table goes from 0 to 3 in indices
or you are trying to remove several object in the same loop like
for(int i = 0; i<lenght; i++){
if(i%2==0){//every even number
tab.remove(i);
}
}
then your are modifying the size of your table, the elements are shifted but your not taking it in account when removing.
those are just guesses/pointer to what might cause the problem. please post your code if this doesn't solve it
The Table Button Column shows how you can render a column as a button and how to add an Action that is executed when the button is clicked. The example Action just happens to show how to delete a row.
Here you need to remove only 0 th row that should be iterated
private void refreshTable() {
int rowCount= model.getRowCount();
// System.out.println(rowCount);
for(int i=0;i<rowCount;i++ ){
model.removeRow(0);
//System.out.println(i);
}
}
you can add new vaiable and check to fireEditingStopped() :
public class ButtonEditor extends DefaultCellEditor {
//create new variable
private boolean isDeleteRow = false;
/////////////////
protected JButton button;
private String label;
private boolean isPushed;
private JTable table;
public ButtonEditor(JCheckBox checkBox) {
super(checkBox);
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (isSelected) {
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
label = (value == null) ? "" : value.toString();
button.setText(label);
isPushed = true;
this.table = table;
// set false when click to button
isDeleteRow = false;
/////////////////
return button;
}
public Object getCellEditorValue() {
if (isPushed) {
// set true when isPushed button
isDeleteRow = true;
/////////////////
}
isPushed = false;
return new String(label);
}
public boolean stopCellEditing() {
isPushed = false;
return super.stopCellEditing();
}
protected void fireEditingStopped() {
super.fireEditingStopped();
//check if isDeleteRow, remove row
if(isDeleteRow)
{
DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
tableModel.removeRow(table.getSelectedRow());
}
/////////////////
}
}