How to use JCombobox inside the JPopupMenu in Swing - java

I'm trying to use JCombobox inside the JPopupMenu, but without success, popup becomes visible when user clicks the label,
label = new JLabel();
label.addMouseListener(this);
this is the label code, with mouse listener, on mousePressed and mouseClicked events it does display and hide popup menu, inside the menu I have JPanel which contains ButtonGroup, click on buttons displays different JPanel's in the center of the panel, short exmaple of panel and popup menu code looks like this
popupPanel = new JPanel();
popupPanel.setLayout(new BorderLayout());
menu = new JPopupMenu();
menu.add(BorderLayout.CENTER, popupPanel);
menu.pack();
menu.addPopupMenuListener(this);
popup panel contains button groups as i mentioned above, when one of the buttons is clicked it displays
color_combo_panel = new JPanel();
color_combo_panel.setLayout(new GridBagLayout());
color_combo = new JComboBox<>();
color_combo.addItem(Color.RED.toString());
color_combo.addItem(Color.BLUE.toString());
color_combo.addItem(Color.CYAN.toString());
color_combo.setRenderer(new ColorRenderer());
panel containing JCombobox, problem starts from here, when I click on combo box to select the color, JPopupMenu gets closed, on the ather hand JCombobox selection does nothing, my question is, how can I force popup menu to stay visible, with mouse and popup listeners i have forced it to stay visible, but as a result I get IllegalComponentStateException, component must be shown on the screen, I found problem similar to mine, but it do not provide relevant solution, plus this behavior is submitted as a BUG here.
will much appreciate any useful advice
EDIT minimal reproducible example asked by #camickr
public class PopupTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(new Dimension(500, 500));
frame.setLayout(new GridBagLayout());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(new ColorCombo());
frame.setVisible(true);
}
static class ColorCombo extends JComboBox {
private static final long serialVersionUID = 2L;
public ColorCombo() {
setPreferredSize(new Dimension(200, 30));
}
#Override
public void updateUI() {
ComboBoxUI cui = (ComboBoxUI) UIManager.getUI(this);
if (cui instanceof MetalComboBoxUI) {
cui = new MetalBrushComboBoxUI();
} else {
cui = new BasicBrushComboboxUI();
}
setUI(cui);
}
class MetalBrushComboBoxUI extends MetalComboBoxUI {
#Override
protected ComboPopup createPopup() {
return new ColorPopup(comboBox);
}
}
class BasicBrushComboboxUI extends BasicComboBoxUI {
#Override
protected ComboPopup createPopup() {
return new ColorPopup(comboBox);
}
}
class ColorPopup extends MouseAdapter implements ComboPopup, ActionListener {
private JList list = new JList();
private JComboBox comboBox;
private JPopupMenu popupMenu;
private JPanel container, first_color_panel;
public ColorPopup(JComboBox comboBox) {
this.comboBox = comboBox;
container = new JPanel();
container.setLayout(new BorderLayout());
JToggleButton first_button = new JToggleButton();
first_button.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2, false));
first_button.setPreferredSize(new Dimension(20, 20));
first_button.setBackground(Color.WHITE);
first_button.addActionListener(this);
first_button.setActionCommand("color1");
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(first_button);
JPanel northPanel = new JPanel();
northPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
northPanel.add(first_button);
first_color_panel = new JPanel();
first_color_panel.setLayout(new GridBagLayout());
JComboBox<String> color_combo = new JComboBox<>();
color_combo.setPreferredSize(new Dimension(120, 30));
for (String color : getColors().keySet())
color_combo.addItem(color);
color_combo.setRenderer(new ColorRenderer());
color_combo.addActionListener(this);
color_combo.setActionCommand("color1_ground");
first_color_panel.add(color_combo);
container.add(northPanel, BorderLayout.NORTH);
popupMenu = new JPopupMenu();
popupMenu.add(BorderLayout.CENTER, container);
}
#Override
public void actionPerformed(ActionEvent e) {
boolean isSet = container.getComponents().length == 2;
if ("color1".equals(e.getActionCommand())) {
if (isSet)
container.remove(1);
container.add(first_color_panel, BorderLayout.CENTER);
}
container.revalidate();
popupMenu.repaint();
}
#Override
public void show() {
this.container.setPreferredSize(new Dimension(this.comboBox.getWidth(), 100));
popupMenu.add(BorderLayout.CENTER, container);
popupMenu.pack();
popupMenu.show(this.comboBox, 0, this.comboBox.getHeight());
}
#Override
public void hide() {
popupMenu.setVisible(false);
}
#Override
public boolean isVisible() {
return popupMenu.isVisible();
}
#Override
public JList getList() {
return list;
}
#Override
public MouseListener getMouseListener() {
return this;
}
#Override
public MouseMotionListener getMouseMotionListener() {
return this;
}
#Override
public KeyListener getKeyListener() {
return null;
}
#Override
public void uninstallingUI() {
}
#Override
public void mouseClicked(MouseEvent e) {
comboBox.requestFocus();
toggle();
}
private void toggle() {
if (isVisible()) {
hide();
} else {
show();
}
}
private Map<String, Color> getColors() {
Map<String, Color> colors = new HashMap<>();
colors.put("Red", Color.RED);
colors.put("blue", Color.BLUE);
colors.put("green", Color.GREEN);
colors.put("Yellow", Color.YELLOW);
return colors;
}
class ColorRenderer extends JPanel implements ListCellRenderer<String> {
#Override
public Component getListCellRendererComponent(JList<? extends String> list, String value, int index, boolean isSelected, boolean cellHasFocus) {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout(3, 3));
panel.setBorder(BorderFactory.createCompoundBorder(getBorder(),
BorderFactory.createEmptyBorder(0, 0, 3, 0)));
JLabel label = new JLabel();
label.setOpaque(true);
label.setPreferredSize(new Dimension(20, label.getHeight()));
label.setBackground(getColors().get(value));
JLabel text = new JLabel();
text.setText(value);
panel.add(label, BorderLayout.WEST);
panel.add(text, BorderLayout.CENTER);
return panel;
}
}
}
}}

