I have a JTable which I would like to display an image depending on the content of a cell, I understand in order to accomplish this I have to implement my own custom cell renderer, which I have already, however, as soon as the first image is drawn on the cell the programme draws the image on other cells regardless of their content. I have tried pretty much everything and have also scoured the internet for a solution, all with no avail. Here is my code:
public class GameBoard extends JTable
{
public GameBoard()
{
super(new GameBoardModel());
setFocusable(false);
setCellSelectionEnabled(true);
setRowHeight(26);
TableColumn column = null;
for (int i = 0; i < getColumnCount(); i++)
{
column = getColumnModel().getColumn(i);
column.setPreferredWidth(26);
}
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
setDefaultRenderer(Object.class, new CellRenderer());
}
private class CellRenderer extends DefaultTableCellRenderer
{
private CellRenderer()
{
setHorizontalAlignment(JLabel.CENTER);
}
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column)
{
if (value.toString().equals("X"))
{
URL test = getClass().getResource(resources/icon.png");
setIcon(new ImageIcon(test));
}
else
setText(value.toString());
return this;
}
}
Forgive me if I'm doing something silly somewhere along those lines. . .
Thanks in advance,
Zig.
Don't forget to invoke:
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
at the start of the method so you get the default settings of the renderer.
If the above doesn't fix the problem then your code may need to be something like:
if (value.toString().equals("X"))
{
URL test = getClass().getResource(resources/icon.png");
setIcon(new ImageIcon(test));
setText("");
}
else
{
setIcon(null);
setText(value.toString());
}
Also, you should never read the image in the renderer. The render gets called multiple times so you don't want to read the image every time. Read the image in the constructor of the class.
Related
As you can see in my pictures:
Before minimize:
After minimize
My renderer takes the last color that have used and paints all my table.
Bellow is my custom renderer class:
public class MyCellRenderer extends DefaultTableCellRenderer {
public static double fstValue;
public static double sndValue;
public MyCellRenderer() { }
public MyCellRenderer(double fstValue, double sndValue) {
this.fstValue = fstValue;
this.sndValue = sndValue;
//System.out.println(this.fstValue+" 2ndvalue"+this.sndValue+" ston constructor");
}
#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);
if(!isSelected) {
if(compare(this.fstValue,this.sndValue)== 1){
c.setBackground(Color.GREEN);
}else if (compare(this.fstValue,this.sndValue)== -1) {
c.setBackground(Color.red);
}else{
c.setBackground(null);
}
}
return c;
}
}
I m updating the table fast, and I have no problem with that.
But when I resize or minimize or scroll down, the coloring change.
When I minimize and resize, my table change color all, but when I scroll down only the table that I scrolled change color.
I suspect that it has something to do with the repaint or paint method that my renderer calls and have trouble fixing it.
I use threads and every thread calls the code below for the update:
if( home.text().equals(hometmp.toString())==false)
{
MyCellRenderer cellRenderer = new MyCellRenderer(valuehm,valuehmt);
table1.setValueAt(home.text(),i-1,1);
}
You have two calls to super.getTableCellRendererComponent(...). Get rid of the second. Also, there is no need to cast the first call to a label. The method return a Component which has a setBackground() method.
You don't need the synchronized keyword on the method.
I'm new to Java and I want to change the background color of a Specific cell, the one I clicked on, of a JTable.
I know that I have to use a MouseListener which I already did, also, the mousePressed. But at this point I am pretty lost.
EDIT: Forgot to add that the table is disabled, so you can't select a cell.
Can anyone help me? Thanks!
You must create a custom TableCellRenderer and pass it to the table
like this
public class ColorRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
// get the DefaultCellRenderer to give you the basic component
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
// apply your rules
if(table.isRowSelected(row) && table.isColumnSelected(col))
c.setBackground(Color.GREEN);
else{
c.setBackground(table.getBackground());
}
return c;
}
}
in this class we check if the given cell if the selected cell (which is pretty much what happens when we click it) and paint it differently (in my case I paint it green) , else we paint with the default color or any color you like.
don't forget to set the custom renderer you just created
table.setDefaultRenderer(Object.class, new ColorRenderer());
Edit 1
you must get the row and col of the clicked cell.
create 2 int variables that will hold the position
private int clickedRow=-1,clickedCol=-1;
add a mouse listener that updates the position variables
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent event) {
clickedRow= table.rowAtPoint(event.getPoint());
clickedCol= table.columnAtPoint(event.getPoint());
}
});
after that you change the renderer so it paints only the clicked cell with the special color
if( clickedRow == row && clickedCol == col){
c.setBackground(Color.GREEN);
}
im been looking around on the internet for about 5 hours now to debug on this issue ive been having. and Basically i haven't been able to find anywhere where a person tries to add a new JLabel for each row in a specific column.
functionality explanation: i get a file url, i take the postFix which is usually xlsx or
doc - this postfix i want to display in a JLabel in coalition with a Excel or Doc
Icon -.- but what my current code does is just paint the same JLabel over and over again because it only sets the CellRenderer one time and uses it on all the rows dispite the fact that im setting it in a for-loop for each iteration - all my code is correct for this functionality up until the renderer only gets called once.
so my question goes as follows - how do i add a new JLabel for each row
in a Column ? -
my code follows.
my TableCellRenderer:
public class JLabelRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = -166379583761969293L;
// private String fileExtension;
// private JLabel label;
private LogEntry log;
private JLabel label;
public JLabelRenderer(LogEntry log) {
label = new JLabel();
System.out.println("makeing a new JLabelRenderer");
this.log = log;
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
label = (JLabel) super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
System.out.println(log.getFileExtension());
if (log.getFileExtension().equalsIgnoreCase("xlsx")) {
label.setIcon((ImageIcon) Pictures.getXlsx());
label.setText(log.getFileExtension());
} else if (log.getFileExtension().equalsIgnoreCase("doc")) {
label.setIcon((ImageIcon) Pictures.getDoc());
label.setText(log.getFileExtension());
} else if (log.getFileExtension().equalsIgnoreCase("docx")) {
label.setIcon((ImageIcon) Pictures.getDoc());
label.setText(log.getFileExtension());
} else if (log.getFileExtension().equalsIgnoreCase("pdf")) {
label.setIcon((ImageIcon) Pictures.getPdf());
label.setText(log.getFileExtension());
}
value = label;
return label;
}
#Override
public void setHorizontalAlignment(int alignment) {
super.setHorizontalAlignment(alignment);
}
public void setLog(LogEntry log) {
this.log = log;
}
}
where i make my model:
(i have alot more code adding actionListeners to right-click functionality and what not
but thats hardly relevant)
public void makeLogModel()
{
logModel = new DefaultTableModel();
//addCellEditorListener(this);
logModel.setColumnIdentifiers(new String[]{"Lavet Dato", "Lavet Af", "Beskrivelse", "Sidst Redigeret Dato", "Sidst Redigeret Af", "Fil Type"});
setAutoCreateRowSorter(true);//allows to sort through the information.
setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
setModel(logModel);
}
Where the magic was suppose to happen(update the log table after a search on logs)
public void updateLogTable(ArrayList<LogEntry> entryList)
{
logModel.setRowCount(entryList.size());
for(int i = 0; i < logModel.getRowCount(); i++)
{
setRowHeight(i, 30);
}
int row = 0;
for(LogEntry log : entryList)
{
logModel.setValueAt(log.getCreateDate(), row, 0);
logModel.setValueAt(log.getMadeBy(), row, 1);
logModel.setValueAt(log.getDescription(), row, 2);
logModel.setValueAt(log.getLastEdited(), row, 3);
logModel.setValueAt(log.getLastEditedBy(), row, 4);
labelRenderer = new JLabelRenderer(log);
getColumn("Fil Type").setCellRenderer(labelRenderer);
logModel.setValueAt(new JLabel(), logRow, 5);
row++;
}
}
i have read the Java documentation for components and Editors- but none of the
code examples are for a JLabel - probably because CellRenderer extends JLabel..
i have allso sniffed up the info that the 'value' parameter in the getTableCellRendererComponent() method is the one that is supposed to be set dynamically somehow... any surgestions would be greatly apriciatet, feel free to ask any questions.
thanks
logModel.setValueAt(new JLabel(), logRow, 5);
don't put JLabel, any JComponent to the model, XxxTableModel is designated to nest value for Renderer or Editor only, more in Oracle tutorial How to use Tables - Creating a Table Model
Renderer or Editor visually represents real JComponents, more in Oracle tutorial How to use Tables - Concepts: Editors and Renderers
label.setIcon((ImageIcon) Pictures.getXlsx());
Icon should be placed into local variables or array, list, whatever of Icons, don't load any FileIO from Renderer, renderer can be called many times per one second, e.g. from all mouse, keys and methods inplemented in APIs
Seems your problem in DefaultTableCellRenderer implementation.
You create renderer like JLabelRenderer(LogEntry log) because of, for all cells you have one instance of LogEntry, and log.getFileExtension() in getTableCellRendererComponent() returns same result for all rows.
In case of TableCellRenderer you need to use value parametr from getTableCellRendererComponent() method to determine extension and LogEntry instance.
Examine Concepts: Editors and Renderers.
Here is simple example for you, I use color instead of icons:
import java.awt.Color;
import java.awt.Component;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
public class TestFrame extends JFrame{
public TestFrame(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
init();
pack();
setVisible(true);
}
private void init() {
JTable table = new JTable(new Object[][]{
{1,"doc"},
{2,"xlsx"},
{3,"abc"}
},new Object[]{"nmb","extension"});
table.getColumnModel().getColumn(1).setCellRenderer(getRenderer());
add(new JScrollPane(table));
}
private TableCellRenderer getRenderer() {
return new DefaultTableCellRenderer(){
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus,row, column);
if("doc".equals(value)){
tableCellRendererComponent.setBackground(Color.YELLOW);
} else if("xlsx".equals(value)){
tableCellRendererComponent.setBackground(Color.GREEN);
} else {
tableCellRendererComponent.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
}
return tableCellRendererComponent;
}
};
}
public static void main(String... strings) {
new TestFrame();
}
}
Also don't put Component's to TableModel like here logModel.setValueAt(new JLabel(), logRow, 5); just value.
I have a table which every cell keep a string. Actually I used the table as a page of book and it contains text. My problem is that I want to click on a cell and all similar words' background color in the table change to one unique color. For instance, when I click on the cell which contains 'and', all 'and' in my table become highlighted. I implemented defaulttablecellrenderer and I know that when java wants to draw table recall it for every cell. I tried to use intrinsic repetition capability and set the color but it does not work in the way I expected. These are my codes:
JTable t=new Jtabale();
//Filling my table....here....
t.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e){
int column=((JTable)e.getSource()).getSelectedColumn();
int row=((JTable)e.getSource()).getSelectedRow();
JTable table=(JTable)e.getComponent();
Object myS=table.getValueAt(row, column);//value of that cell saved
CustomCellRenderer r=(CustomCellRenderer)table.getCellRenderer(row, column);
r.setCell(myS);
table.repaint();
}
});
and this is my DefaultTableCellRenderer implementation:
public class CustomCellRenderer extends DefaultTableCellRenderer {
Object myStr;
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);
if(myStr==value){
c.setBackground(Color.YELLOW);
}
else
c.setBackground(table.getBackground());
return c;
}
public void setCell(Object val){
myStr=val;
}
I do not know what's wrong with this code? This is only highlight that cell which I click. But I expected it change the background of several cells together! Even I put println inside the if but even it goes once in the if brace! I got confused. What is your idea?!
HI, I've a JLIST and assigned it a cellRenderer. but i was not able select element in list. Actually it is selected but visually we can not see that it is selected means i was not able to see which item is selected in list.
Screen shot of my list:
and what is expected is
The second screen shot is without CellRenderer. But when i add CellRenderer i was not able to see the selected item in list.
is it normal behaviour that when you add CellRenderer to list.
what am i doing wrong ???
EDIT:-
this is my CellRenderer class:
public class ContactsRender extends JLabel implements ListCellRenderer {
private static final long serialVersionUID = 1L;
ImageIcon img;
public ContactsRender(){
setOpaque(true);
setIconTextGap(12);
setBackground(Color.WHITE);
setForeground(Color.black);
}
#Override
public Component getListCellRendererComponent(JList list,
Object value, int index, boolean isSelected,
boolean cellHasFocus) {
if(value != null){
User user = (User) value;
String pres = user.getPresence().toLowerCase();
if(pres.contains("unavailable")){
img = new ImageIcon("res/offline.jpg");
} else {
img = new ImageIcon("res/online.jpg");
}
setText(user.getName());
setIcon(img);
return this;
}
return null;
}
You implemented your cell renderer incorrectly. The renderer is responsible for setting the renderer background to the selection color.
Read the JList API and follow the link to the Swing tutorial on "How to Use Lists" where you will find working examples that use a JList. You will also find a section on writing a renderer and an example.
Edit: Also, I just noticed you are reading your icon in the renderer code. You should never do this. The icon should only be read once when the renderer is created and then you cache the Icon. Every time a cell needs to be repainted the renderer is called so it is not efficient to keep reading the icon.
On your cell renderer, you have to implement the case for isSelected is true. For your ListCellRenderer :
Component getListCellRendererComponent(JList<? extends E> list,
E value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
if (!isSelected) doThis(index);
else doThatForSelectedItem(index);
}