Некоторые действия JList не выполняются, когда ActionEvent запускается другим методом..? - Ява

Итак, у меня есть кнопка, которая должна добавить нового пользователя (чье имя взято из другого класса) в список после нажатия. Когда я нажимаю кнопку, щелкая ее вручную после сборки и запуска, она работает нормально. Дело в том, что когда я вызываю метод ActionEvent через другой метод, он выводит мой текст System.out.println, но не добавляет никаких новых записей в список.

Какие-либо предложения?

Вот код, который вызывается при нажатии кнопки (строка, отмеченная "‹--", кажется, работает, только если я нажимаю кнопку вручную):

public void actionPerformed(ActionEvent e) {

        listModel.insertElementAt(name, index); // <--
        System.out.println("finished running action");
    }

Вот более полная версия моего кода:

public void actionPerformed(ActionEvent e) {
        System.out.println("ran action");

        addAuthor();
        System.out.println("authornamefinalfunc name: " + name);

        //Reset the text field.
        employeeName.requestFocusInWindow();
        //employeeName.setText("");

        //Select the new item and make it visible.
        list.setSelectedIndex(index);
        list.ensureIndexIsVisible(index);
        System.out.println("ran action final");
    }
    private void addAuthor()
    {
        String name = Global.s;

        int index = list.getSelectedIndex(); //get selected index
        if (index == -1) { //no selection, so insert at beginning
            index = 0;
        } else {           //add after the selected item
            index++;
        }

        listModel.insertElementAt(name, index);

    }

person Community    schedule 17.06.2014    source источник
comment
Было бы проще ответить на ваш вопрос с образцом рабочего кода. Разместите свой код в виде минимального примера, демонстрирующего вашу проблему.   -  person Duncan Jones    schedule 17.06.2014
comment
Хорошо! плохо изменить его сейчас   -  person    schedule 17.06.2014


Ответы (1)


Всегда ли метод addAuthor вызывается в потоке отправки событий? JList (и все в Swing) не синхронизировано или безопасно для потоков, поэтому любые изменения/действия, связанные с Swing, должны выполняться в этом потоке. Поскольку метод addAuthor взаимодействует с компонентами Swing, его никогда нельзя вызывать ни из какого потока, кроме этого. Это относится к любому другому методу, который у вас есть в этом классе (за исключением, возможно, метода main, если он хорошо написан).

Если вам нужно вызвать addAuthor или любой другой метод, который напрямую взаимодействует с компонентами Swing, из потока, который не является потоком отправки событий, используйте что-то вроде этого для вызова метода (предполагается, что ваша форма Swing называется "myUI"):

SwingUtilities.invokeAndWait(new Runnable() {
  @Override public void run() {
    addAuthor();
  }
});

Вы также можете использовать invokeLater, если хотите запустить код, а не ждать его завершения.

Если вы не уверены, из какого потока выполняется код, используйте следующие эмпирические правила:

  1. Any code that is in your main method, or called by your main method (no matter how many levels deep), is run by the "main" thread.
    • For example, your main method calls foo(), which in turn calls bar(), which in turn calls foobar(). All of the code in all of these methods is run by the main thread.
  2. Если вы вручную создаете новый поток, например, с чем-то вроде new Thread(...).start(), этот код и код во всех вызываемых им методах запускаются из этого потока.
  3. Весь код прослушивателя, вызываемый пользовательским интерфейсом (например, ваш ActionListener выше, когда вы нажимаете кнопку), вызывается кодом в потоке отправки событий.

Код, выполняемый в потоке отправки событий, является единственным кодом, который может безопасно взаимодействовать с компонентами Swing. Следовательно, методы с кодом, который взаимодействует с компонентами Swing (например, ваши методы ActionListener и addAuthor), должны вызываться только из кода, работающего в EDT.

Если вы хотите вызвать методы из любого другого потока (1 и 2 выше), вам нужно использовать метод, который я показал вам выше, поскольку вы не можете сделать это напрямую.

person Alvin Thompson    schedule 17.06.2014
comment
Если я помещу это в метод actionPerformed, я получаю сообщение об ошибке: Исключение в потоке AWT-EventQueue-0 java.lang.Error: Невозможно вызвать invokeAndWait из потока диспетчера событий - person ; 17.06.2014
comment
С другой стороны, когда я вызываю метод actionPerformed через другой метод, код просто пропускает его... - person ; 17.06.2014
comment
@ user3749591: Вы не должны помещать этот код в метод ActionPerformed. Метод ActionPerformed уже выполняется в потоке отправки событий, когда он вызывается компонентом Swing. Этот код должен идти в другом методе (тот, где вы вызываете ActionPerformed, но он, похоже, не работает). - person Alvin Thompson; 17.06.2014
comment
@user3749591: Все компоненты и методы в формах Swing должны быть доступны только в потоке отправки событий, иначе у вас возникнут проблемы, подобные той, с которой вы столкнулись. - person Alvin Thompson; 17.06.2014
comment
@ user3749591: Просто опубликуйте свой код для другого метода, и я исправлю его для вас. - person Alvin Thompson; 17.06.2014
comment
@ user3749591: ... но вам действительно нужно узнать, как потоки обрабатываются в Swing, иначе все никогда не будет работать правильно. - person Alvin Thompson; 17.06.2014
comment
@ user3749591: Круто! Я обновил свой ответ, чтобы, надеюсь, прояснить ситуацию. - person Alvin Thompson; 18.06.2014