Best way to render icon and text in JList - java

I create a JList constructed with my own sublass of AbstractListModel, the models stores instance of Action class and I had getElementAt() defined as
public final Object getElementAt(final int index)
{
return ((Action) actionList.get(index)).getValue(Action.NAME);
}
my JList displays a list of action names, which is okay.
But these actions also have an icon defined, so if I do
public final Object getElementAt(final int index)
{
return ((Action) actionList.get(index)).getValue(Action.SMALL_ICON)
);
}
it now displays the icon instead.
But I want both so I tried
public final Object getElementAt(final int index)
{
return new JButton(
(String)((Action) actionList.get(index)).getValue(Action.NAME),
(Icon)((Action) actionList.get(index)).getValue(Action.SMALL_ICON)
);
}
and now it just outputs the properties of the button instead how come

Nevermind reading the javadoc helped !
getElementAt() should just be
public final Object getElementAt(final int index)
{
return actionList.get(index);
}
then I look the render in the javadoc and modified as follows:
class MyCellRenderer extends JLabel implements ListCellRenderer {
ImageIcon longIcon = new ImageIcon("long.gif");
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
{
Action action = (Action)value;
setText((String)action.getValue(Action.NAME));
setIcon((Icon)action.getValue(Action.SMALL_ICON));
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;
}
}
Then set as the Jlists renderer
availableList.setCellRenderer(new MyCellRenderer());
and it works.

Related

Background color to selected item in JList not working

Why my selected item background not changing? I surely know that i press list item because my System.out.println says my Current selection and showing id of selected item. No errors no nothing just not working. Why ?
Object[] tablen = sqltable.toArray();
JList list;
list = new JList(tablen);
list.addListSelectionListener(new ListSelectionListener(){
#Override
public void valueChanged(ListSelectionEvent e) {
int idx = list.getSelectedIndex();
setOpaque(true);
if (idx != -1){
//list.setSelectionBackground(Color.lightGray);
// list.setSelectionForeground(Color.lightGray);
setForeground(Color.red);
setBackground(Color.BLUE);
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
System.out.println("Current selection: " + tablen[idx]);
}else{
setForeground(Color.red);
setBackground(Color.BLUE);
setBackground(list.getBackground());
setForeground(list.getForeground());
System.out.println("Please choose a language.");
}
}
});
list.setCellRenderer(new ListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
String[] val = (String[]) value;
return new JLabel(val[0]);
}
});
Beware in your cell renderer implementation that JLabel is non opaque by default, and probably is the reason why the background color in the list cell renderer is not painted. (see related)
On the other hand I'd take a look to Providing a Custom Renderer for a better example on how to implement a custom cell renderer.

JCombobox with custom DefaultListCellRenderer as a DefaultCellEditor: returns string value instead of custom object

