Другой общий случай, когда можно получить это исключение, включает в себя насмешливые классы во время модульного тестирования. Независимо от используемой насмешливой структуры, вы должны убедиться, что все соответствующие уровни иерархии классов должным образом высмеиваются. В частности, все свойства HttpContext
, на которые ссылается тестируемый код, должны быть изделены.
См. « Исключение NullReferenceException при проверке пользовательского AuthorizationAttribute » для несколько подробного примера.
Вы можете удалить прослушиватель действий, прежде чем добавлять новые элементы, и добавить его обратно, как только вы закончите. Качание однопоточное, поэтому нет необходимости беспокоиться о других потоках, требующих увольнения слушателя.
Ваш слушатель, вероятно, также может проверить, что что-то выбрано, и предпринять соответствующие действия, если нет. Лучше, чем получить NPE.
, хотя его поздняя, лучшей альтернативой было бы отключить выпадающее поле, которое должно быть изменено до того, как оно будет изменено. при этом вы предотвращаете события стрельбы из измененного поля со списком, когда, например, вы используете методы like removeAllItems () или 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);
}
}
});
Я как-то пошел глупый простой маршрут с этой проблемой для своей программы, так как я новичок в программировании.
Я изменил прослушиватели действий на наличие счетчика if:
if(stopActionlistenersFromFiringOnLoad != 0){//action performed ;}
Затем в конце создания программы java я добавил 1 к счетчику:
topActionlistenersFromFiringOnLoad += 1;
Что я делаю вместо добавления и удаления прослушивателей действий, у меня есть логическая переменная в моих обработчиках действий, которая истинна, если она должна разрешить действие через или false, если оно должно заблокировать его.
Затем я устанавливаю его в false, когда я делаю некоторые изменения, которые срабатывают при прослушивании действий
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.
Это работает:
/** 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;
}
}
Примечание. Вы не можете просто переопределить setSelectedItem(...)
или setSelectedIndex(...)
, поскольку они также используются внутри, когда элементы фактически выбраны с помощью действий клавиатуры или мыши пользователя, когда вы не хотите препятствовать запуску слушателей.
Чтобы определить, следует ли выполнять различные методы в действии. Методы интерфейса интерфейса (actionPerformed () блоков кода) используют setActionCommand () для исходных компонентов (combo1 или combo2).
Для вашего примера перед добавлением элементов в combo2 вызовите setActionCommand («doNothing») и защитите свой метод comboBoxActionPerformed ().
Вот компилируемый пример, который использует этот принцип для того, чтобы один комбо установил выбранный индекс комбо, также отображая String в JTextField. Используя setActionCommand () и защищая блок кода comboActionPerformed (), JTextField будет циклически перебирать каждое слово в wordBank. Если метод comboActionPerformed () не был защищен или если actionCommand String не была изменена, будет активировано 2 actionEvents, а textField пропустит слова.
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();
}
});
}
}
Более чистый способ заключается в использовании лямбда-выражений следующим образом:
do(comboBox, () -> comboBox.setSelectedItem("Item Name"));
Для того, чтобы вышеприведенное работало, вам нужен следующий метод:
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);
}
}
попробуйте следующее:
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();
}
};