Related

Table does not update when selecting combobox

My problem is that a JTable does not update when I select my combobox. The program I present below should delete all data (data = null;), when LA is selected. The table does not update.
public class minimumExample extends JFrame {
private JTabbedPane tabbedPane;
private FilteredTabPanel filteredTabPanel;
public void createTabBar() {
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
filteredTabPanel = new FilteredTabPanel();
tabbedPane.addTab("Test", filteredTabPanel.createLayout());
add(tabbedPane);
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
}
private void makeLayout() {
setTitle("Test App");
setLayout(new BorderLayout());
setPreferredSize(new Dimension(1000, 500));
createTabBar();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public void start() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
makeLayout();
}
});
}
public static void main(String[] args) throws IOException {
minimumExample ex = new minimumExample();
ex.start();
}
public class FilteredTabPanel extends JPanel {
private JPanel selectionArea;
private JLabel lCity;
private JComboBox cityBox;
private JTable filterTable;
String[] columnNames = {"Cities"};
String[][] data = {
{"NY"}, {"NY"}, {"NY"}, {"NY"}, {"LA"}, {"LA"},{"Columbia"},{"DC"},{"DC"},{"DC"},{"DC"},{"DC"},{"DC"}
};
private JScrollPane scrollPane;
public JPanel createLayout() {
JPanel panel = new JPanel(new GridLayout(0, 1));
//add panels to the layout
panel.add(addButtons());
panel.add(showTable());
repaint();
revalidate();
return panel;
}
public JPanel addButtons(){
selectionArea = new JPanel(new FlowLayout(FlowLayout.LEFT));
lCity = new JLabel("City");
String[] fillings = {"NY", "LA", "Columbia", "DC"};
cityBox = new JComboBox(fillings);
cityBox.addActionListener(new ActionListener() {
private String cityFilter;
#Override
public void actionPerformed(ActionEvent arg0) {
//2. get data
cityFilter = cityBox.getSelectedItem().toString();
if(cityFilter.equals("LA")) {
data = null;
}
showTable();
repaint();
}
});
selectionArea.add(lCity);
selectionArea.add(cityBox);
selectionArea.repaint();
return selectionArea;
}
private JScrollPane showTable() {
filterTable =new JTable(data, columnNames);
filterTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
scrollPane = new JScrollPane(filterTable);
scrollPane.repaint();
scrollPane.validate();
return scrollPane;
}
}
}
As you can see the table does not update. Any recommendations what I am doing wrong?
Instead of creating new instance of you objects by calling showTable (which never get added to the screen in any way), which is just going to completely mess up your object references, try resetting the TableModel, for example...
if ("LA".equals(cityFilter)) {
filterTable.setModel(new DefaultTableModel(null, columnNames));
}
Take a closer look at How to Use Tables for more details

Why JPanel.focusGaind and Lost don't work?

