I'm looking for a way to pass fields with enter key in VerticalLayout or others. In vaadin book there an example with Shortcut and Handler listeners but I don't know how to implement that.
I'm trying this.
public class MyWindow extends Window implements Handler{
private Action action_enter; //pass fields with enter
private Action action_esc;
private TextField name, lastName;
public MyWindow(){
super("this window is opened");
VerticalLayout vLayout = new VerticalLayout();
setContent(vLayout);
center();
setModal(true);
setClosable(false);
setDraggable(false);
setResizable(false);
//actions
action_enter = new ShortcutAction("Enter key", ShortcutAction.KeyCode.ENTER, null);
action_esc = new ShortcutAction("Esc key", ShortcutAction.KeyCode.ESCAPE, null);
addActionHandler(this);
//fields
name = new TextField("Name");
lastName = new TextField("Last name");
name.focus();
vLayout.addComponent(name);
vLayout.addComponent(lastName);
}
#Override
public Action[] getActions(Object target, Object sender) {
return new Action[] { action_enter, action_esc };
}
#Override
public void handleAction(Action action, Object sender, Object target) {
/** close window with esc key */
if(action == action_esc){
close();
}
/** pass fields with enter key */
if(action == action_enter){
//here pass fields with enter key
}
}
}
any idea ?
try this way with ShortcutListener:
ShortcutListener skEnterListener = new ShortcutListener("Enter", ShortcutAction.KeyCode.ENTER, null){
#Override
public void handleAction(Object sender, Object target) {
if (target instanceof VerticalLayout) { // VerticalLayout or other
// sending fileds here
}
}
};
addShortcutListener(skEnterListener);
change focus of TextField using Enter instead Tab:
final TextField tf1 = new TextField("tf1");
tf1.setId("tf1");
final TextField tf2 = new TextField("tf2");
tf2.setId("tf2");
ShortcutListener skEnterListener = new ShortcutListener("Enter", ShortcutAction.KeyCode.ENTER, null){
#Override
public void handleAction(Object sender, Object target) {
if (target instanceof TextField) {
TextField field = (TextField) target;
if ("tf1".equals(field.getId())) {
tf2.focus();
}
if ("tf2".equals(field.getId())) {
tf1.focus();
}
}
}
};
addShortcutListener(skEnterListener);
There is no interface which does provide an accessor that would allow you finding out the currently focused component. Focus information can be acquired for some (but not all) field components through the com.vaadin.event.FieldEvents.FocusListener and com.vaadin.event.FieldEvents.BlurListener interfaces.
You could add for all possible fields a FocusListener and remember every time it's invoked, the current field in a variable. (Problem: not all fields provide a FocusListener.) Then when ENTER is pressed focus the next component according to the current focused field (remember the variable) that has to be focused (with the help of a simple List, LinkedList, Map, switch-case and so forth). To make it even better add a BlurListener as well to know when not to focus the next field.
Hope that helps.
Related
I have a vaadin ListSelect component on which I would like to remove items if the key DEL is used.
All I found was the ShortcutListener but if I add the following listener, the DEL key does not work in the rest of my application (e.g. deleting text in a TextField):
listSelect.addShortcutListener(new ShortcutListener("", KeyCode.DELETE, null) {
private static final long serialVersionUID = 4703134138899283799L;
#Override
public void handleAction(Object sender, Object target) {
// handle delete
}
});
How should I implement a listener for the DEL key?
EDIT: Tried to use a wrapper Panel as suggested in comments, but it still doesn't work. Here my current code:
listSelect = new ListSelect(null);
listSelect.setWidth(100, Unit.PERCENTAGE);
listSelect.setHeight(82, Unit.PIXELS);
listSelect.setMultiSelect(true);
listSelect.setNullSelectionAllowed(false);
listSelect.setDescription("Löschen mit der DEL Taste");
listSelect.addShortcutListener(new ShortcutListener("", KeyCode.DELETE, null) {
private static final long serialVersionUID = 4703134138899283799L;
#Override
public void handleAction(Object sender, Object target) {
// handle delete
}
});
Panel wrapperPanel = new Panel(listSelect);
form.addComponent(wrapperPanel);
The form is a GridLayout, the parent of form is a Panel. This panel is part of a TabSheet. I'm using Vaadin Version 7.7.1.
Looking at the sources (currently line 110), it seems that the action is delegated to the containing window...
/**
* Keeps track of the Actions added to this component; the actual
* handling/notifying is delegated, usually to the containing window.
*/
private ConnectorActionManager actionManager;
... or parent container at least, because based on this question Select-all shortcut (Ctrl-A) in Vaadin Table? you can work around this issue. If you wrap the list select in a panel and add the short-cut listener to the panel instead, it works as expected:
public class MyListSelectComponent extends VerticalLayout {
public MyListSelectComponent() {
ListSelect list = new ListSelect("Press DEL to remove items");
TextField input = new TextField("Focus this input and press DEL to delete some text");
input.setValue("This is some very long text, or not...");
for (int i = 0; i < 10; i++) {
list.addItem(i);
}
Panel panel = new Panel(list);
panel.addShortcutListener(new ShortcutListener("", ShortcutAction.KeyCode.DELETE, null) {
#Override
public void handleAction(Object sender, Object target) {
if (list.getValue() != null) {
list.removeItem(list.getValue());
}
}
});
addComponent(panel);
addComponent(input);
}
}
Actual output:
I have 2 classes, one class is a JFrame (MainUIHolder.java) and the other class is a JDialog (EditValuationsDialog.java). MainUIHolder can call EditValuationsDialog on button click event.
Once EditValuationsDialog is open, user can enter data in its fields and press its "Add" button. OK, here is the issue now. Once the user press the "Add" button, the EditValuationsDialog should inform that to the MainUIHolder.
Below is the code.
MainUIHolder
Action edit = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
JTable table = (JTable)e.getSource();
int rowNum = Integer.valueOf(e.getActionCommand());
Object valueAt = table.getModel().getValueAt(rowNum, 0);
EditValuationsDialog edit = new EditValuationsDialog(null,true);
edit.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
edit.setTitle("Edit Valuations");
edit.setClientName(portfolioViewClientName.getText());
edit.setPortfolioType(portfolioViewInvestmentTypeCombo.getSelectedItem().toString());
edit.setPortfolioId(id);
edit.setOngoingValuationsId(Integer.parseInt(String.valueOf(valueAt)));
edit.setLocationRelativeTo(table);
edit.setVisible(true);
//CATCH THE CALL FROM EditValuationsDialog HERE!!!!//
}
};
EditValuationsDialog
//Action Listeners
private class AddBtnAction implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
if(someCondition)
{
return String / int to MainUIHolder (See where I want to catch it in MainUIHolder)
}
else
{
do nothing
}
}
}
In my code I have indicated from where the call to MainUIHolder should be generated and in what place I must catch that call in MainUIHolder. How can I do this call back work?
You could...
Add a static method to EditValuationsDialog that shows the dialog, evaluates the results and returns the value you are expecting...
public void actionPerformed(ActionEvent e)
{
int result = EditValuationsDialog.showDialog();
}
public class EditValuationsDialog ... {
//...
private int result = -1;
//...
public int getResult() {
return result;
}
//...
public static int showDialog(Component source, int rowNum, Object valueAt) {
EditValuationsDialog edit = null;
Window parent = SwingUtilities.windowFor(source);
if (parent instanceof Frame) {
edit = new EditValuationsDialog((Frame)parent,true);
} else if (parent instanceof Dialog) {
edit = new EditValuationsDialog((Dialog)parent,true);
} else {
edit = new EditValuationsDialog(null,true);
}
edit.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
edit.setTitle("Edit Valuations");
edit.setClientName(portfolioViewClientName.getText());
edit.setPortfolioType(portfolioViewInvestmentTypeCombo.getSelectedItem().toString());
edit.setPortfolioId(id);
edit.setOngoingValuationsId(Integer.parseInt(String.valueOf(valueAt)));
edit.setLocationRelativeTo(source);
edit.setVisible(true);
return edit.getResult();
}
//...
private class AddBtnAction implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
if(someCondition)
{
result = 0;
}
else
{
result = 1;
}
EditValuationsDialog.this.dispose();
}
}
}
Or you could...
Simply evaluate the results of getResult() from the above example directly...
Side note: Because I don't like extending from top level containers like JDialog, I tend to create some of my panels/components with static showDialog methods, thing something along the lines of a login panel for example. It means I could re-use the panel else where, but provides me with the convenience of been able to popup a dialog when I need to. I've also used JOptionPane from time to time to show these panels, but it depends on the complexity of the available actions...
Make the dialog modal (setModal(true)). Then the code after dialog.setVisible(true) is executed after the dialog is closed.
BTW it's better to pass the MainUIHolder JFrame instance as parent of the dialog.
You could add an interface to the EditValuationsDialog something like this:
Interface EditValuationsDialogInterface {
public void onAddClicked(addedVlue);
}
and then add it as such:
edit.setOnAddButtonCallback(new EditValuationsDialogInterface () {
#Override
onAddClicked(addedVlue){
//DO SOMETHING
}
});
in your EditValuationsDialog's add button onclick call add this:
onAddButtonClickedCallback.onAddClicked(retunrValue);
This allows you to have a direct link back to the original calling class.
I am following the Oracle tutorial on how to create a custom dialog box: http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html
I have two buttons: Save Object and Delete Object which when clicked should execute a certain piece of code. Unfortunately I can't seem to add any ActionListener to the JOptionPane buttons so when they're clicked nothing happens.
Can anyone help tell me how I can go about doing this? Here is the class I have for the dialog box so far:
class InputDialogBox extends JDialog implements ActionListener, PropertyChangeListener {
private String typedText = null;
private JTextField textField;
private JOptionPane optionPane;
private String btnString1 = "Save Object";
private String btnString2 = "Delete Object";
/**
* Returns null if the typed string was invalid;
* otherwise, returns the string as the user entered it.
*/
public String getValidatedText() {
return typedText;
}
/** Creates the reusable dialog. */
public InputDialogBox(Frame aFrame, int x, int y) {
super(aFrame, true);
setTitle("New Object");
textField = new JTextField(10);
//Create an array of the text and components to be displayed.
String msgString1 = "Object label:";
Object[] array = {msgString1, textField};
//Create an array specifying the number of dialog buttons
//and their text.
Object[] options = {btnString1, btnString2};
//Create the JOptionPane.
optionPane = new JOptionPane(array,
JOptionPane.PLAIN_MESSAGE,
JOptionPane.YES_NO_OPTION,
null,
options,
options[0]);
setSize(new Dimension(300,250));
setLocation(x, y);
//Make this dialog display it.
setContentPane(optionPane);
setVisible(true);
//Handle window closing correctly.
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
/*
* Instead of directly closing the window,
* we're going to change the JOptionPane's
* value property.
*/
optionPane.setValue(new Integer(
JOptionPane.CLOSED_OPTION));
}
});
//Ensure the text field always gets the first focus.
addComponentListener(new ComponentAdapter() {
public void componentShown(ComponentEvent ce) {
textField.requestFocusInWindow();
}
});
//Register an event handler that puts the text into the option pane.
textField.addActionListener(this);
//Register an event handler that reacts to option pane state changes.
optionPane.addPropertyChangeListener(this);
}
/** This method handles events for the text field. */
public void actionPerformed(ActionEvent e) {
optionPane.setValue(btnString1);
System.out.println(e.getActionCommand());
}
/** This method reacts to state changes in the option pane. */
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (isVisible()
&& (e.getSource() == optionPane)
&& (JOptionPane.VALUE_PROPERTY.equals(prop) ||
JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
Object value = optionPane.getValue();
if (value == JOptionPane.UNINITIALIZED_VALUE) {
//ignore reset
return;
}
//Reset the JOptionPane's value.
//If you don't do this, then if the user
//presses the same button next time, no
//property change event will be fired.
optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
if (btnString1.equals(value)) {
typedText = textField.getText();
String ucText = typedText.toUpperCase();
if (ucText != null ) {
//we're done; clear and dismiss the dialog
clearAndHide();
} else {
//text was invalid
textField.selectAll();
JOptionPane.showMessageDialog(
InputDialogBox.this,
"Please enter a label",
"Try again",
JOptionPane.ERROR_MESSAGE);
typedText = null;
textField.requestFocusInWindow();
}
} else { //user closed dialog or clicked delete
// Delete the object ...
typedText = null;
clearAndHide();
}
}
}
/** This method clears the dialog and hides it. */
public void clearAndHide() {
textField.setText(null);
setVisible(false);
}
I think you're missing the point of the JOptionPane. It comes with the ability to show it's own dialog...
public class TestOptionPane02 {
public static void main(String[] args) {
new TestOptionPane02();
}
public TestOptionPane02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JTextField textField = new JTextField(10);
String btnString1 = "Save Object";
String btnString2 = "Delete Object";
//Create an array of the text and components to be displayed.
String msgString1 = "Object label:";
Object[] array = {msgString1, textField};
//Create an array specifying the number of dialog buttons
//and their text.
Object[] options = {btnString1, btnString2};
int result = JOptionPane.showOptionDialog(null, array, "", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, "New Object", options, options[0]);
switch (result) {
case 0:
System.out.println("Save me");
break;
case 1:
System.out.println("Delete me");
break;
}
}
});
}
}
To do it manually, you're going to have to do a little more work.
Firstly, you're going to have to listen to the panel's property change events, looking for changes to the JOptionPane.VALUE_PROPERTY and ignoring any value of JOptionPane.UNINITIALIZED_VALUE...
Once you detect the change, you will need to dispose of your dialog.
The you will need extract the value that was selected via the JOptionPane#getValue method, which returns an Object. You will have to interrupt the meaning to that value yourself...
Needless to say, JOptionPane.showXxxDialog methods do all this for you...
Now if you worried about having to go through all the setup of the dialog, I'd write a utility method that either did it completely or took the required parameters...but that's just me
UPDATED
Don't know why I didn't think it sooner...
Instead of passing an array of String as the options parameter, pass an array of JButton. This way you can attach your own listeners.
options - an array of objects indicating the possible choices the user
can make; if the objects are components, they are rendered properly;
non-String objects are rendered using their toString methods; if this
parameter is null, the options are determined by the Look and Feel
For the flexibility you seem to want you should have your class extend JFrame instead of JDialog. Then declare your buttons as JButtons:
JButton saveButton = new JButton("Save"); and add an actionListnener to this button:
saveButton.addActionListener();
either you can put a class name inside the parenthesis of the saveButton, or you can simply pass it the keyword 'this' and declare a method called actionPerformed to encapsulate the code that should execute when the the button is pressed.
See this link for a JButton tutorial with more details:
http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html
I have created a key binding for a JTextArea Component. When invoked, it creates a new instance of itself and sets focus to it.
If you hold down the enter (which invokes key binding) my program will start spitting out bunch of JTextArea instances.
Is there a way to force the user to press enter againg to create a new instance?
Do I have I switch to KeyListeners or is there a way with key bindings?
You specify that a KeyStroke only fire on key release when you're setting up the input map
See KeyStroke getKeyStroke(int keyCode, int modifiers, boolean onKeyRelease)
the way to do it with keybindings is to have two actions:
an action creating the component is bound to the pressed enter, it disables itself when inserting the component
an action enabling the action again is bound to the released enter
Some code:
// the action to create the component
public static class CreateAction extends AbstractAction {
private Container parent;
private Action enableAction;
public CreateAction(Container parent) {
this.parent = parent;
enableAction = new EnableAction(this);
}
#Override
public void actionPerformed(ActionEvent e) {
setEnabled(false);
Component field = createTextField();
parent.add(field);
parent.revalidate();
field.requestFocus();
}
int count;
private Component createTextField() {
// just for fun counting the fields we create
JTextField field = new JTextField("field: " + count++, 20);
field.getInputMap().put(KeyStroke.getKeyStroke("ENTER"),
"createComponent");
field.getActionMap().put("createComponent", this);
field.getInputMap().put(KeyStroke.getKeyStroke("released ENTER"),
"enableCreation");
field.getActionMap().put("enableCreation", enableAction);
return field;
}
}
// the action that enables another
public static class EnableAction extends AbstractAction {
Action toEnable;
public EnableAction(Action toEnable) {
this.toEnable = toEnable;
}
#Override
public void actionPerformed(ActionEvent e) {
toEnable.setEnabled(true);
}
}
// usage
final JComponent parent = new JPanel(new MigLayout("wrap"));
// here I'm lazy and let the action create the very first component as well
add.actionPerformed(null);
add.setEnabled(true);
Note that the same instances of the actions are registered to all components, so it doesn't matter which has the focus (and ultimately enables the creation again)
Here is the code I use, to have an action only run when a key is first pressed down:
private void registerKeyBindings(final JFrame frame) {
var inputMap = frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(KeyCode.G.getInputEventCode(), 0, false), "g_down");
inputMap.put(KeyStroke.getKeyStroke(KeyCode.G.getInputEventCode(), 0, true), "g_up");
frame.getRootPane().getActionMap().put("g_down", new AbstractAction() {
#Override public void actionPerformed(ActionEvent e) {
if (gDown) return;
gDown = true;
// put your custom key-down-action code here
}
});
frame.getRootPane().getActionMap().put("g_up", new AbstractAction() {
#Override public void actionPerformed(ActionEvent e) {
gDown = false;
}
});
}
Boolean gDown = false;
I need your suggestions and guidence on following task.
I have a frame which has two JComboBoxes supposed they are named combo1 and combo2, a JTable and other components.
At initial stage when frame is visible with above component. The combo1 combobox is filled with some values but no value is selected at initial stage, the combo2 combobox is disabled and the table is empty.
I have added an actionListener on combo1 as well as combo2. There are two types of values in combo1 suppose those values are type1 and type2.
Condition 1:
When we selects value type1 from Combo1 the actionListener method is called of combo1 which invokes a method which combo2 remains disabled and adds some rows to table related to selected value type1 from combo1.
Condition 2:
when we selects value type2 from combo1 the actionListener method is called of combo1 which invokes a method who makes combo2 filled with some values related to type2 and gets enabled but no value is selected from combo2 and table also should remain empty until we selects any value from combo2.
table at every addition of value to combo2 the action listener method of combo2 is gets fired. In actionListener method of combo2 which gets combo2 selected value but here there is no selected value of combo2 which leads to a NullPointerException.
So what should I do that the action listner method of combo2 will not be get executed after addition of an values to combo2.
You could remove the action listener before you add the new elements, and add it back once you're done . Swing is single threaded so there is no need to worry about other threads needing to fire the listener.
Your listener could probably also check if something is selected and take appropriate action if not. Better than getting a NPE.
What i do instead of adding and removing action listeners i have a boolean variable in my action listeners that is true if it has to allow the action through or false if it has to block it.
I then set it to false when i do some changes that will fire off the action listener
JComboBox test = new JComboBox();
test.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if(testActionListenerActive)
{
//runn your stuff here
}
}
});
//then when i want to update something where i want to ignore all action evetns:
testActionListenerActive = false;
//do stuff here like add
SwingUtilities.invokeLater(() -> testActionListenerActive = false);
//and now it is back enabled again
//The reason behind the invoke later is so that if any event was popped onto the awt queue
//it will not be processed and only events that where inserted after the enable
//event will get processed.
try this:
indicatorComboBox = new JComboBox() {
/**
* Do not fire if set by program.
*/
protected void fireActionEvent() {
// if the mouse made the selection -> the comboBox has focus
if(this.hasFocus())
super.fireActionEvent();
}
};
although its late, a better alternative would be to disabled the combobox to be modified prior to being modified. by doing so, you prevent firing events of the modified combobox, when for example, you use methods likes removeAllItems() or addItem()
String orderByOptions[] = {"smallest","highest","longest"};
JComboBox<String> jcomboBox_orderByOption1 = new JComboBox<String(orderByOptions);
JComboBox<String> jcomboBox_orderByOption2 = new JComboBox<String(orderByOptions);
JComboBox<String> jcomboBox_orderByOption3 = new JComboBox<String(orderByOptions);
jcomboBox_orderByOption1.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent itemEvent)
{
int eventID = itemEvent.getStateChange();
if (eventID == ItemEvent.SELECTED)
{
Object selectedItem = jcomboBox_orderByOption1.getSelectedItem();
jcomboBox_orderByOption2.setEnabled(false);
jcomboBox_orderByOption2.removeAllItems();
for (String item: string_orderByOptions)
{
if (!item.equals(selectedItem))
{
jcomboBox_orderByOption2.addItem(item);
}
}
jcomboBox_orderByOption2.setEnabled(true);
}
}
});
jcomboBox_orderByOption2.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent itemEvent)
{
int eventID = itemEvent.getStateChange();
if (eventID == ItemEvent.SELECTED)
{
Object selectedItem1 = jcomboBox_orderByOption1.getSelectedItem();
Object selectedItem2 = jcomboBox_orderByOption2.getSelectedItem();
jcomboBox_orderByOption3.setEnabled(false);
jcomboBox_orderByOption3.removeAllItems();
for (String item: string_orderByOptions)
{
if (!item.equals(selectedItem1) && !item.equals(selectedItem2))
{
jcomboBox_orderByOption3.addItem(item);
}
}
jcomboBox_orderByOption3.setEnabled(true);
}
}
});
The cleaner way is to use lambda expressions like this:
do(comboBox, () -> comboBox.setSelectedItem("Item Name"));
For the above to work, you need the following method defined somewhere:
public static void do(final JComboBox<String> component, final Runnable f) {
final ActionListener[] actionListeners = component.getActionListeners();
for (final ActionListener listener : actionListeners)
component.removeActionListener(listener);
try {
f.run();
} finally {
for (final ActionListener listener : actionListeners)
component.addActionListener(listener);
}
}
This works:
/** Implements a Combo Box with special setters to set selected item or
* index without firing action listener. */
public class MyComboBox extends JComboBox {
/** Constructs a ComboBox for the given array of items. */
public MyComboBox(String[] items) {
super(items);
}
/** Flag indicating that item was set by program. */
private boolean isSetByProgram;
/** Do not fire if set by program. */
protected void fireActionEvent() {
if (isSetByProgram)
return;
super.fireActionEvent();
}
/** Sets selected Object item without firing Action Event. */
public void setSelection(Object item) {
isSetByProgram = true;
setSelectedItem(item);
isSetByProgram = false;
}
/** Sets selected index without firing Action Event. */
public void setSelection(int index) {
isSetByProgram = true;
setSelectedIndex(index);
isSetByProgram = false;
}
}
Note: You can't just override setSelectedItem(...) or setSelectedIndex(...) because these are also used internally when items are actually selected by user keyboard or mouse actions, when you do not want to inhibit firing the listeners.
To determine whether or not to perform various methods in actionListener interface methods (actionPerformed() blocks of code) use setActionCommand() on source components (combo1 or combo2).
For your example, before adding elements to combo2, call setActionCommand("doNothing") and guard your comboBoxActionPerformed() method.
Here's a compilable example that uses this principle to have one combo set another combo's selected index while also displaying a String in a JTextField. By using setActionCommand() and guarding the comboActionPerformed() block of code, the JTextField will cycle through each word in the wordBank. If the comboActionPerformed() method was not guarded or if the actionCommand String was not changed, 2 actionEvents will trigger and the textField will skip words.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
/** #author PianoKiddo */
public class CoolCombos extends JPanel {
JComboBox<String> candyCombo;
JComboBox<String> flavorCombo;
JTextField field;
String[] wordBank;
int i = 0;
CoolCombos() {
super();
initComponents();
addComponentsToPanel();
}
private void initComponents() {
initCombos();
initTextField();
}
private void initCombos() {
ActionListener comboListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
comboActionPerformed(e);
}
};
String[] candyList = {"Sourpatch", "Skittles"};
String[] flavorList = {"Watermelon", "Original"};
candyCombo = new JComboBox<>(candyList);
candyCombo.addActionListener(comboListener);
flavorCombo = new JComboBox<>(flavorList);
flavorCombo.addActionListener(comboListener);
}
private void initTextField() {
wordBank = new String[]{"Which", "Do", "You", "Like", "Better?"};
field = new JTextField("xxxxx");
field.setEditable(false);
field.setText(wordBank[i]);
}
private void addComponentsToPanel() {
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(candyCombo);
this.add(flavorCombo);
this.add(field);
}
public void comboActionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (!command.equals("doNothing")) {
JComboBox combo = (JComboBox) e.getSource();
if (combo.equals(candyCombo)) {
setOtherComboIndex(candyCombo, flavorCombo); }
else {
setOtherComboIndex(flavorCombo, candyCombo); }
displayText(); //replace here for toDo() code
}
}
private void setOtherComboIndex(JComboBox combo, JComboBox otherCombo) {
String command = otherCombo.getActionCommand();
otherCombo.setActionCommand("doNothing"); //comment this line to skip words.
otherCombo.setSelectedIndex(combo.getSelectedIndex());
otherCombo.setActionCommand(command);
}
private void displayText() {
i++;
String word;
if (i > 4) { i = 0; }
word = wordBank[i];
field.setText(word);
this.repaint();
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("CoolCombos");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new CoolCombos();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setMinimumSize(frame.getSize());
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
I kind of went the stupid simple route with this issue for my program since I am new to programming.
I changed the action listeners to have a counter if statement:
if(stopActionlistenersFromFiringOnLoad != 0){//action performed ;}
Then at the end of the java program creation, I added 1 to the counter:
topActionlistenersFromFiringOnLoad += 1;
To avoid that addItem method fire events is better to use an DefaultComboBoxModel in the JComboBox to add data. Also, if you invoke a model.addElement(), an event is fired, so, you can add all the elements to the model and later use JComboBox.setModel(model). In this way, if you add elements to the model, events are not fired because you have not link the JComboBox with the model. Then, I show you an example.
private void rellenarArrendatarioComboBox(ArrayList<Arrendatario> arrendatarios) {
DefaultComboBoxModel model = new DefaultComboBoxModel();
model.addElement(new Arrendatario(" -- Seleccione un arrendatario --"));
for (Arrendatario arrendatario : arrendatarios) {
model.addElement(arrendatario);
}
ArrendatarioComboBox.setModel(model);
}
First, we create the model, add all elements to the model (events are not fired because you have not link the JComboBox with the model), we link the model with the JComboBox using ArrendatarioComboBox.setModel(model). After linking, events are fired.