Java ComboBox how to populate on click add item not working - java

it's really simple. I want to populate a jcomboBox but only after the user press the arrow on the combobox.
I think the code is right cause i test it in a separate button and it populate the Combobox but when i create an action listener for the combobox itself it doesn't populate, Here are the code.
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
comboBox.addItem("Item");
comboBox.addItem("Second Item");
}
It's a country city neighborhood situation . What i want is the second to be populated when the first is selected .
The first box is easy to populate (The country box) But the second box (City) I added a switch for it but it just won't populate , What i want to know is there an action i should put my code into for it to populate ?

I want to populate a jcomboBox but only after the user press the arrow on the combobox.
Why would the user look at an empty combo box and then click on the arrow? If the contents of the combo box are based on some other user Action, then that Action should cause the combo box to be populated.
Anyway, maybe you are trying to popuplate the combo box when the dropdown is displayed?
That is the user could click anywhere on the combo box, not just the down arrow.
In this case you can use a PopupMenuListener
comboBox.addPopupMenuListener(new PopupMenuListener()
{
public void popupMenuWillBecomeVisible(PopupMenuEvent e)
{
JComboBox comboBox = (JComboBox)e.getSource();
comboBox.addItem("Item1");
comboBox.addItem("Item2");
comboBox.addItem("Item3");
comboBox.addItem("Item4");
}
public void popupMenuCanceled(PopupMenuEvent e) {}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
});
Edit:
It's a country city neighborhood situation .
Which is a requirement that should have been included with your original question. As people has suggested your approach is wrong. The child combo boxes should be updated when the parent is changed, not when you click the child.
See How to Update Multiple Combo Boxes for a better solution. The example there only shows 2 combo boxes, but the concept is the same for the second and third.

Pressing a JComboBox arrow doesn't trigger the ActionListener. Only making a selection does, and so your combo box will need to be populated before the arrow has been pressed. You'll have to re-think your design such as populating the combo box before the user interacts with it.
If you absolutely needed to add an action listener to the arrow button, it can be done, such as via a recursive method:
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class Foo extends JPanel {
private JComboBox<String> combo = new JComboBox<>();
public Foo() {
add(combo);
combo.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
// this doesn't work!!!
System.out.println("mouse pressed");
super.mousePressed(e);
}
});
recursiveAddAxnListener(combo);
}
private void recursiveAddAxnListener(Component comp) {
if (comp instanceof AbstractButton) {
((AbstractButton) comp).addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("added to combo's button");
}
});
} else if (comp instanceof Container) {
Component[] comps = ((Container) comp).getComponents();
for (Component component : comps) {
recursiveAddAxnListener(component);
}
}
}
private static void createAndShowGUI() {
Foo paintEg = new Foo();
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(paintEg);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
But do I recommend it? No, not at all.
Edit
You have edited your question and have added:
It's a country city neighborhood situation . What i want is the second to be populated when the first is selected .
The first box is easy to populate (The country box) But the second box (City) I added a switch for it but it just won't populate , What i want to know is there an action i should put my code into for it to populate ?
You may be asking an XY-Problem type question where you ask how do I solve X code problem when the best solution is to use an entirely different approach. In this situation I strongly recommend that you not populate the second combobox on mouse press, but rather populate it only once and do it when the first combobox selection has been made. In other words, populate the 2nd combo box in the first combo box's ActionListener. This will simplify things greatly and prevent re-population of the 2nd combobox unnecessarily.

Thank you all for your help , you have been just awesome.
I found the problem I had to have the combobox.removeallItems(); before the switch not in the switch.
This is the testing version of it.and it worked.
JComboBox comboBox = new JComboBox();
comboBox.addItem("");
comboBox.addItem("first");
comboBox.addItem("second");
comboBox.addItem("third");
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
comboBox_1.removeAllItems();
String test = comboBox.getSelectedItem().toString();
switch (test) {
case "first":
comboBox_1.addItem("Tesing");
break;
case "second":
comboBox_1.addItem("Tesing2");
break;
case "third":
comboBox_1.addItem("Tesing three");
break;
default:
break;
}
}
});
Again , i appreciate all the help , Thank you so much.