Please take a look at the following code (I've missed the imports purposely)
public class MainFrame extends JFrame {
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainFrame frame = new MainFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MainFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
tabbedPane.setBounds(10, 11, 414, 240);
contentPane.add(tabbedPane);
JPanel panel = new JPanel();
panel.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent arg0) {
System.out.println("lost");
// I want to do something here, if I reach here!
}
#Override
public void focusGained(FocusEvent arg0) {
System.out.println("gained");
// I want to do something here, if I reach here!
}
});
tabbedPane.addTab("New tab", null, panel, null);
JButton button = new JButton("New button");
panel.add(button);
JPanel panel_1 = new JPanel();
tabbedPane.addTab("New tab", null, panel_1, null);
JPanel panel_2 = new JPanel();
tabbedPane.addTab("New tab", null, panel_2, null);
}
}
I've created this class to test it and then add the onFocusListener in my main code, but it's not working the way I expect. Please tell what's wrong or is this the right EvenetListener at all?
JPanels are not focusable by default. If you ever wanted to use a FocusListener on them, you'd first have to change this property via setFocusable(true).
But even if you do this, a FocusListener is not what you want.
Instead I'd look to listen to the JTabbedPane's model for changes. It uses a SingleSelectionModel, and you can add a ChangeListener to this model, listen for changes, check the component that is currently being displayed and if your component, react.
You are using setBounds and null layouts, something that you will want to avoid doing if you are planning on creating and maintaining anything more than a toy Swing program.
Edit
For example:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.*;
#SuppressWarnings("serial")
public class MainPanel extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
private static final int GAP = 5;
private static final int TAB_COUNT = 5;
private JTabbedPane tabbedPane = new JTabbedPane();
public MainPanel() {
for (int i = 0; i < TAB_COUNT; i++) {
JPanel panel = new JPanel();
panel.add(new JButton("Button " + (i + 1)));
panel.setName("Panel " + (i + 1));
tabbedPane.add(panel.getName(), panel);
}
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BorderLayout());
add(tabbedPane, BorderLayout.CENTER);
tabbedPane.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent evt) {
Component component = tabbedPane.getSelectedComponent();
System.out.println("Component Selected: " + component.getName());
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
MainPanel mainPanel = new MainPanel();
JFrame frame = new JFrame("MainPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
JPanel is a lightweight container and it is not a Actionable component so it does not get focus events. It lets you add focus listener because of swing component hierarchy. In Order to get tab selected events you need to use JTabbedPane#addChangeListener.
Hope this helps.

JPopupMenu change size dynamically if there is a JPanel inside

I have a JPopupMenu and I want to change it's inner size dynamically depending on it's inner components' size. In my SSCCE I described the problem.
SSCCE:
public class PopupTest2 {
public static void main(String[] a) {
final JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(Color.RED));
final JPopupMenu menu = new JPopupMenu();
// critical step
JPanel itemPanel = new JPanel();
itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));
final JMenuItem[] items = new JMenuItem[10];
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
itemPanel.add(item);
items[i] = item;
}
menu.add(itemPanel);
JToggleButton button = new JToggleButton("Press me");
button.addActionListener(new ActionListener() {
boolean pressed = false;
#Override
public void actionPerformed(ActionEvent e) {
pressed = !pressed;
if (pressed) {
for (JMenuItem item : items) {
item.setText(item.getText()+" changed");
}
} else {
for (JMenuItem item : items) {
item.setText(item.getText().substring(0, item.getText().length() - 8));
}
}
}
});
panel.add(button, BorderLayout.NORTH);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
menu.show(panel, (int) (e.getX() - menu.getPreferredSize().getWidth()), e.getY());
}
}
});
frame.setContentPane(panel);
frame.setUndecorated(true);
frame.setBackground(new Color(50, 50, 50, 200));
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
}
}
Steps 2 reproduce:
Right-click to show popup menu.
Click the Press me button (on the top of window).
Right-click to show popup menu again (bug #1 - popup is still small-size)
Right-click to show popup menu again (popup menu size is OK)
Click the Press me button again.
Right-click to show popup menu. (bug #2 - popup is still large-size)
How can I force JPopupMenu to change its size before showing? And why does it work if I add items directly to popupMenu?
Here is one way to do this:
public static void main(String[] a) {
final JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(Color.RED));
final JPopupMenu menu = new JPopupMenu();
// critical step
final JPanel itemPanel = new JPanel();
itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));
final JMenuItem[] items = new JMenuItem[10];
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
itemPanel.add(item);
items[i] = item;
}
menu.add(itemPanel);
JToggleButton button = new JToggleButton("Press me");
button.addActionListener(new ActionListener() {
boolean pressed = false;
#Override
public void actionPerformed(ActionEvent e) {
pressed = !pressed;
if (pressed) {
for (JMenuItem item : items) {
item.setText(item.getText()+" changed");
item.setMaximumSize(new Dimension(70, 50));
item.setPreferredSize(new Dimension(70, 50));
item.setMinimumSize(new Dimension(70, 50));
itemPanel.invalidate();
}
} else {
for (JMenuItem item : items) {
item.setText(item.getText().substring(0, item.getText().length() - 8));
item.setMaximumSize(new Dimension(130, 50));
item.setPreferredSize(new Dimension(130, 50));
item.setMinimumSize(new Dimension(130, 50));
itemPanel.invalidate();
}
}
}
});
panel.add(button, BorderLayout.NORTH);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
menu.show(panel, (int) (e.getX() - menu.getPreferredSize().getWidth()), e.getY());
}
}
});
frame.setContentPane(panel);
frame.setUndecorated(true);
frame.setBackground(new Color(50, 50, 50, 200));
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
}
Thanks all, but I've found the solution after continuous debugging. The problem was in layout used in JPanel (between Popup and items). It called the getPreferredSize() of JPanel which called directly menuItem.getPrefferedSize(), which called BasicMenuItemUI.getPrefferedSize(). The last method uses the MainMenuLayoutHelper class to get the preferred size. This class stores the data about size in Properties static object.
The default JPopupMenu layout - DefaultMenuLayout - clears this static data each time its preferredLayoutSize() method called, with call MenuItemLayoutHelper.clearUsedClientProperties(popupMenu). We will do the same - call this method with our JPanel parameter with further revalidate() call:
public class PopupTest2 {
public static void main(String[] a) {
final JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel(new BorderLayout());
final JPopupMenu menu = new JPopupMenu();
final JPanel itemPanel = new JPanel();
itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));
final JMenuItem[] items = new JMenuItem[1];
for (int i = 0; i < 1; i++) {
JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
itemPanel.add(item);
items[i] = item;
}
menu.updateUI();
menu.add(itemPanel);
JToggleButton button = new JToggleButton("Press me");
button.addActionListener(new ActionListener() {
boolean pressed = false;
#Override
public void actionPerformed(ActionEvent e) {
pressed = !pressed;
if (pressed) {
for (JMenuItem item : items) {
item.setText(item.getText()+" changed");
}
} else {
for (JMenuItem item : items) {
item.setText(item.getText().substring(0, item.getText().length() - 8));
}
}
}
});
panel.add(button, BorderLayout.NORTH);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
MenuItemLayoutHelper.clearUsedClientProperties(itemPanel);
itemPanel.revalidate();
menu.show(panel, (int) (e.getX() - menu.getPreferredSize().getWidth()), e.getY());
}
}
});
frame.setContentPane(panel);
frame.setUndecorated(true);
frame.setBackground(new Color(50, 50, 50, 200));
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
}
}
PS: Dear reader, it is not the best way to write your code. I do that because I really need that (I have such requirements). If you can build your JPopupMenu without JPanel inside, do not use code in this answer, please.
You have to add
menu.updateUI();
after add menu items.
final JMenuItem[] items = new JMenuItem[10];
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
itemPanel.add(item);
item.setUI(new MyUI());
items[i] = item;
}
menu.updateUI(); <<<<<<--------
menu.add(itemPanel);

