I have a list of expences that looks like this :
My List
I would like the elements of the list to appear as if formatted with \t :
PRODUCT NAME PRICE DATE
PRODUCT NAME PRICE DATE
ect. I created DefaultListCellRenderer but I don't know how to implement this formatting.. If it's not doable, than at least how do I center the elements?
My DefaultListCellRenderer looks like this at the moment :
private class MyListRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 1L;
public Component getListCellRendererComponent( JList<?> list,
Object value, int index, boolean isSelected,
boolean cellHasFocus )
{
Component c = super.getListCellRendererComponent( list, value, index,
isSelected, cellHasFocus );
Color czerwony = new Color(205, 16, 26);
setForeground(czerwony);
return(this);
}
}
Shoot, I'll make my comment an answer: use a JTable to display tabular data since it excels at this and was built for this. Otherwise if you want to create your own kludge of a Table via a JList, you'll be forced to use mono-spaced fonts and code that can easily break if one item of data exceeds the expected width of that column.
If you have restrictions on why you can't or are not allowed to use this, then please by all means share this with us.
Related
I have a JTable object which displays the content of an Excel table. Once another Excel table is loaded, the differences have to be displayed (so some cells will change its background color, blue for example). This is the structure of my table.
And this is my code:
tblGSM.setDefaultRenderer(Object.class, new CustomTableRenderer(diffs));
CustomTableRenderer.java
public class CustomTableRenderer extends DefaultTableCellRenderer {
private Vector<Diff> diffs;
public PersoTableRenderer(Vector<Diff> diffs){
this.diffs = diffs;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = null;
for (int x = 0; x < diffs.size(); x++){
Diff d = diffs.elementAt(x);
c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
d.getRow(), d.getColumn());
c.setBackground(Color.BLUE);
}
return c;
}}
Diff.java
/*
A class to store the difference of corresponding cells
*/
public class Diff {
private int row, col;
public Diff(int row, int col){
this.row = row;
this.col = col;
}
public Diff(){
this(0,0);
}
public int getRow(){
return row;
}
public int getColumn(){
return col;
}
}
My question is diffs is populated correctly, yet the cells colors which are should be changed are not. Turns out all cells in column 1, 2, ,3, and 7 are changed. What it the solution, then?
From the documentation for DefaultTableCellRenderer (emphasis mine):
However JTable employs a unique mechanism for rendering its cells and therefore requires some slightly modified behavior from its cell renderer. The table class defines a single cell renderer and uses it as a as a rubber-stamp for rendering all cells in the table; it renders the first cell, changes the contents of that cell renderer, shifts the origin to the new location, re-draws it, and so on.
So as you can see, super.getTableCellRendererComponent() may return the same component for multiple cells, and thus your approach will not work.
Note that getTableCellRendererComponent is called once per cell as it is rendering, so in addition to the above caveat, your general approach of setting all renderer components in the table to blue when retrieving a single cell's component is not correct.
Instead you will want to only modify the background color of the component being requested, like (pseudo-code):
c = super.getTableCellRendererComponent(..., row, column)
// also don't forget to translate to model coords
model_row = table.convertRowIndexToModel(row)
model_column = table.convertColumnIndexToModel(column)
if diffs contains model_row,model_column:
c.setBackground(blue)
else
c.setBackground(table.getBackground()) // don't forget to reset
return c
Noting that you also have to reset the background color to its default if its not a "diff" cell, since as the docs state, the components are shared among multiple cells.
By the way, rather than storing the Vector<Diff> in your renderer, you really ought to be using a proper TableModel for this, and then querying the model for information. With a sanely implemented model this will also give you constant-time lookups of whether or not a cell should be blue, rather than having to search through the entire list of Diffs.
PS: Don't forget to translate your renderer/view coordinates to model coordinates when working with your Diffs, assuming they are in model coordinates. View coordinates may not agree with model coordinates if e.g. the table is sorted or the user has rearranged the columns. I've shown this in the above pseudo code.
Here is a complete example showing the use of a table model and per-cell custom backgrounds. You can sort the table and rearrange its columns.
i need to change my jtable appearance .
i have these data :
image image.
title String.
date String .
description String.
auteur String .
img , title , date ,description ,auteur.
my question is :
is that possible that i can show in every row these data as twitter feed appearance .
i want to show all these data in the same cell with a sample .
thanks every one .
You should use a JList (or a JTable, but with only one cell per row, a JList seems to be more appropriate) with a custom cell renderer.
Create your data class
public class MyData {
// image, title, date, description and author
}
Create your cell renderer
class MyCellRenderer extends JLabel implements ListCellRenderer<MyData> {
public Component getListCellRendererComponent(
JList<?> list, // the list
MyData value, // value to display
int index, // cell index
boolean isSelected, // is the cell selected
boolean cellHasFocus) // does the cell have focus
{
// tune your component in the way you want, for example
this.setText(value.getTitle());
// return the component to draw for this cell
return this;
}
}
Of course, your cell renderer can extends another component like JPanel.
Finally, instantiate a JList and set your custom renderer
JList<MyData> list = new JList<>();
list.setCellRenderer(new MyCellRenderer());
A quick question about the example code in the JavaDoc for javax.swing.ListCellRenderer:
I'm a little surprised, that in the example, the ListCellRenderer is implemented by a class that extends JLabel and that the getListCellRendererComponent(...)-method simply returns this. It looks like there is only one instance of a JLabel around then, even for a list containing more than one element.
Usually, I would then expect that when the setText(...) method is called inside getListCellRendererComponent(...) for the second item in the list, it changes the label of the already existing first item in the list. Or, actually, it probably shouldn't even be possible for the list to use the same JLabel-instance twice (or more times), once for each item in the list.
Now, I've come up with two possible ways to resolve this and was wondering which one (if any) is actually happening:
Does JList somehow create new instances of the provided ListCellRenderer for each list item?
Or does it use the component returned by getListCellRendererComponent(...) only to invoke its paint(...) method on the list's canvas rather than actually adding this component to some panel?
When the JList renders itself it asks the ListModel for the elements it should display.
For each element it calls the javax.swing.ListCellRenderer to provide a render component. Then it paints the component. That's all. A render component is not bound to an element's state that it renders.
The javadoc of ListCellRenderer says:
Identifies components that can be used as "rubber stamps"
to paint the cells in a JList.
So your second assumption is right.
A look at javax.swing.plaf.BasicListUI shows it:
protected void paintCell(Graphics g, int row, Rectangle rowBounds,
ListCellRenderer cellRenderer, ListModel dataModel,
ListSelectionModel selModel, int leadIndex) {
Object value = dataModel.getElementAt(row);
boolean cellHasFocus = list.hasFocus() && (row == leadIndex);
boolean isSelected = selModel.isSelectedIndex(row);
Component rendererComponent = cellRenderer
.getListCellRendererComponent(list, value, row, isSelected,
cellHasFocus);
int cx = rowBounds.x;
int cy = rowBounds.y;
int cw = rowBounds.width;
int ch = rowBounds.height;
if (isFileList) {
// Shrink renderer to preferred size. This is mostly used on Windows
// where selection is only shown around the file name, instead of
// across the whole list cell.
int w = Math
.min(cw, rendererComponent.getPreferredSize().width + 4);
if (!isLeftToRight) {
cx += (cw - w);
}
cw = w;
}
rendererPane.paintComponent(g, rendererComponent, list, cx, cy, cw, ch,
true);
}
what's up?
I created one jList on my project that I can't retrieve the element. I know jList only accepts objects, but I was adding Strings to my list, because when I add "Discipline" object, I see something like "Discipline{id=21, name=DisciplineName}" on my view. So, I'm adding strings instead objects.
Following is my code:
ArrayList<Discipline> query = myController.select();
for (Discipline temp : query){
model.addElement(temp.getNome());
}
When I get the index of a double click in one element, I try to retrieve my String to make a query and know what's this discipline. But I'm getting some errors, see what I already tried:
Object discipline = lista1.get(index);
// Error: local variable lista1 is accessed from within inner class; needs to be declared final
String nameDiscipline = (String) lista1.get(index);
// Error: local variable lista1 is accessed from within inner class; needs to be declared final
I really don't know what means "final", but what can I do to solve this problem? One thing that I thinked is:
Can I add a Discipline instead String, show to user discipline.getName() and retrieve Discipline object?
Yes, add Discipline objects. A quick fix is to change Discipline's toString method, but a much better fix is to create a ListCellRenderer that displays each Discipline's data in a nice String.
Here are two ListCellRenderers that I have used in a project of mine to change the item displayed in my JList from text to an ImageIcon:
private class ImgListCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if (value != null) {
BufferedImage img = ((SimpleTnWrapper) value).getTnImage();
value = new ImageIcon(img); // *** change value parameter to an ImageIcon
}
return super.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
}
}
private class NonImgCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
// all this does is use the item held by the list, here value
// to extract a String that I want to display
if (value != null) {
SimpleTnWrapper simpleTn = (SimpleTnWrapper) value;
String displayString = simpleTn.getImgHref().getImgHref();
displayString = displayString.substring(displayString.lastIndexOf("/") + 1);
value = displayString; // change the value parameter to the String ******
}
return super.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
}
}
They are declared like so:
private ListCellRenderer imgRenderer = new ImgListCellRenderer();
private ListCellRenderer nonImgRenderer = new NonImgCellRenderer();
And I use them thusly:
imgList.setCellRenderer(imgRenderer);
The DefaultListCellRenderer is pretty powerful and knows how to display a String or an ImageIcon correctly (since it is based off of a JLabel).
I have a JTable and i want a cell (or its row) painted in red when the value entered is higher than a certain value. I'm checking that into a TableModelListener to detect TableChange, so I see no way of colouring the table at the renderer (yet I'm sure it is possible, only it is unknown for me).
I also saw this question but i don't know how to use it.
that job for prepareRendered as you can see here
Following is for single table cell you can extend it for row:
First take table column you want to pint and then add a TableCellRenderer to it as follows:
TableColumnModel columnModel = myTable.getColumnModel();
TableColumn column = columnModel.getColumn(5); // Give column index here
column.setCellRenderer(new MyTableCellRenderer());
Make MyTableCellRendere class which implements TableCellRenderer and extends JLabel(so that we can give a background color to it). It will look something like following:
public class MyTableCellRenderer extends JLabel implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int col) {
JLabel jLabel = (JLabel) value;
setBackground(jLabel.getBackground());
setForeground(UIConstants.black);
setText(jLabel.getText());
return this;
}
}
Now in method where you are listening table cell value change do something like follow:
JLabel label = new JLabel(changedValue);
// check for some condition
label.setBackground(Color.red); // set color based on some condition
myTable.setValueAt(label, 0, 5); // here 0 is rowNumber and 5 is colIndex that should be same used to get tableColumn before.