conditional jtable background row - java

Hi I have a problem I have a list of Persnäs in a table, also have a list of bad people at a vector and I want to load jtable, poor people are marked in red
tabla= table
conteo= count
the problem of the code that I have is that only one match brand eventhough it has several
tabla.setDefaultRenderer(Object.class, new DefaultTableCellRenderer()
{
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
try {
String sql;
String driver = "org.apache.derby.jdbc.EmbeddedDriver";
String bdd = "616c756d6e6f";
String par = "create=true";
String conexion = "jdbc:derby:" + bdd + ";" + par;
Connection con = DriverManager.getConnection(conexion);
sql="select matricula from bajas";
PreparedStatement st = con.prepareStatement(sql);
ResultSet rs= st.executeQuery();
Vector<String> vec = new Vector<String>();
while(rs.next())
{
vec.addElement(rs.getString("matricula"));
}
con.close();
for(int x=0;x<tabla.getRowCount();x++)
{
int conteo=0;
for(String valor:vec)
{
if(valor.equals(tabla.getValueAt(x, 0)))
{
conteo++;
}
}
if(conteo!=0)
{
final Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(row ==x ? Color.RED:null);
return c;
}
}
} catch (SQLException ex) {
Logger.getLogger(InicioAlumnos.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}

Don't do anything in your renderers that could be time consuming (this is pretty good rule for GUI's generally). EACH cell that the renderer is responsible for could call this renderer (have 1000 lines, expect to be hit 1000 times). Instead, pre-load you "black" list and use the cached values. If you need to, provide a means by which the list can reloaded
Always return a value from the cell renderers, failing to do so may cause other problems.
This...
for(int x=0;x<tabla.getRowCount();x++)
{
int conteo=0;
for(String valor:vec)
{
if(valor.equals(tabla.getValueAt(x, 0)))
{
conteo++;
}
}
Doesn't make sense. A TableCellRenderer is responsible for a individual cell, not the entire table.
Assuming you only want to mark the row that matches your blacklist, you should be using...
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (vec.contains(table.getValueAt(row, 0)) {
setBackground(Color.RED);
}
return this;

Related

JTable ImageIcon and String

I want to create a JTable where in the cells there could be an ImageIcon, String or both. I've already tried solutions like table.setvalue() or just adding the Icon to the Object Array for creating the JTable.
for (int n = 0; n < tableHeight; n++) {
for (int m = 0; m < tableWidth; m++) {
if ((n + m) == labelArray.size()) {
break;
}
if (labelArray.get(n + m).iconMode) { //iconMode is True if there is an icon instead of line text
data[n][m] = null;
} else {
String text = new String("<html><p>" + labelArray.get(n + m).lineOne + "<br>" + labelArray.get(n + m).lineTwo + "<p></html>");
data[n][m] = text;
}
}
}
table = new JTable(data, columnNames);
renderer = new DefaultTableCellRenderer();
renderer.setHorizontalTextPosition(JLabel.CENTER);
renderer.setHorizontalAlignment(JLabel.CENTER);
for (int n = 0; n < tableWidth; n++) {
table.getColumnModel().getColumn(n).setCellRenderer(renderer);
table.getColumnModel().getColumn(n).setWidth(50);
}
there could be an ImageIcon, String or both.
You will need to create a custom object to store in the TableModel. This object will contain two properties:
text
icon
Then you will need to create a custom renderer (not use the default renderer) to display this object.
The custom renderer might look something like:
class CustomRenderer extends DefaultTableCellRenderer
{
public CustomRenderer()
{
super();
setHorizontalTextPosition(JLabel.CENTER);
setHorizontalAlignment(JLabel.CENTER);
}
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
CustomObject custom = (CustomObject)value;
setText( custom.getText() );
setIcon( custom.getIcon() );
return this;
}
}

Unable to get column names as headers into JTable

I have this code that should create my JTable column hearders based on the field names returned from my query. For some reason my code is not working, I am very new to Java and I have been doing research but cant seem to find where my issue is. Any help will be greatly appreciated.
public void initTable(){
try {
DefaultTableModel tblModel = new DefaultTableModel()
{
#Override
public boolean isCellEditable(int row, int column)
{
return false;
}
};
tblMain.setModel(tblModel);
tblMain.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
//tblMain.getTableHeader().setReorderingAllowed(false);
Connection dbconn = dbConn();
Statement stmt = dbconn.createStatement();
String qry = "SELECT * FROM Services";
ResultSet rs = stmt.executeQuery(qry);
int numCols = rs.getMetaData().getColumnCount();
System.out.println("Num Cols: " + numCols);
for (int col = 1; col <= numCols; col++){
tblModel.addColumn(rs.getMetaData().getColumnLabel(col));
//tblModel.addColumn("Tmp");
System.out.println(col + " - " + rs.getMetaData().getColumnLabel(col));
}
int row = 0;
while (rs != null && rs.next()){
tblModel.addRow(new Object[0]);
tblModel.setValueAt(rs.getString("ServiceID"), row, 0);
tblModel.setValueAt(rs.getString("Institution"), row, 1);
tblModel.setValueAt(rs.getString("Doctor"), row, 2);
tblModel.setValueAt(rs.getString("Street"), row, 3);
tblModel.setValueAt(rs.getString("City"), row, 4);
tblModel.setValueAt(rs.getString("State"), row, 5);
tblModel.setValueAt(rs.getString("ZipCode"), row, 6);
tblModel.setValueAt(rs.getDate("Date"), row, 7);
tblModel.setValueAt(rs.getDouble("Cost"), row, 8);
tblModel.setValueAt(rs.getInt("ServiceTypeID"), row, 9);
tblModel.setValueAt(rs.getString("Comments"), row, 10);
row++;
}
rs.close();
}
catch (Exception e){
e.printStackTrace();
}
}
Not really related to your problem but I would like to suggest a better way to add the data to the model.
Instead of creating an empty array and then using setValueAt(...) you can change the looping code to look something like:
while (rs != null && rs.next())
{
Vector<Object> row = new Vector<Object>(11);
tblModel.addRow(new Object[0]);
row.add(rs.getString("ServiceID"));
row.add(rs.getString("Institution"));
...
row.add(rs.getString("Comments"));
tblModel.addRow( row );
}
Reasons for this approach:
The DefaultTableModel stores its data in a Vector. So the data from the Array is copied to the Vector. Save resources by just using an Vector from the beginning.
The code is shorter to type. This also makes it easier to rearrange columns since you don't need to worry about indexes.
Every time you invoke the setValueAt(...) method an event is generated to tell the table to paint itself. So this is happening 12 times, once for the addrow() method and once for each setValueAt() method. By just using the addRow() method at the end you only generate one event.

JTable Specifying column and row number on setBackground()

I recently learned that I can create a custom DefaultTableCellRenderer class for a JTable.
However, my code only colors the entire row but not the specific columns / cells I want to color based on a condition.
How can I specify the row and column in the DefaultTableCellRenderer class I created?
So here are the classes I created.
public class Schedule extends JPanel(){
public Schedule(){
schedulesJtbl.setDefaultRenderer(Object.class, new ScheduleTableCellRenderer());
int startTime = 1230, endTime = 1330;
int jtStartTime = scheduleJtbl.getValueAt(0,1);
int jtEndTime = scheduleJtbl.getValueAt(0,2);
int conflictCheck = 0;
// duplicate startTime and endTime
if((startTime == jtStartTime) && (endTime == jtEndTime)){
conflictCheck++
ScheduleTableCellRenderer.setConflict(conflictCheck);
}
//duplicate startTime
else if(startTime == jtStartTime){
conflictCheck++
ScheduleTableCellRenderer.setConflict(conflictCheck);
}
}
and here's the ScheduleTableCellRenderer
public class ScheduleTableCellRenderer extends DefaultTableCellRenderer {
static int conflict = 0;
#Override
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int col) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
if (conflict > 0) {
c.setBackground(Color.RED);
} else if (conflict == 0) {
c.setBackground(Color.GREEN);
}
return c;
}
public static void setConflict(int aConflict) {
conflict = aConflict;
}
}
If it's only startTime(as second condition on if) that duplicated, how can I color only column 2 but not the entire row just like what is happening right now on my JTable.
I hope you can help me.
Thank you.
schedulesJtbl.setDefaultRenderer(Object.class, new ScheduleTableCellRenderer());
That sets the default renderer for all Objects in any row/column.
To set the renderer for a specific column you do:
table.getColumnModel().getColumn(???).setCellRenderer( ... );
You also need to reset the default background:
if (conflict > 0) {
c.setBackground(Color.RED);
} else if (conflict == 0) {
c.setBackground(Color.GREEN);
} else {
c.setBackgrund( table.getBackground() );
}

Error when sorting rows in Jtable

I'm trying to set a RowSorter on my Jtable, I used the method setAutoCreateRowSorter(Boolean b) to sort the rows
table.setAutoCreateRowSorter(true);
But when I make the table as rawSorted, I get a strange error!
The conflict is visible when I want to delete a line, I used fireTableRowsDeleted().
int raw = table.getSelectedRow(); // the index of raw that i want to delete it
System.out.println(raw);
model.delte_raw(raw); // model is my table model
public void delte_raw(int raw)
{
if (!ls.isEmpty()) {
this.fireTableRowsDeleted(raw+1, raw);
ls.remove(raw);
}
I want to show you what result return the code as above in 2 cases:
Case 1:
When I make my table as not rawsorted:
table.setAutoCreateRowSorter(false);
when I delete a line, it all works successfully.
Case 2:
When I make my table as rawsorted:
table.setAutoCreateRowSorter(true);
when I delete a line, I get the error as below:
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Invalid range
at javax.swing.DefaultRowSorter.checkAgainstModel(DefaultRowSorter.java:921)
at javax.swing.DefaultRowSorter.rowsDeleted(DefaultRowSorter.java:878)
at javax.swing.JTable.notifySorter(JTable.java:4277)
at javax.swing.JTable.sortedTableChanged(JTable.java:4121)
at javax.swing.JTable.tableChanged(JTable.java:4398)
at javax.swing.table.AbstractTableModel.fireTableChanged(AbstractTableModel.java:296)
at javax.swing.table.AbstractTableModel.fireTableRowsDeleted(AbstractTableModel.java:261)
I think that the error is in my defaultRowSorter, so I defined my specific cellRenderer as below:
// final TableCellRenderer r = table.getTableHeader().getDefaultRenderer();
//TableCellRenderer wrapper = new TableCellRenderer() {
// private Icon ascendingIcon = new ImageIcon("images/e.png");
// private Icon descendingIcon = new ImageIcon("images/e.png");
//
// #Override
// public Component getTableCellRendererComponent(JTable table,
// Object value, boolean isSelected, boolean hasFocus,
// int row, int column)
// {
// Component comp = r.getTableCellRendererComponent(table, value, isSelected,
// hasFocus, row, column);
// if (comp instanceof JLabel) {
// JLabel label = (JLabel) comp;
// label.setIcon(getSortIcon(table, column));
// }
// return comp;
// }
//
// /**
// * Implements the logic to choose the appropriate icon.
// */
// private Icon getSortIcon(JTable table, int column) {
// SortOrder sortOrder = getColumnSortOrder(table, column);
// if (SortOrder.UNSORTED == sortOrder) {
// return null;
// }
// return SortOrder.ASCENDING == sortOrder ? ascendingIcon : descendingIcon;
// }
//
// private SortOrder getColumnSortOrder(JTable table, int column) {
// if (table == null || table.getRowSorter() == null) {
// return SortOrder.UNSORTED;
// }
// List<? extends RowSorter.SortKey> keys = table.getRowSorter().getSortKeys();
// if (keys.size() > 0) {
// RowSorter.SortKey key = keys.get(0);
// if (key.getColumn() == table.convertColumnIndexToModel(column)) {
// return key.getSortOrder();
// }
// }
// return SortOrder.UNSORTED;
// }
//
//};
//table.getTableHeader().setDefaultRenderer(wrapper);
But again, the same error!
Why do I get this error? I googled it a lot, but either I used the wrong keywords or there are no simple solutions on the internet.
In your table model:
public void delte_raw(int raw) {
if (!ls.isEmpty()) {
this.fireTableRowsDeleted(raw+1, raw); // why raw+1 ???
ls.remove(raw);
}
}
As your table model extends from AbstractTableModel and looking at fireTableRowsDeleted(int firstRow, int lastRow) javadoc:
Notifies all listeners that rows in the range [firstRow, lastRow],
inclusive, have been deleted.
So it should be:
public void delte_raw(int raw) {
if (!ls.isEmpty()) {
ls.remove(raw); // remove the row index from the List and then fire the event
fireTableRowsDeleted(raw, raw);
}
}
Knowing the exception source: looking at DefaultRowSorter.checkAgainstModel(int firstRow, int endRow) implementation:
private void checkAgainstModel(int firstRow, int endRow) {
if (firstRow > endRow || firstRow < 0 || endRow < 0 ||
firstRow > modelRowCount) {
throw new IndexOutOfBoundsException("Invalid range");
}
}
As you can see, calling this method with [raw+1,raw] range causes an IndexOutOfBoundsException.
Edit
As #mKorbel masterfully points out, I've totally overlooked this:
int raw = table.getSelectedRow(); // this is the index in the view
model.delte_raw(raw); // convert raw in the right model index is needed
You need to convert raw in the right model index. Otherwise it can cause side effects since in a sorted table is most likely the selected index in the view be different than its related model's index:
int raw = table.getSelectedRow(); // this is the index in the view
model.delte_raw(table.convertRowIndexToModel(raw)); // perfect
See JTable.convertRowIndexToModel(int viewRowIndex)

Set a cell's background in JTable based on some other inputs

All - I'm trying to set a specific cell's background color after it is clicked AND a successful operation has occurred. I cant seem to do it. Here is the code:
JTable table = new JTable(new DefaultTableModel());
String [] colNames = {"col1", "col2", "ClickMe"};
for (String name : colNames)
table.addColumn(name);
.... some code .....
String [] someArray = {"t", "t2", "t3"};
....
for (int i=0; i<someArray.length;i++) {
Object [] row = new Object[3];
row[0] = "bla";
row[1] = "bla";
row[2] = "Update";
((DefaultTableModel)table.getModel()).addRow(row);
((DefaultTableCellRenderer)gameTable.getCellRenderer(i, 2)).setBackground(Color.LIGHT_GRAY);
((DefaultTableCellRenderer)gameTable.getCellRenderer(i, 2)).setHorizontalAlignment(JLabel.CENTER);
}
table.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
int row = gameTable.rowAtPoint(e.getPoint());
int col = gameTable.columnAtPoint(e.getPoint());
if (col == 2) {
Color cellColor = ((DefaultTableCellRenderer)gameTable.getCellRenderer(row,col)).getBackground();
if (cellColor == Color.LIGHT_GREY) {
String val1 = (String)table.getModel().getValueAt(row,1);
String val2 = (String)table.getModel().getValueAt(row,0);
if (doSomething(val1, val2)) { //this returns either true or false, its a Database operations
((DefaultTableCellRenderer)table.getCellRenderer(row, 2)).setBackground(Color.BLUE);
}
}
}
};
Even thought i am specific calling setBackground on a row & column, it makes every cell in every row in column "2" change background color instead of just one specific one.
All the examples with customRenderers seem to just change the color based on when its clicked just change it to something else, i need to do some processing as well.
any thoughts here?
Thanks-
Try this
table.setDefaultRenderer(Object.class, new TableCellRenderer(){
private DefaultTableCellRenderer DEFAULT_RENDERER = new DefaultTableCellRenderer();
private Component comp;
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = DEFAULT_RENDERER.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if(isSelected){
c.setBackground(Color.YELLOW);
}else{
if (row%2 == 0){
if (column==2){
c.setBackground(Color.WHITE);
}
else {
c.setBackground(Color.LIGHT_GRAY);
} } }
return c;
}
});

Categories