Related

Java Swing: Controlling focus with textfield and autocompletion dialog/menu

I have a JTextField that I'm trying to add an autocompletion menu to. But I'm having issues with how I should handle the focus.
Here's a SSCCE
package test;
import java.awt.Point;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class SSCCE extends JFrame implements DocumentListener {
private AutocompletionDialog dialog;
public SSCCE() {
dialog = new AutocompletionDialog ();
JTextField textField = new JTextField(20);
textField.getDocument().addDocumentListener(this);
add(textField);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SSCCE().setVisible(true);
}
});
}
public void insertUpdate(DocumentEvent e) {
Point p = this.getLocationOnScreen();
dialog.setLocation(p.x, p.y + 50);
dialog.setVisible(true);
}
public void removeUpdate(DocumentEvent e) { }
public void changedUpdate(DocumentEvent e) { }
private class AutocompletionDialog extends JDialog {
JList<String> list = new JList<>(
new String[] { "One", "Two", "Three" });
AutocompletionDialog() {
setSize(100, 100);
add(list);
}
}
}
Of course there's more logic to it in the real program, but the issue I'm having is that I want to show the autocompletion dialog/menu, but still be able to continue typing in the text field. At the same time, I also want to be able to navigate the menu with the up/down arrows and the enter key, as well as with the mouse, to select one of the completion options.
Can someone please help me with how I should proceed here? Thanks!
EDIT:
Thanks to #camickr's reply I played around a bit with setFocusableWindowState together with an InputMap/ActionMap to always keep the focus in the text field, and manually control the selected list item. The problem is that you get a visual difference when doing it that way compared to if the list had proper focus. See the screen shots.
This is what it looks like if I don't mess with the focus (this is what I want).
This is what it looks like if I run setFocusableWindowState(false)
The main differences are the highlight border (darker blue) around the selected list item, but also the blue highlight around the entire dialog. Then there's also the differences in the title bar.
(Don't mind the render artifacts, I'm connecting to a three year old virtual Linux installation using an old NX client)
EDIT 2:
I was afraid that it was the Look and Feel or OS that determined how the selected list item should look (with the highlighted border for example). But it turns out that it is indeed just the cell renderer that makes that call. Knowing that I felt much better about writing my own cell renderer, and I now have a solution that I'm happy with.
This is the code I ended up using:
private class CellRenderer extends DefaultListCellRenderer
{
#Override
public Component getListCellRendererComponent(
JList<?> jlist, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(
jlist, value, index, isSelected, cellHasFocus);
if (isSelected) {
Border border = UIManager.getBorder(
"List.focusSelectedCellHighlightBorder");
if (border == null) {
border = UIManager.getBorder(
"List.focusCellHighlightBorder");
}
setBorder(border);
}
return this;
}
}
As I show the auto completion menu the focus is given to that dialog.
To prevent focus from going to the popup window you can use:
JDialog dialog = new JDialog(...);
dialog.setFocusableWindowState( false );
...
dialog.setVisible( true );
I also want to be able to navigate the menu with the up/down arrows and the enter key
Then you need to override the default Actions provided by the text field. Check out Key Bindings for more information.
You can also check out: button highlighting using keyboard keys where I just provided a simple example of implementing an Action.

Show jlabel when select an item in jcombobox

