Cemre Mengü
Cemre Mengü

Reputation: 18754

The Stubborn JComboBox

I have a JComboBox shown in the code below. When the program starts its actionPerformed event fires up immediately causing some null pointer exceptions so I want to start with none of the elements selected. However, for some reason it does not work (it always start with displaying "USD/TRY" whatever I do). Anyone has any idea ?

JComboBox comboBox = new JComboBox(new String[]{"USD/TRY", "EUR/TRY", "GBP/TRY"});

comboBox.setSelectedIndex(-1); // doesnt change anything
comboBox.setSelectedIndex(2); // doesnt change anything     
comboBox.setSelectedItem(null); // doesnt change anything

UPDATE: Building the combo box like below doesnt change anything either

JComboBox comboBox = new JComboBox(); 

comboBox.addItem("USD/TRY"); 
comboBox.addItem("EUR/TRY"); 
comboBox.addItem("GBP/TRY"); 

Here is the SSCCE:

public class MainFrame {

    private final JTextArea textArea = new JTextArea();
    private IExchangeSource s;

    public MainFrame(final IExchangeSource s) {
        //build gui
        final JComboBox comboBox = new JComboBox();

        comboBox.addItem("USD/TRY");
        comboBox.addItem("EUR/TRY");
        comboBox.addItem("GBP/TRY");

        comboBox.setSelectedIndex(-1); // doesnt change anything
        //comboBox.setSelectedIndex(2); // doesnt change anything


        JFrame f = new JFrame("Currency Converter");
        JPanel p = new JPanel(new BorderLayout());
        textArea.setName("textarea");
        textArea.setWrapStyleWord(true);
        textArea.setLineWrap(true);
        this.s = s;

        comboBox.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                String exchange = (String) comboBox.getSelectedItem();

                s.getData(exchange);
            }
        });

        p.add(comboBox, BorderLayout.NORTH);
        p.add(textArea, BorderLayout.CENTER);
        f.setPreferredSize(new Dimension(300, 300));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.add(p);
        comboBox.setSelectedIndex(0);
        f.setVisible(true);
    }
}

Upvotes: 4

Views: 4230

Answers (3)

trashgod
trashgod

Reputation: 205775

Your (incomplete) example invokes

comboBox.setSelectedIndex(0);

right before becoming visible, canceling any previous setting. Set the desired initial index before adding the listener, and don't neglect to start on the EDT, as shown in the sscce below.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class MainFrame {

    private final JTextArea textArea = new JTextArea();


    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new MainFrame();
            }
        });
    }
    public MainFrame() {
        //build gui
        final JComboBox comboBox = new JComboBox();

        comboBox.addItem("USD/TRY");
        comboBox.addItem("EUR/TRY");
        comboBox.addItem("GBP/TRY");

        JFrame f = new JFrame("Currency Converter");
        JPanel p = new JPanel(new BorderLayout());
        textArea.setName("textarea");
        textArea.setWrapStyleWord(true);
        textArea.setLineWrap(true);

        comboBox.setSelectedIndex(-1);
        comboBox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println(comboBox.getSelectedItem() + ": " + e);
            }
        });

        p.add(comboBox, BorderLayout.NORTH);
        p.add(textArea, BorderLayout.CENTER);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setSize(new Dimension(300, 300));
        f.add(p);
        f.setVisible(true);
    }
}

Upvotes: 7

user949300
user949300

Reputation: 15729

The suggestions so far are good. But sometimes, when things are really convoluted on how Components get constructed, a more direct fix is needed:

  1. subclass the JComboBox (or whatever Swing class is firing the events, JList, etc...)
  2. add a field, private boolean fireEvents = false; Consider making it volatile.
  3. override the relevant fireXXX() methods to check the status of fireEvents
  4. only set fireEvents = true after all construction and initialization is complete
  5. if a "major overhaul" is later called for, such as on loading a new file, new settings, you can set fireEvents back to false while rebuilding everything.

Upvotes: 0

mKorbel
mKorbel

Reputation: 109815

1) add ItemListener instead of ActionListener, but this ItemListener always fired twice events SELECTED and DESELECTED,

  myComboBox.addItemListener(new ItemListener() {

        @Override
        public void itemStateChanged(ItemEvent e) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                //some stuff
            }
        }
    });

2) your GUI maybe is or isn't created on EventDispashThread, but in this case doesn't matter, you have to delay this method by wraping into invokeLater(), for example

public class MainFrame {
     .
     .
     .

    f.setPreferredSize(new Dimension(300, 300));
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.pack();
    f.add(p);
    comboBox.setSelectedIndex(0);
    f.setVisible(true);
    selectDesiredItem();
}

private void selectDesiredItem() {
  EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            comboBox.setSelectedIndex(-1);
        }
    });  
}

3) better would be implements AutoCompete JComboBox / JTextField for Currency Pairs

4) maybe not important but CcyPairs have got four sides by default

  • Buy BaseCcy

  • Sell BaseCcy

  • Buy VariableCcy

  • Sell VariableCcy

Upvotes: 2

Related Questions