I have a JTable with a model that implements AbstractTableModel. The Model holds custom RequisitionItem objects which also have a Section Object in one of its field. When inserting a new record into the table, i add a new row with a new RequisitionItem initialized with non-null but empty values. For the Section column, i have custom renderers for the table and the combobox as follows
for the table;
requestItemsTable.getColumnModel().getColumn(3).setCellRenderer(new DefaultTableCellRenderer(){
public void setValue(Object value) {
if (value==null) {
setText("");
} else {
Section section = (Section) value;
setText(section.getName());
}
}});
for the combobox;
sectionComboBox.setRenderer(new BasicComboBoxRenderer() {
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value != null) {
setText(((Section) value).getName());
}
if (index == -1) {
setText("");
}
return this;
}
});
for the editing, i have the following;
sectionComboBox = new JComboBox<>();
sectionComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(sectionJpaController.getDepartmentSections(department.getNumber()).toArray(new Section[0])));
requestItemsTable.getColumnModel().getColumn(3).setCellEditor(new DefaultCellEditor(sectionComboBox));
But after clicking the Section cell, selecting one of the Section items in the combobox and hitting enter, i get java.lang.ClassCastException: java.lang.String cannot be cast to ***.model.domain.Section. Sow why is the return from the DefaultCellEditor not a section object but String?
Why do you have to use so much customized logic for rendering and selecting your Section objects in the combobox?
If I understand correctly, you are trying to render only the name your Section objects on the JCombobox but be able to retrieve the entire Section object at the JTable.
To achieve this, you only need to things:
Initialize the JComboBox using a vector of Section objects that are for selection.
return the name of Section in its toString method because JComboBox evaluates the toString of its items for rendering.
set the combox to be used in the CellEditor for the JTable column for Section (which you have done)
A running example would be:
public class JTableWithComboboxEditor extends JFrame {
class Section {
String name;
int value2;
public Section(String name, int value2) {
this.name = name;
this.value2 = value2;
}
#Override
public String toString() {
return name;
}
}
private JTable table = new JTable(new DefaultTableModel(new String[]{"Section"}, 2));
public JTableWithComboboxEditor() {
this.add(new JScrollPane(table));
Section section1 = new Section("A", 1);
Section section2 = new Section("B", 2);
Vector sectionList = new Vector();
sectionList.add(section1);
sectionList.add(section2);
JComboBox comboBox = new JComboBox(sectionList);
table.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(comboBox));
table.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
Object value = table.getValueAt(0, 0);
if (value != null) {
Section section = (Section) value;
System.out.println(section.name + " " + section.value2);
}
}
});
}
}

Displaying an ImageIcon in a JList that uses a different Object to load the JList data

I have a JList that is being populated through an ArrayList of strings somewhere else, i want to for the same list now display an ImageIcon saved in my directory somewhere. For now i want to display the same icon for any item added to the list (or any items currently in the list).
My list should look like this : ICON STUDENT NAME ...
ICON STUDENT NAME
The problem (The image icon shows the correct height and it is being captured but does not show in the list at run-time
Here is my action listener that adds the data to the List.
public class StudentListener implements ActionListener{
private Main_Menu menu;
private ArrayList<String> arrayList = new ArrayList<String>();;
Iterator iterator = arrayList.iterator();
JList sList;
Map<Object, Icon> icons = new HashMap<Object, Icon>();
/**
*
* #param menu the referenced menu from our main menu
*/
public StudentListener(Main_Menu menu){
this.menu = menu;
}
#Override
public void actionPerformed(ActionEvent ae) {
Icon iCon = new ImageIcon("/Project/src/Images/1312046124_picture.png"); // icons
int iHeight = iCon.getIconHeight();
icons.put("name", iCon);
//add all the students to our List
try {
StudentModel = new Student_Model();
} catch (SQLException ex) {
Logger.getLogger(Student_Controller.class.getName()).log(Level.SEVERE, null, ex);
}
//arrayList = StudentModel.getStudents(); // modify to use an arrayList of string
arrayList.add("John");
arrayList.add("Smith");
iterator = arrayList.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next().toString());
}
sList = this.menu.getStudentList();
sList.setListData(arrayList.toArray());
sList.setFont(new Font("Arial", Font.BOLD, 14));
System.out.println("height of icon " + iHeight); // displays the correct height
sList.setCellRenderer(new IconListRenderer(icons));
}
}
IconListCellRenderer
public class IconListRenderer
extends DefaultListCellRenderer {
private Map<Object, Icon> icons = null;
public IconListRenderer(Map<Object, Icon> icons) {
this.icons = icons;
}
#Override
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
// Get the renderer component from parent class
JLabel label =
(JLabel) super.getListCellRendererComponent(list,
value, index, isSelected, cellHasFocus);
// Get icon to use for the list item value
Icon icon = icons.get(value);
// Set icon to display for value
label.setIcon(icon);
return label;
}
}
JList has method how to add Icon/ImageIcon to the ListCellRenderer, link for example is about JComboBox that contains JList, another examples here and here

Issues with add JButton in the table