I have a jframe that has a jcmbobox with three state (three item, from 0 to 2).
i want when user select second item(1) my jlabel should be display!
But now, when i select second item, Don't show it!
public class LoginFrame extends javax.swing.JFrame {
public LoginFrame() {
initComponents();
this.setTitle("Library Management System Login");
this.setLocation(300, 50);
this.setResizable(false);
if (jComboBox1.getSelectedIndex() == 1) {
jLabel4.setVisible(true);
}
else{
jLabel4.setVisible(false);
}
}
My selected index number in my IDE menu is 0.
Any code in the constructor will not reflect changes made to the selected item in the JComboBox. You need to use a Listener such as an ActionListener to detect these changes:
jComboBox1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jLabel4.setVisible(jComboBox1.getSelectedIndex() == 1);
}
});
Aside: A slight improvement can be made by making the statement use the comparison expression directly in the setVisible statement as shown.
See Handling Events on a Combo Box
You should use ActionListener to do this:
jComboBox1.addActionListener(this);
...
jLabel4.setVisible(jComboBox1.getSelectedIndex() == 1);

How i handle keypress event for Jcombobox in java

I want to add item to JCombobox , that item is what I typed in JCombobox which is item to be add. this jCombox box is editable.
How can i do this.
Ok i tryied add KeyPress event for this JCombo box but it doesn't respose
private void jbcBOXKeyTyped(java.awt.event.KeyEvent evt) {
if (evt.getKeyCode() == 13) {
System.out.println("Keypress");
jbcBOX.addItem(jbcBOX.getSelectedItem().toString());
}
}
Made a short example hope it helps.
Basically just adds ActionListener to JComboBox the ActionListener is called whenever an item is selected or added. In the ActionListener we simply check if there is an item that matches the currently selected item, if not then add the item to JComboBox if a match is found then do nothing:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class EditableJComboBox {
public EditableJComboBox() {
initComponents();
}
private void initComponents() {
JFrame frame = new JFrame("Editable JComboBox");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String labels[] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"};
final JComboBox comboBox = new JComboBox(labels);
comboBox.setEditable(true);
comboBox.addActionListener(new ActionListener() {
private boolean found = false;
#Override
public void actionPerformed(ActionEvent actionEvent) {
String s = (String) comboBox.getSelectedItem();
for (int i = 0; i < comboBox.getItemCount(); i++) {
if (comboBox.getItemAt(i).toString().equals(s)) {
found = true;
break;
}
}
if (!found) {
System.out.println("Added: " + s);
comboBox.addItem(s);
}
found = false;
}
});
frame.add(comboBox);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new EditableJComboBox();
}
});
}
}
This is explained in the Combobox tutorial. No need for dirty KeyListeners and checks for the enter key.
You make the combobox editable
You add an ActionListener which will be triggered when the enter key is hit
In your ActionListener you can update the model
Or to quote that tutorial more literally
JComboBox patternList = new JComboBox(patternExamples);
patternList.setEditable(true);
patternList.addActionListener(this);
An editable combo box fires an action event when the user chooses an item from the menu and when the user types Enter. Note that the menu remains unchanged when the user enters a value into the combo box. If you want, you can easily write an action listener that adds a new item to the combo box's menu each time the user types in a unique value.
It's worse than even this says - it seems (from using Netbeans) keyTyped etc events simply don't fire. I imagine a great number of people are here wondering why they can catch java.awt.event.KeyEvent.getKeyChar() on a JTextField but using exactly the coresponding part of the GUI Builder (in Netbeans) for a JComboBox gets them absolutely nothing!
Handling Events on a Combo Box
...
Although JComboBox inherits methods to register listeners for
low-level events — focus, key, and mouse events, for example — we
recommend that you don't listen for low-level events on a combo box.
Here's why: A combo box is a compound component — it is comprised of
two or more other components. The combo box itself fires high-level
events such as action events. Its subcomponents fire low-level events
such as mouse, key, and focus events. The low-level events and the
subcomponent that fires them are look-and-feel-dependent. To avoid
writing look-and-feel-dependent code, you should listen only for
high-level events on a compound component such as a combo box. For
information about events, including a discussion about high- and
low-level events, refer to Writing Event Listeners.

How to prevent a disabled JMenuItem from hiding the menu when being clicked?