Prevent JComboBox rendering on update JLabel

I'm doing an application that play a video and in a JLabel i'm showing timecode of video. Also have a JCombobox that allows to change subtitles of the video.
That JCombobox has a ListCellRenderer that change default output of each item of combobox.
Problem is that each time the JLabel change its value the JCombobox is rendered again.
I think this is a waste of resources there is some way of change that behavior?.
There is the code relative to the JComboBox. The JLabel is modified by a swing.Timer each second.
JComboBox comboBox = new JComboBox<>();
comboBox.setEditable(false);
DefaultComboBoxModel<File> defaultComboBox = new DefaultComboBoxModel<>();
for (File f : Player.capitulo.getFicheros()) {
if (f.getAbsolutePath().endsWith(".srt")) {
System.out.println(f.getAbsolutePath());
defaultComboBox.addElement(f);
}
}
comboBox.setModel(defaultComboBox);
comboBox.setRenderer(new ListRenderer());
public class ListRenderer implements ListCellRenderer<File> {
protected DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer();
#Override
public Component getListCellRendererComponent(JList<? extends File> list,
File value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel renderer = new JLabel();
// JLabel renderer = (JLabel) defaultRenderer
// .getListCellRendererComponent(list, value, index, isSelected,
// cellHasFocus);
if (value != null) {
Path p = value.toPath();
System.out.println(p.getParent());
String language = value.getName().trim().replace(".srt", "");
language = language.substring(language.lastIndexOf(".") + 1,
language.length());
// System.out.println(language.length());
if (language.length() == 3) {
renderer.setText(language);
} else {
renderer.setText("Subtitulo " + (index + 1));
}
}
return renderer;
}
}
UPDATED: Here is an example that reproduce the problem
Ok, here is SSCCE code. Doing the example i noticed that when JLabel es in the same line of JCombobox reproduce the same problem but when is in other line doesn't happen.
public class Example extends JFrame {
private JPanel contentPane;
private JLabel lblNewLabel;
private JComboBox<String> comboBox;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Example frame = new Example();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Example() {
initGUI();
}
private void initGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 428, 362);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
lblNewLabel = new JLabel("New label");
contentPane.add(lblNewLabel, BorderLayout.WEST);
Timer t = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Random r = new Random();
lblNewLabel.setText(String.valueOf(r.nextInt()));
}
});
t.start();
comboBox = new JComboBox<>();
comboBox.setRenderer(new ListCellRenderer<String>() {
#Override
public Component getListCellRendererComponent(
JList<? extends String> list, String value, int index,
boolean isSelected, boolean cellHasFocus) {
JLabel label = new JLabel("");
System.out.println("Pass");
return label;
}
});
contentPane.add(comboBox, BorderLayout.CENTER);
}
}

