I have written a renderer for JComboBoxes to replace the milky colour when in
disabled state by a more legible one.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;
public class RendererDemo extends JFrame {
public static final long serialVersionUID = 100L;
String[] items= {"one", "two", "three"};
public RendererDemo() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 100);
JComboBox<Object> cmb = new JComboBox<>(items);
// JComboBox<String> cmb = new JComboBox<>(items);
cmb.setRenderer(new DisabledDarkTextRenderer(cmb));
add(cmb, BorderLayout.NORTH);
JCheckBox check = new JCheckBox("Combo enabled", true);
add(check, BorderLayout.SOUTH);
check.addActionListener(e -> cmb.setEnabled(check.isSelected()));
setVisible(true);
}
static public void main(String args[]) {
EventQueue.invokeLater(RendererDemo::new);
}
class DisabledDarkTextRenderer extends DefaultListCellRenderer {
public static final long serialVersionUID = 50378L;
JComboBox<Object> cmb;
ListCellRenderer<Object> origRenderer;
Object defaultResource= UIManager.get("ComboBox.disabledForeground");
public DisabledDarkTextRenderer(JComboBox<Object> cmb) {
this.cmb= cmb;
origRenderer= cmb.getRenderer();
}
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Component orig= origRenderer.getListCellRendererComponent(list, value,
index, isSelected, cellHasFocus);
if (cmb.isEnabled())
UIManager.put("ComboBox.disabledForeground", defaultResource);
else
UIManager.put("ComboBox.disabledForeground", new ColorUIResource
(Color.GRAY));
return orig;
}
}
}
However, when I declare the JComboBox as being of type <String>, the code fails to compile due to "incompatible types: ListCellRenderer<CAP#1> cannot be converted to ListCellRenderer<Object> ..."
So I tried to make the renderer more general. From all my attempts to modify the
generic type, the following version is the one with only one error left. It's again the above mentioned error, only that it reads now: "incompatible types: JList<CAP#1> cannot be converted to JList<? extends CAP#2> ...".
How to fix this?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;
public class RendererDemo2 extends JFrame {
public static final long serialVersionUID = 100L;
String[] items= {"one", "two", "three"};
public RendererDemo2() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 100);
JComboBox<String> cmb = new JComboBox<>(items);
cmb.setRenderer(new DisabledDarkTextRenderer2(cmb));
add(cmb, BorderLayout.NORTH);
JCheckBox check = new JCheckBox("Combo enabled", true);
add(check, BorderLayout.SOUTH);
check.addActionListener(e -> cmb.setEnabled(check.isSelected()));
setVisible(true);
}
static public void main(String args[]) {
EventQueue.invokeLater(RendererDemo2::new);
}
class DisabledDarkTextRenderer2 extends DefaultListCellRenderer {
public static final long serialVersionUID = 50379L;
JComboBox<?> cmb;
ListCellRenderer<?> origRenderer;
Object defaultResource= UIManager.get("ComboBox.disabledForeground");
public DisabledDarkTextRenderer2(JComboBox<?> cmb) {
this.cmb= cmb;
origRenderer= cmb.getRenderer();
}
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Component orig= origRenderer.getListCellRendererComponent(list, value,
index, isSelected, cellHasFocus);
if (cmb.isEnabled())
UIManager.put("ComboBox.disabledForeground", defaultResource);
else
UIManager.put("ComboBox.disabledForeground", new ColorUIResource
(Color.GRAY));
return orig;
}
}
}
Following MadProgrammer's advice my renderer now looks like this:
class DisabledDarkTextRenderer2<T> extends DefaultListCellRenderer {
public static final long serialVersionUID = 50379L;
JComboBox<T> cmb;
ListCellRenderer<?> origRenderer;
Object defaultResource= UIManager.get("ComboBox.disabledForeground");
public DisabledDarkTextRenderer2(JComboBox<T> cmb) {
this.cmb= cmb;
origRenderer= cmb.getRenderer();
}
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Component orig= origRenderer.getListCellRendererComponent(list, value,
index, isSelected, cellHasFocus);
if (cmb.isEnabled())
UIManager.put("ComboBox.disabledForeground", defaultResource);
else
UIManager.put("ComboBox.disabledForeground", new ColorUIResource
(Color.GRAY));
return orig;
}
}
but the compile time error persists.
I am using this renderer for combos which change their state at runtime. So I am free from caring in each program to set the colour when needed, as the renderer is doing this automatically for me.
You need to "genericfy" your DisabledDarkTextRenderer2, as an example...
class DisabledDarkTextRenderer2<T> implements ListCellRenderer<T> {
public static final long serialVersionUID = 50379L;
private JComboBox<T> combobox;
private ListCellRenderer<? super T> origRenderer;
public DisabledDarkTextRenderer2(JComboBox<T> combobox) {
this.combobox = combobox;
this.origRenderer = combobox.getRenderer();
}
public static <T> void install(JComboBox<T> combobox) {
combobox.setRenderer(new DisabledDarkTextRenderer2<T>(combobox));
}
#Override
public Component getListCellRendererComponent(JList<? extends T> list, T value, int index, boolean isSelected, boolean cellHasFocus) {
Component orig = origRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (combobox.isEnabled()) {
orig.setForeground(null);
} else {
orig.setForeground(Color.GRAY);
}
return orig;
}
}
Now, having said that, I would discourage you from using UIManager within the renderer, as this will effect ALL components rendered after the change, which may or may not be your desired goal, if so, then just set the value at the start of the application.
The following example will make the default disabled foreground color RED for all comboboxes without you having to do anything else at all.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.ColorUIResource;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
UIManager.put("ComboBox.disabledForeground", new ColorUIResource(Color.RED));
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(32, 32, 32, 32));
JComboBox<String> cmb = new JComboBox<>(new String[]{"Hello", "Goodbye"});
cmb.setSelectedIndex(0);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(cmb, gbc);
JButton toggle = new JButton("Toggle");
toggle.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cmb.setEnabled(!cmb.isEnabled());
}
});
add(toggle, gbc);
}
}
}
Related
I have added a checkbox into JList its working successfully but problem is it not select multiple checkbox in same time and the multi-selection code for checkbox not working and I also add the image.
lstsubsub.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
public class CheckboxListCellRenderer extends JCheckBox implements
ListCellRenderer {
#Override
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;
}
}
Don't use a JList for the JCheckBoxes... Use a JPanel with GridLayout like so:
import java.awt.GridLayout;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JPanel {
private final JCheckBox checkReg, checkPerm, checkAcc;
public Main() {
super(new GridLayout(0, 1)); //1 column, any number of rows...
super.add(checkReg = new JCheckBox("User Registration"));
super.add(checkPerm = new JCheckBox("User Permission"));
super.add(checkAcc = new JCheckBox("User Accounts"));
}
public static void main(final String[] args) {
final JFrame frame = new JFrame("List of checkboxes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Main());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I'm writing a GUI using Swing. I have a custom written JComboBox using a ListCellRenderer and a BasicComboBoxEditor.
In my getListCellRendererComponent() method I change the color of the the list based on whether the item is "selected" (mouse is hovering above), which is nice and all, but I don't want the selection to change background color once a choice is made, which it currently does.
The first picture shows how the interface looks before a selection is made, and the second one shows how it looks after.
QUESTION
How do I change the background of the "selection" to the "stockColor"?
MCVE
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.Vector;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.plaf.basic.BasicComboBoxEditor;
public class TFComboBox extends JComboBox{
public static void main(String[] args){
createAndShowGUI();
}
public static void createAndShowGUI(){
JFrame frame = new JFrame("MCVE");
JPanel pane = new JPanel(new BorderLayout());
TFComboBox cb = new TFComboBox();
boolean[] tf = {true, false};
cb.addItems(tf);
JButton b = new JButton("Click me!");
pane.add(cb, BorderLayout.CENTER);
pane.add(b, BorderLayout.LINE_END);
frame.add(pane);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private DefaultComboBoxModel model;
private Vector<Boolean> comboBoxItems;
private JComboBox comboBox;
public TFComboBox(){
comboBoxItems = new Vector<Boolean>();
comboBoxItems.add(Boolean.TRUE);
comboBoxItems.add(Boolean.FALSE);
comboBox = new JComboBox(comboBoxItems);
model = new DefaultComboBoxModel();
setModel(model);
setRenderer(new TrueFalseComboRenderer());
setEditor(new TrueFalseComboEditor());
}
public void addItems(boolean[] items){
for(boolean anItem : items){
model.addElement(anItem);
}
}
}
class TrueFalseComboRenderer extends JPanel implements ListCellRenderer {
private JLabel labelItem = new JLabel();
private Color stockColor = labelItem.getBackground();
public TrueFalseComboRenderer(){
setLayout(new BorderLayout());
labelItem.setOpaque(true);
labelItem.setHorizontalAlignment(JLabel.CENTER);
add(labelItem);
setBackground(Color.LIGHT_GRAY);
}
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
boolean tempValue = (boolean) value;
labelItem.setText(Boolean.toString(tempValue));
if(isSelected){
labelItem.setBackground(stockColor.darker());
labelItem.setForeground(Color.WHITE);
} else {
labelItem.setBackground(stockColor);
labelItem.setForeground(Color.BLACK);
}
return this;
}
}
class TrueFalseComboEditor extends BasicComboBoxEditor {
private JLabel labelItem = new JLabel();
private JPanel panel = new JPanel();
private Object selectedItem;
public TrueFalseComboEditor() {
labelItem.setOpaque(false);
labelItem.setHorizontalAlignment(JLabel.CENTER);
labelItem.setForeground(Color.WHITE);
panel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 2));
panel.setBackground(Color.BLUE);
panel.add(labelItem);
}
public Component getEditorComponent(){
return this.panel;
}
public Object getItem(){
return this.selectedItem;
}
public void setItem(Object item){
if(item == null){
return;
}
this.selectedItem = item;
labelItem.setText(item.toString());
}
}
EDIT
I've added a MCVE and as you can see it is the "problem" that the JComboBox is focused that has to do with my issue. I've placed a button next to the ComboBox to help with removing the focus from the ComboBox.
Simply doing a setFocusable(false) would fix it, but also take away some of the functionality of the rest of the program, so this is not desired.
for better help sooner post an SSCCE / MCVE, short, runnable, compilable, with hardcoded value for JComboBox / XxxComboBoxModel in local variable
JList has Boolean array implemented as default in API (no idea whats hidden in
String trueFalseItem = Boolean.toString(tempValue); and with value stored JComboBox model)
this is just code minimum to test isSelected and to change JList.setSelectionXxx inside DefaultListCellRenderer
for example (code in SSCCE / MCVE form)
.
.
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.SwingUtilities;
public class ComboBoxBooleanModel {
private javax.swing.Timer timer = null;
private Vector<Boolean> comboBoxItems;
private JComboBox box;
public ComboBoxBooleanModel() {
comboBoxItems = new Vector<Boolean>();
comboBoxItems.add(Boolean.TRUE);
comboBoxItems.add(Boolean.FALSE);
box = new JComboBox(comboBoxItems);
box.setRenderer(new DefaultListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
if (Boolean.TRUE.equals(value)) {
l.setBackground(Color.RED);
if (isSelected) {
list.setSelectionForeground(Color.RED);
list.setSelectionBackground(Color.BLUE);
}
} else if (Boolean.FALSE.equals(value)) {
l.setBackground(Color.BLUE);
if (isSelected) {
list.setSelectionForeground(Color.BLUE);
list.setSelectionBackground(Color.RED);
}
}
return l;
}
return c;
}
});
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(box);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
box.setSelectedIndex(1);
}
});
start();
}
private void start() {
timer = new javax.swing.Timer(2250, updateCol());
timer.start();
}
public Action updateCol() {
return new AbstractAction("text load action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
if (box.getSelectedItem() == (Boolean) false) {
box.setSelectedItem((Boolean) true);
} else {
box.setSelectedItem((Boolean) false);
}
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ComboBoxBooleanModel comboBoxModel = new ComboBoxBooleanModel();
}
});
}
}
Here is a short demo of 2 JCombos, one of which will not change its background color when selected :
public static void main(String[] args){
JFrame frame = new JFrame("Combos BG Color test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.getContentPane().setPreferredSize(new Dimension(400, 40));
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new GridLayout(1,2));
frame.add(mainPanel);
JComboBox<String> aCombo = new JComboBox<>(new String[]{"A","B","C"});
mainPanel.add(aCombo);
JComboBox<String> bCombo = new JComboBox<>(new String[]{"1","2","3"});
Color bgColor = bCombo.getBackground();
bCombo.setRenderer(new DefaultListCellRenderer() {
#Override
public void paint(Graphics g) {
setBackground(bgColor);
super.paint(g);
}
});
mainPanel.add(bCombo);
frame.pack();
frame.setVisible(true);
}
(Most of the credit goes to this answer)
I searched for the answer for quite awhile , but most cases were different from mine.
I want to add a JButton directly after the last row of the table, the table is dynamic and is inside a scrollPane.
almost all of the other questions were answered with a button added after scrollPane in BorderLayout.South , which is not what i want.
thanks
updated the picture to better represent it, the button should appear inside the scrollPane just after the last row.
Read more about different LayoutManager's. Use proper manager or combination of them.
Here is simple example:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class TestFrame extends JFrame {
public TestFrame() {
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void init() {
JTable t = new JTable(3,3);
add(new JScrollPane(t));
JPanel btns = new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));
JButton jButton = new JButton("here");
btns.add(jButton);
add(btns,BorderLayout.SOUTH);
}
public static void main(String args[]) {
new TestFrame();
}
}
EDIT:
Try to use next example:
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
public class TestFrame extends JFrame {
public TestFrame() {
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void init() {
JTable t = new JTable(new DefaultTableModel(3,3){
#Override
public boolean isCellEditable(int row, int column) {
if(row == getRowCount()-1 && column != 0){
return false;
}
return super.isCellEditable(row, column);
}
});
t.setGridColor(t.getTableHeader().getBackground());
add(new JScrollPane(t));
for(int i=0;i<3;i++)
t.getColumnModel().getColumn(i).setCellRenderer(getDummyRenderer());
t.getColumnModel().getColumn(0).setCellEditor(getDummyEditor());
}
private TableCellEditor getDummyEditor() {
return new DummyEditor();
}
private TableCellRenderer getDummyRenderer() {
return new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if(row == table.getRowCount()-1){
if(column == 0){
return new JButton("dummy");
} else {
JLabel jLabel = new JLabel("");
jLabel.setOpaque(true);
jLabel.setBorder(null);
return jLabel;
}
} else {
Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
return tableCellRendererComponent;
}
}
};
}
public static void main(String args[]) {
new TestFrame();
}
private class DummyEditor extends DefaultCellEditor implements TableCellEditor{
private JButton btn = new JButton("dummy");
public DummyEditor(){
super(new JTextField());
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("clicked");
}
});
}
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
return row == table.getRowCount()-1 ? btn : super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
}
Hi i have created a j list and there i want to add an image before any text in that text how can i do this i tried but i am not able to achieve my goal i want to add an image before list element"Barmer".
public class ListDemo extends JPanel
implements ListSelectionListener {
private JList list;
private DefaultListModel listModel;
public ListDemo() {
super(new BorderLayout());
listModel = new DefaultListModel();
listModel.addElement("Barmer");
//Create the list and put it in a scroll pane.
list = new JList(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setSelectedIndex(0);
list.addListSelectionListener(this);
list.setVisibleRowCount(5);
list.setBackground(new java.awt.Color(0,191,255));;
list.setFont(new Font("Arial",Font.BOLD,35));
list.setForeground( Color.white );
list.setFixedCellHeight(60);
list.setFixedCellWidth(50);
list.setBorder(new EmptyBorder(10,20, 20, 20));
JScrollPane listScrollPane = new JScrollPane(list);
add(listScrollPane, BorderLayout.CENTER);
}
public void valueChanged(ListSelectionEvent e) {
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("ListDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new ListDemo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setUndecorated(true);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
createAndShowGUI();
}
}
How can i do this help me?
Thanks in advance
You want to look as a custom ListCellRenderer. You can look at Provding a Custom Renderer for JComboBox. It the same for a JList. The tutorial over-complicates a bit for simple scenarios. They extends JLabel and implements ListCellRender where you have to implement a few unnecessary things if you just want basic functionality but with am image.
You can just instead extends or create a anonymous DefaultListCellRender and just get the JLabel render component and add to it, like setting Font and ImageIcon. Something like this
public class MarioListRenderer extends DefaultListCellRenderer {
Font font = new Font("helvitica", Font.BOLD, 24);
#Override
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
label.setIcon(imageMap.get((String) value));
label.setHorizontalTextPosition(JLabel.RIGHT);
label.setFont(font);
return label;
}
}
What happens is that each cell uses this renderer and calls the getListCellRendererComponent method. The value you see passed to the method is the value in each cell, in my case, one of the character names in the list. I then map that to the corresponding ImageIcon and set the Icon on the JLabel renderer component.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.util.HashMap;
import java.util.Map;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class MarioList {
private final Map<String, ImageIcon> imageMap;
public MarioList() {
String[] nameList = {"Mario", "Luigi", "Bowser", "Koopa", "Princess"};
imageMap = createImageMap(nameList);
JList list = new JList(nameList);
list.setCellRenderer(new MarioListRenderer());
JScrollPane scroll = new JScrollPane(list);
scroll.setPreferredSize(new Dimension(300, 400));
JFrame frame = new JFrame();
frame.add(scroll);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class MarioListRenderer extends DefaultListCellRenderer {
Font font = new Font("helvitica", Font.BOLD, 24);
#Override
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
label.setIcon(imageMap.get((String) value));
label.setHorizontalTextPosition(JLabel.RIGHT);
label.setFont(font);
return label;
}
}
private Map<String, ImageIcon> createImageMap(String[] list) {
Map<String, ImageIcon> map = new HashMap<>();
for (String s : list) {
map.put(s, new ImageIcon(
getClass().getResource("/marioscaled/" + s + ".png")));
}
return map;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MarioList();
}
});
}
}
Side Note
AndrewThompson is correct about just checking the tutorial first. You could have easily found an example implementation, then tried it out. Swing tutorials can be found here. Look under the Using Swing Components for how to use different components.
Swing apps should be run on the Event Dispatch Thread (EDT). You can do so by wrapping your creatAndShowGui() in a SwinUtilities.invokeLater.... See more at Initial Threads
UPDATE with internet images.
new Code
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class MarioList {
private final Map<String, ImageIcon> imageMap;
public MarioList() {
String[] nameList = {"Mario", "Luigi", "Bowser", "Koopa", "Princess"};
imageMap = createImageMap(nameList);
JList list = new JList(nameList);
list.setCellRenderer(new MarioListRenderer());
JScrollPane scroll = new JScrollPane(list);
scroll.setPreferredSize(new Dimension(300, 400));
JFrame frame = new JFrame();
frame.add(scroll);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class MarioListRenderer extends DefaultListCellRenderer {
Font font = new Font("helvitica", Font.BOLD, 24);
#Override
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
label.setIcon(imageMap.get((String) value));
label.setHorizontalTextPosition(JLabel.RIGHT);
label.setFont(font);
return label;
}
}
private Map<String, ImageIcon> createImageMap(String[] list) {
Map<String, ImageIcon> map = new HashMap<>();
try {
map.put("Mario", new ImageIcon(new URL("http://i.stack.imgur.com/NCsHu.png")));
map.put("Luigi", new ImageIcon(new URL("http://i.stack.imgur.com/UvHN4.png")));
map.put("Bowser", new ImageIcon(new URL("http://i.stack.imgur.com/s89ON.png")));
map.put("Koopa", new ImageIcon(new URL("http://i.stack.imgur.com/QEK2o.png")));
map.put("Princess", new ImageIcon(new URL("http://i.stack.imgur.com/f4T4l.png")));
} catch (Exception ex) {
ex.printStackTrace();
}
return map;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MarioList();
}
});
}
}
Designing a custom JTable I already know that DefaultCellEditor admits a JComboBox in his constructor. This JComboBox, when clicked to display the list items, shows above the other cells of the JTable. The problem is that I need a more sophisticated behavior as what JComboBox offers, so that I've implemented a JTextField with a JList and a JButton, when the JButton gets clicked (or the user enters text in the JTextField) the elements in the JList become visible. This 3 elements are in a JPanel. When I try to use this panel as a cell editor (extending AbtractCellEditor and implementing TableCellEditor) the elements in the list show inside the editing cell but I cannot mimic the behavior of the DefaultCellEditor with the combo so that the list elements show above the JTable.
Here I define the custom cell editor: (very short version);
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.TableCellEditor;
public class CustomCellEditor extends AbstractCellEditor implements TableCellEditor {
private JList list;
private JButton button;
private JTextField editor;
private JPanel mainPanel;
public CustomCellEditor() {
list = new JList(new String[] { "One", "Two", "Three" });
editor = new JTextField();
button = new JButton("Click me ");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
list.setVisible(!list.isVisible());
}
});
JPanel auxPanel = new JPanel(new BorderLayout());
auxPanel.add(editor, BorderLayout.CENTER);
auxPanel.add(button, BorderLayout.EAST);
mainPanel = new JPanel(new BorderLayout());
mainPanel.add(auxPanel, BorderLayout.NORTH);
mainPanel.add(list, BorderLayout.CENTER);
}
#Override
public Object getCellEditorValue() {
return editor.getText();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
return mainPanel;
}
}
And this a main program with a jtable with this panel as a cell editor:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
public class CustomTable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CustomTable instance = new CustomTable();
instance.createAndShowUI();
}
});
}
private void createAndShowUI() {
JTable table = new JTable(new CustomTableModel());
//So that I can see the contents of the list when edited
table.setRowHeight(60);
TableColumn editableColumn = table.getColumnModel().getColumn(0);
editableColumn.setPreferredWidth(250);
editableColumn.setCellEditor(new CustomCellEditor());
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(table, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
private class CustomTableModel extends AbstractTableModel {
private final String[] columnNames = {"Editable column", "Other column"};
private final Object[][] data = {
{"Ricardo", "Mr."},
{"Josefina", "Ms."}
};
#Override
public int getRowCount() {
return data.length;
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return data[rowIndex][columnIndex];
}
#Override
public boolean isCellEditable(int row, int col) {
if (0 == col)
return true;
return false;
}
#Override
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
}
Can someone help me?
Thanks!!
Using a JComboBox as a table editor relies on it being a button that displays a popup component when pressed. As you have several components in a cell, consider these alternatives:
Add the components to a panel, as shown here for a group of JRadioButton instances.
Add the components to a modal dialog, as shown here using JDialog.