In my Java swing application i have noticed that when i click on a disabled JMenuItem in a JPopupMenu it hides the menu, but i i do not want to hide it, as if nothing is clicked. Is there a way to prevent this ?
-----------------------------------> Update: Added Code sample :
JMenuItem saveMenuItem = new JMenuItem();
saveMenuItem.setEnabled(false);
saveMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
saveMenuItemActionPerformed();
}
});
add(saveMenuItem);
private void saveMenuItemActionPerformed() {
System.out.println( "Save clicked." );
}
This has been tested and works.
The Look & Feel decides how to handle the mouse events on disabled menu items. Anyway, you can intercept the undesired events by using a custom MenuItem. Simply use that code (copy/paste):
public class CustomMenuItem extends JMenuItem {
public CustomMenuItem(String text) {
super(text);
}
public CustomMenuItem() {
super();
}
protected void processMouseEvent(MouseEvent e) {
if (isEnabled()) super.processMouseEvent(e);
}
}
First, adapt the code to suit your needs (optional).
Finally, replace any JMenuItem with a CustomMenuItem.
That's it!
not sure how to prevent. but you can setVisible(false) to prevent it being displayed. Also if a user clicks on the disable menu no action will take place.
When you are disabling JMenuItem, you should remove the ActionListener associated with that JMenuItem by using
jMenuItem.removeActionListener() method.
If u remove that that action will not call the listener and popup will not be disappeared.
I hope this will help to achieve your target.
did you gave a try at this method:
http://download.oracle.com/javase/6/docs/api/javax/swing/JMenuItem.html#setArmed%28boolean%29
"arm the menu item so it can be selected", which I guess would do the trick if set to false.
In short, you can do this, but you will have to write your own mouse listener, which may require a lot of copy&paste from the jdk source code, which is not a very good idea, and I'm not sure about what license restrictions it will put on your code.
I would start digging from this method:
javax.swing.plaf.basic.BasicMenuItemUI.Handler#mouseReleased
which seems to be the entry point from where the menu handling mechanism hides the popup. I would take a closer look at
javax.swing.plaf.basic.BasicPopupMenuUI.MouseGrabber#stateChanged
EDIT Developing answer by #Burhan Valikarimwala, try this apporach: remove all action listeners from the disabled JMenuItem and store them in some static temp structure (let's say a Map<WeakReference<JMenuItem>, List<MouseListener>>), this way it will not hide the popup. When you make the menu item enabled again, add all the listeners back. Make it into some util method and it will be seamless.
The only solution I could come up with, for your problem of a click on disable JMenuItem causing it to hide is below:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
public class PopupMenuDisableNoCloseTest extends JPanel implements ActionListener
{
public static void main(String[] args)
{
PopupMenuDisableNoCloseTest p = new PopupMenuDisableNoCloseTest();
p.setPreferredSize(new Dimension(200, 300));
p.setBackground(Color.GREEN);
JPanel contentPane = new JPanel();
contentPane.add(p);
final JFrame f = new JFrame();
final JPopupMenu popup = new JPopupMenu();
final JMenuItem menuItem1 = new JMenuItem("A popup menu item");
menuItem1.addActionListener(p);
menuItem1.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e)
{
System.out.println(" menuItem1 mousePressed e.getPoint()=" + e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e)
{
System.out.println(" menuItem1 mouseReleased e.getPoint()=" + e.getPoint());
if(!menuItem1.isEnabled())
popup.setVisible(true);
}
});
menuItem1.setEnabled(false);
popup.add(menuItem1);
JMenuItem menuItem2 = new JMenuItem("Another popup menu item");
menuItem2.addActionListener(p);
popup.add(menuItem2);
MouseListener popupListener = new PopupListener(popup);
f.addMouseListener(popupListener);
f.setContentPane(contentPane);
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e)
{
JMenuItem source = (JMenuItem) (e.getSource());
String s = "Action event detected. Event source: " + source.getText();
System.out.println("s=" + s);
}
static class PopupListener extends MouseAdapter
{
JPopupMenu popup;
PopupListener(JPopupMenu popupMenu)
{
popup = popupMenu;
}
#Override
public void mousePressed(MouseEvent e)
{
maybeShowPopup(e);
}
#Override
public void mouseReleased(MouseEvent e)
{
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e)
{
if(e.isPopupTrigger())
{
popup.show(e.getComponent(),
e.getX(), e.getY());
}
}
}
}
Basically the hiding happens when your release is inside the bounds of the JMenuItem, therefore we are checking if it is disabled then we show popup again. As by this time it is already decided that it will be hidden. I was trying calling super.mouseRelease with a different MouseEvent pointing outside component and consuming the previous one but it helps nothing.
Anyway this solution works.
Enjoy, Boro
I think in Java7 this has been fixed.