I am adding Jbutton to a table by extendibg AbstractCellEditor class. But on click of button the text doesnt change from "Start" to "Stop" .here is the class i implemented
public class ButtonEditor1 extends AbstractCellEditor implements
TableCellEditor,ActionListener,TableCellRenderer{
JButton btnSTART = new JButton("START");
private JTable table ;
public ButtonEditor1(JTable table){
this.table = table;
btnSTART.addActionListener(this);
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
return btnSTART;
}
public Object getCellEditorValue() {
// TODO Auto-generated method stub
return btnSTART;
}
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
if(btnSTART.getText().equals("START")){
if(row != -1){
btnSTART.setText("STOP");
}
}else if(btnSTART.getText().equals("STOP")){
if(row != -1){
btnSTART.setText("START");
}
}
fireEditingStopped();
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
return btnSTART;
}
}
what i am doing wrong .. I have a Model class which takes the column as JButton and have overriden the method setValueAt and getValueAt.
A JTable uses renderers to display data. Once you click on the cell using the button as an editor, the button editor is invoked for a split second, then the cell is placed back in rendering mode. So if you want to change the text you change the value in the model.

How do I make a list with checkboxes in Java Swing?

What would be the best way to have a list of items with a checkbox each in Java Swing?
I.e. a JList with items that have some text and a checkbox each?
A wonderful answer is this CheckBoxList. It implements Telcontar's answer (though 3 years before :)... I'm using it in Java 1.6 with no problems. I've also added an addCheckbox method like this (surely could be shorter, haven't used Java in a while):
public void addCheckbox(JCheckBox checkBox) {
ListModel currentList = this.getModel();
JCheckBox[] newList = new JCheckBox[currentList.getSize() + 1];
for (int i = 0; i < currentList.getSize(); i++) {
newList[i] = (JCheckBox) currentList.getElementAt(i);
}
newList[newList.length - 1] = checkBox;
setListData(newList);
}
I tried out the demo for the Jidesoft stuff, playing with the CheckBoxList I encountered some problems (behaviors that didn't work). I'll modify this answer if I find problems with the CheckBoxList I linked to.
Create a custom ListCellRenderer and asign it to the JList.
This custom ListCellRenderer must return a JCheckbox in the implementantion of getListCellRendererComponent(...) method.
But this JCheckbox will not be editable, is a simple paint in the screen is up to you to choose when this JCheckbox must be 'ticked' or not,
For example, show it ticked when the row is selected (parameter isSelected), but this way the check status will no be mantained if the selection changes. Its better to show it checked consulting the data below the ListModel, but then is up to you to implement the method who changes the check status of the data, and notify the change to the JList to be repainted.
I Will post sample code later if you need it
ListCellRenderer
Just implement a ListCellRenderer
public class CheckboxListCellRenderer extends JCheckBox implements ListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
setComponentOrientation(list.getComponentOrientation());
setFont(list.getFont());
setBackground(list.getBackground());
setForeground(list.getForeground());
setSelected(isSelected);
setEnabled(list.isEnabled());
setText(value == null ? "" : value.toString());
return this;
}
}
and set the renderer
JList list = new JList();
list.setCellRenderer(new CheckboxListCellRenderer());
this will result in
Details at Custom swing component renderers.
PS: If you want radio elements just replace extends JCheckbox with extends JRadioButton.
I'd probably be looking to use a JTable rather than a JList and since the default rendering of a checkbox is rather ugly, I'd probably be looking to drop in a custom TableModel, CellRenderer and CellEditor to represent a boolean value. Of course, I would imagine this has been done a bajillion times already. Sun has good examples.
Better solution for Java 7 and newer
I stumbled upon this question and realized that some of the answers are pretty old and outdated. Nowadays, JList is generic and thus there are better solutions.
My solution of the generic JCheckBoxList:
import java.awt.Component;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;
#SuppressWarnings("serial")
public class JCheckBoxList extends JList<JCheckBox> {
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public JCheckBoxList() {
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox) getModel().getElementAt(index);
checkbox.setSelected(!checkbox.isSelected());
repaint();
}
}
});
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
public JCheckBoxList(ListModel<JCheckBox> model){
this();
setModel(model);
}
protected class CellRenderer implements ListCellRenderer<JCheckBox> {
public Component getListCellRendererComponent(
JList<? extends JCheckBox> list, JCheckBox value, int index,
boolean isSelected, boolean cellHasFocus) {
JCheckBox checkbox = value;
//Drawing checkbox, change the appearance here
checkbox.setBackground(isSelected ? getSelectionBackground()
: getBackground());
checkbox.setForeground(isSelected ? getSelectionForeground()
: getForeground());
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ? UIManager
.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}
For dynamically adding JCheckBox lists you need to create your own ListModel or add the DefaultListModel.
DefaultListModel<JCheckBox> model = new DefaultListModel<JCheckBox>();
JCheckBoxList checkBoxList = new JCheckBoxList(model);
The DefaultListModel are generic and thus you can use methods specified by JAVA 7 API here like this:
model.addElement(new JCheckBox("Checkbox1"));
model.addElement(new JCheckBox("Checkbox2"));
model.addElement(new JCheckBox("Checkbox3"));
I recommend you use a JPanel with a GridLayout of 1 column. Add the checkBoxes to the JPanel, and set the JPanel as the data source of a JScrollPane. And to get the selected CheckBoxes, just call the getComponents() of the JPanel to get the CheckBoxes.
Odds are good w/ Java that someone has already implemented the widget or utility you need. Part of the benefits of a large OSS community. No need to reinvent the wheel unless you really want to do it yourself. In this case it would be a good learning exercise in CellRenderers and Editors.
My project has had great success with JIDE. The component you want, a Check Box List, is in the JIDE Common Layer (which is OSS and hosted on java.net). The commercial stuff is good too, but you don't need it.
http://www.jidesoft.com/products/oss.htm
https://jide-oss.dev.java.net/
I don't like the solutions that put a Checkbox into the model. The model should only contain data not display elements.
I found this http://www.java2s.com/Tutorials/Java/Swing_How_to/JList/Create_JList_of_CheckBox.htm
which I optimized a bit. The ACTIVE flag represents the Checkbox, the SELECTED flag shows what entry the cursor sits on.
my version requires a renderer
import java.awt.Component;
import javax.swing.JCheckBox;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
class CheckListRenderer extends JCheckBox implements ListCellRenderer<Entity> {
#Override
public Component getListCellRendererComponent(JList<? extends Entity> list,
Entity value, int index, boolean isSelected, boolean cellHasFocus) {
setEnabled(list.isEnabled());
setSelected(value.isActive()); // sets the checkbox
setFont(list.getFont());
if (isSelected) { // highlights the currently selected entry
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setText(value.toString()+" - A" + value.isActive()+" - F"+cellHasFocus+" - S"+isSelected );
return this;
}
}
and an entity that got the active field:
public class Entity {
private boolean active = true;
public boolean isActive() {
return active;
}
public void setActive(boolean isActive) {
this.active = isActive;
}
}
Now you only have to add this to your JList:
list = new JList<Entity>();
list.setModel(new DefaultListModel<Entity>());
list.setCellRenderer(new CheckListRenderer());
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent event) {
if (event.getX() < 20) {
// Quick and dirty: only change the tick if clicked into the leftmost pixels
#SuppressWarnings("unchecked")
JList<Entity> list = ((JList<Entity>) event.getSource());
int index = list.locationToIndex(event.getPoint());// Get index of item clicked
if (index >= 0) {
Entity item = (Entity) list.getModel().getElementAt(index);
item.setActive(!item.isActive()); // Toggle selected state
list.repaint(list.getCellBounds(index, index));// Repaint cell
}
}
}
});
All of the aggregate components in Swing--that is, components made up other components, such as JTable, JTree, or JComboBox--can be highly customized. For example, a JTable component normally displays a grid of JLabel components, but it can also display JButtons, JTextFields, or even other JTables. Getting these aggregate components to display non-default objects is the easy part, however. Making them respond properly to keyboard and mouse events is a much harder task, due to Swing's separation of components into "renderers" and "editors." This separation was (in my opinion) a poor design choice and only serves to complicate matters when trying to extend Swing components.
To see what I mean, try enhancing Swing's JList component so that it displays checkboxes instead of labels. According to Swing philosophy, this task requires implementing two interfaces: ListCellRenderer (for drawing the checkboxes) and CellEditor (for handling keyboard and mouse events on the checkboxes). Implementing the ListCellRenderer interface is easy enough, but the CellEditor interface can be rather clumsy and hard to understand. In this particular case, I would suggest forgetting CellEditor entirely and to handle input events directly, as shown in the following code.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
public class CheckBoxList extends JList
{
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public CheckBoxList()
{
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox)
getModel().getElementAt(index);
checkbox.setSelected(
!checkbox.isSelected());
repaint();
}
}
}
);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
protected class CellRenderer implements ListCellRenderer
{
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus)
{
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(isSelected ?
getSelectionBackground() : getBackground());
checkbox.setForeground(isSelected ?
getSelectionForeground() : getForeground());
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ?
UIManager.getBorder(
"List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}
Here, I intercept mouse clicks from the listbox and simulate a click on the appropriate checkbox. The result is a "CheckBoxList" component that is both simpler and smaller than an equivalent component using the CellEditor interface. To use the class, simply instantiate it, then pass it an array of JCheckBox objects (or subclasses of JCheckBox objects) by calling setListData. Note that the checkboxes in this component will not respond to keypresses (i.e. the spacebar), but you could always add your own key listener if needed.
Source: DevX.com
Here is just a little addition to the JCheckBoxList by Rawa. This will add the ability to select using space bar. If multiple items are selected, all will be set to inverted value of the first item.
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
int index = getSelectedIndex();
if (index != -1 && e.getKeyCode() == KeyEvent.VK_SPACE) {
boolean newVal = !((JCheckBox) (getModel()
.getElementAt(index))).isSelected();
for (int i : getSelectedIndices()) {
JCheckBox checkbox = (JCheckBox) getModel()
.getElementAt(i);
checkbox.setSelected(newVal);
repaint();
}
}
}
});
this is yet another example of making list with checkboxes
class JCheckList<T> extends JList<T> {
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public void setSelected(int index) {
if (index != -1) {
JCheckBox checkbox = (JCheckBox) getModel().getElementAt(index);
checkbox.setSelected(
!checkbox.isSelected());
repaint();
}
}
protected static class CellListener
extends DefaultListModel
implements ListDataListener {
ListModel ls;
public CellListener(ListModel ls) {
ls.addListDataListener(this);
int i = ls.getSize();
for (int v = 0; v < i; v++) {
var r = new JCheckBox();
r.setText(ls.getElementAt(v).toString());
this.addElement(r);
}
this.ls = ls;
}
#Override
public void intervalAdded(ListDataEvent e) {
int begin = e.getIndex0();
int end = e.getIndex1();
for (; begin <= end; begin++) {
var r = new JCheckBox();
r.setText(ls.getElementAt(begin).toString());
this.add(begin, r);
}
}
#Override
public void intervalRemoved(ListDataEvent e) {
int begin = e.getIndex0();
int end = e.getIndex1();
for (; begin <= end; end--) {
this.remove(begin);
}
}
#Override
public void contentsChanged(ListDataEvent e) {
}
}
public JCheckList() {
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
int index = locationToIndex(e.getPoint());
setSelected(index);
}
}
);
addKeyListener(new KeyListener(){
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE){
int index = JCheckList.this.getSelectedIndex();
setSelected(index);
}
}
#Override
public void keyReleased(KeyEvent e) {
}
});
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
#Override
public void setModel(ListModel<T> d) {
var r = new CellListener(d);
d.addListDataListener(r);
super.setModel(r);
}
protected class CellRenderer implements ListCellRenderer {
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(isSelected
? getSelectionBackground() : getBackground());
checkbox.setForeground(isSelected
? getSelectionForeground() : getForeground());
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected
? UIManager.getBorder(
"List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}

Categories

Resources