Adding JList to a JPanel is different from JLabel (aside from the obvious) why?

We have a controller where we have a pre-declared JList and JLabel that we are adding to a JPanel. Outside of the initial layout/adding code I can update a JLabel (e.g. change its text) but I can't change the selection of the JList (e.g. jlist.setSelection(index) ) where it will update the UI. Code Below:
public class Test {
private JPanel myPanel;
private JList myList;
private JLabel myLabel;
public Test() {
//Some init code here...
this.myPanel = new JPanel();
this.myPanel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
String[] values = {"Value1", "Value2", "Value3", "Value4"}; //etc. etc.
this.myList = new JList(values);
this.myPanel.add(this.myList, gbc); //Add to panel
this.myLabel = new JLabel("Label1");
this.myPanel.add(this.myLabel, gbc); //Add to panel
//Add some code here to add it to a frame or something to display
}
public void updateLabel(String workingNewLabel) {
//The following works...
this.myLabel.setText(workingNewLabel);
// as in the label component in the JPanel will
//now be updated to the new value of workingNewLabel
}
public void changeSelectionInListToSomeIndex(int nonWorkingNewIndex) {
//The following does NOT update the JList in the panel...
//the selection remains whatever it was last set to.
this.myList.setSelectedIndex(nonWorkingNewIndex);
}
}
I've been able to get around this by iterating through all the components in myPanel looking for the JList component then set it to to myList eg.
//Code that goes after the line this.myPanel.add(this.myList, gbc);
for(Component component : this.myPanel.getComponents() ) {
//Iterate through it all until...
if (component.getClass() == this.myList.getClass()) {
this.myList = (JList) component; //cast the component as JList
}
}
Why do I need to do this for a JList but not for the JLabel? This is a workaround but it seems extremely hack-ish.
Thanks in advance!
-Daniel
#JB's right. Here's a working sscce:
/** #see http://stackoverflow.com/q/9540263/230513 */
public class Test {
private static Test test = new Test();
private JPanel myPanel;
private JList myList;
private JLabel myLabel;
public Test() {
myPanel = new JPanel();
myPanel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
String[] values = {"Value1", "Value2", "Value3", "Value4"};
myList = new JList(values);
myPanel.add(this.myList, gbc);
myLabel = new JLabel("Label1");
myPanel.add(this.myLabel, gbc);
myPanel.add(new JButton(new AbstractAction("Select Value3") {
#Override
public void actionPerformed(ActionEvent e) {
test.updateList(2);
}
}));
}
public void updateLabel(String label) {
myLabel.setText(label);
}
public void updateList(int index) {
myList.setSelectedIndex(index);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(test.myPanel);
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
});
}
}

Categories