Using JTextField with Model (on focusLost) and run Actions with model data

I have a Java Swing application, that has many JTextFields and a datamodel.
When leaving the textfields (focus lost), the text is written to the Model. So far, so good.
There are JMenu-Actions that read data from the model and send it to the server.
The Problem is, that the "focus lost" is not fired when running the Menu Action by it's accelerator. So the Actions reads and transmit the old value from the datamodel. .
There may be many ways to fix this...? Do you have suggestions how to solve this?
What doesn't work for me:
Write to model on every key press (via Document Listener): not usable, should only write on leaving textfield (focus lost). The text is (expensively) evaluated after writing it to the model - can not run after every key press.
Handling the writing to model in every action. There ca. 500 Textfields and ca. 100 actions. Diffucult to match without forgetting anything.
Runnable Demo Code:
package swingmodel;
import java.awt.FlowLayout;
import java.awt.event.*;
import javax.swing.*;
/**
* Simple Demo Problem. Enter a Text in the first Textfield and press ALT-T. The
* focus listener did no run, therefore the old value from model is displayed.
*/
public class TextDemoOnMenu extends JPanel {
private Model model;
public TextDemoOnMenu() {
super(new FlowLayout());
model = new Model();
MyTextField textField = new MyTextField(20, model);
add(textField);
add(new JTextField(5));
}
class MyTextField extends JTextField {
private Model model;
public MyTextField(int arg, Model model) {
super(arg);
this.model = model;
addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent e) {
System.out.println("focus lost");
writeToModel();
}
});
}
public void writeToModel() {
this.model.setText(getText());
}
}
class ShowModelTextAction extends AbstractAction {
public ShowModelTextAction(String string) {
super(string);
}
#Override
public void actionPerformed(ActionEvent e) {
String message = "text is: " + model.getText();
JOptionPane.showMessageDialog(TextDemoOnMenu.this, message);
}
}
class Model {
private String text;
void setText(String t) {
text = t;
}
public String getText() {
return text;
}
}
private void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("TextDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add contents to the window.
frame.add(this);
Action action = new ShowModelTextAction("show text");
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("My Menu");
menuBar.add(menu);
JMenuItem menuItem = new JMenuItem("show text");
menuItem.setAction(action);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, ActionEvent.ALT_MASK));
menu.add(menuItem);
frame.setJMenuBar(menuBar);
// Display the window.
frame.setSize(400, 200);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TextDemoOnMenu().createAndShowGUI();
}
});
}
}
You could modify all your Actions to use the KeyboardFocusManager. You would get the current component that has focus. If it is one of your custom text fields, then you can force an update to the model before processing the Action.
The text is (expensively) evaluated after writing it to the model
Also, it sounds like you should be handling focusGained as well. Then can save the original text and do a comparison on the text on focus lost before automatically updating the model. (ie. what if somebody just tabs through all the text fields?).
Create a dirty flag for each textField. If the save event occurs you can update the model with any textField that is dirty.
If you are worried that you will 'forget' to do this for a particular textField it is your management of the textfields that is the problem. You should have a factory method for them that sets them up correctly and creates dirty flags for them.
My other suggestion is to when that save action occurs you request focus to a hidden component to trigger the focusLost on the textField. When the save is completed you give the focus back to the previous owner.

Categories

Resources