So I have a class called Note and I need to put every Note inside a JComboBox.
Each Note has a String id and a String title. The title is being shown to the user, and the id is being used in the backend.
I've written a custom renderer to make this work, but I am getting compiler error: error: Note cannot be converted to String
Here is the code:
//Inside of the GUI class
cmbNotes.setRenderer(new NoteListCellRenderer());
//Populate combo box with the title of each note
NoteManager.notes.forEach((id, note) -> { //For-each loop
if (!note.isOpen()) {
cmbNotes.addItem(note); //ERROR: Note cannot be converted to String
}
});
Here is my custom renderer:
//In the same file as GUI, but outside of the GUI class
class NoteListCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
if (value instanceof Note) {
value = ((Note) value).getTitle();
}
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
return this;
}
}
Thank you Riann Nel for helping me to solve this problem.
I had created the JComboBox through the design, not through code.
The design by default sets the Type Parameters to String so I went in the design and clicked on the code section on the right then changed the Type Parameters to <Note>.
I also had to add a default constructor in my Note class.
Related
When I add a file object into a DefaultListModel, which is used to create a JList, with model.addElement(file), the displayed text in the JList is the path to the file. But I only want the file name to be displayed. I cannot do model.addElement(file.getName()), however, because I need access to the file object, not just a string, later on.
How can I add a file object to a list/model while displaying only the file name? Thank you!
You would do this by creating a custom renderer:
class FileRenderer extends DefaultListCellRenderer
{
public Component getListCellRendererComponent(
JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
{
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
File file = (File)value;
setText( file.getName() );
return this;
}
}
Then you set the renderer for the JList using:
list.setCellRenderer( new FileRenderer() );
For more information and working examples see the section from the Swing tutorial on Writing a Custom Cell Renderer
I am writing a simple text based chat application using applets in java, which consists of few components & one of them is my Jlist which provides list of online users at that particular point of time.
What i want is that i need to set a small picture besides online user name in Jlist.
Does anyone have any idea based on this. Please feel free to ask if you have any questions.
Thanks,
Puneet
The JList documentation has an example that loads icons into the JList. You should be able to use this to insert your small pictures into the JList.
http://docs.oracle.com/javase/6/docs/api/javax/swing/JList.html
Here is the relevant code from that link:
// Display an icon and a string for each object in the list.
class MyCellRenderer extends JLabel implements ListCellRenderer {
final static ImageIcon longIcon = new ImageIcon("long.gif");
final static ImageIcon shortIcon = new ImageIcon("short.gif");
// This is the only method defined by ListCellRenderer.
// We just reconfigure the JLabel each time we're called.
public Component getListCellRendererComponent(
JList list, // the list
Object value, // value to display
int index, // cell index
boolean isSelected, // is the cell selected
boolean cellHasFocus) // does the cell have focus
{
String s = value.toString();
setText(s);
setIcon((s.length() > 10) ? longIcon : shortIcon);
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setEnabled(list.isEnabled());
setFont(list.getFont());
setOpaque(true);
return this;
}
}
myList.setCellRenderer(new MyCellRenderer());
Assuming your JList contains usernames, you could put your usernames in a HashMap
setIcon(userHashMap.get(s));
If your JLIst is actually store other parts than just the username (dynamic components such as status, group name, etc.) you may need to parse out the username from the String passed into the value object.
So i am working with a JTable, It has Columns A-K. with A and B being the only editable ones. If someone edits an empty row in A, I make an API call to get B then i make a DB call to get all rows where B exists.If someone edits an empty row in B, i make the same call as the will be retrieved from the DB for that row as well. The call returns 0-N rows. If 0 rows were returned, I change the values of all row except B to N/A otherwise i populate the rows using the data.Once populated, i make all columns non-editable. The DB call occurs in its own thread as once the call is return i create my own record object which I add to the tablemodel.
I have my own TableModel and a TableModelListener to keep the data and handle changes in values.
Here is my issue. I am using TableCellRenderer and using the cellrenderer to see if the value was changed, if so then i make the calls and populate as needed. When a large number of rows is being pulled from DB, it takes a while to load and making all that records so I tried to use a ProgressBar to show the user that the screen isn't just frozen, it is progressing and by how much. However the frame that comes up is blank and nothing gets displayed. I get the feeling i am doing something either improperly or missing something.Any help much appreciated.
some code to understand what i am talking about
public class MyPanel extends JPanel {
private JTable myTable;
private MyTableModel tm;
//OTHER FIELDS
public static void createPanel() {
tm = new MyTableModel(columnnames);
myTable = new JTable(tm);
TableColumn account = myTable.getColumnModel().getColumn(
MyTableModel.ACCOUNT_INDEX);
account.setCellRenderer(new MyTableRenderer(
MyTableModel.ACCOUNT_INDEX));
}
}
public class MyTableRenderer extends DefaultTableCellRenderer{
protected int interactiveColumn;
public MyTableRenderer(int interactiveColumn) {
this.interactiveColumn = interactiveColumn;
}
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 (column == interactiveColumn && hasFocus) {
//DO DB and API CALLS HERE
//IF DB CALL DISPLAY A NEW FRAME WITH PROGRESSBAR
}
return c;
}
}
Sorry for formatting issues
Use SwingWorker, which allows you to update your TableModel as you examine your result set.
Addendum: Don't try to update the TableModel from the renderer. You can update the model when your implementation of CellEditor has concluded, by starting a suitable worker in getCellEditorValue(). In that way, the revised data will be available when the renderer is next invoked for any modified cell(s). This related example outlines the approach.
Addendum: getCellEditorValue() is invoked after editing has concluded, but starting the worker in setValueAt() offers more reliable access to the target row and column.
It is weird that I set my JTable cell renderer like this:
setDefaultRenderer(Object.class, new MyTableRenderer());
My table renderer works like this:
class MyTableRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
Component comp = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
Font font = comp.getFont();
if (table.getModel().getValueAt(row, 0).equals(BUY)) {
comp.setFont(font.deriveFont(Font.BOLD));
comp.setForeground(BUY_COLOR);
}
else {
comp.setFont(font.deriveFont(Font.BOLD));
comp.setForeground(SELL_COLOR);
}
return comp;
}
}
But it turns out, it didin't apply those columns that have type "BigDecimal", Other String fields are all working fine.
And then, I add one more line:
setDefaultRenderer(BigDecimal.class, new MyTableRenderer());
Then everything just work fine.
Why it is like this?
JTable by default installs a renderer for type Number. BigDecimal is-a Number so the default renderer is used instead of your custom renderer.
BTW: your custom renderer is buggy in that it doesn't take potentially sorted/filtered rows into account (the row/column index params of the method are view coordinates).
#eugener: your answer is wrong - it's not the storage that's important but the lookup ;-)
Cheers
Jeanette
Take look at the source code of the JTable:
public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
if (renderer != null) {
defaultRenderersByColumnClass.put(columnClass, renderer);
} else {
defaultRenderersByColumnClass.remove(columnClass);
}
}
It uses a map where column class is a key and means that class comparison is literal. This should explain the reason for behavior you're experiencing. This is by design.
I have a JComboBox and have 10 string items added in it.
I want to assign different colors to each item.
How i can achive this?
Please help.
The example in Chandru's answer looks like a lot of code so I can understand why you're asking for an easier solution. However, if you subclass DefaultListCellRenderer a lot of the work is done for you, as this renderer is a subclass of JLabel.
JList list = ... // Create JList
// Install custom renderer.
list.setCellRenderer(new DefaultListCellRenderer() {
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
// Request superclass to render the JLabel.
Component ret = super.getListCellRenderer(list, value, index, isSelected, cellHasFocus);
// Now conditionally override background if cell isn't selected.
if (!isSelected) {
String s = String.valueOf(value);
if (s.equals("Foo")) {
ret.setBackground(Color.RED);
} else {
ret.setBackground(Color.GREEN);
}
}
return ret;
}
});
You must use a custom list cell renderer. Look into this how-to for an example.
You must implement a new ListCellRenderer ,which will be used by your combobox, through setRenderer, to render properly your objects.
You can extend BasicComboBoxRenderer to avoid reconding everything.