Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как лучше обрабатывать события, implements или внутренний класс 
:(
    Опции темы
JVM
Дата 12.2.2007, 17:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 189
Регистрация: 30.10.2006

Репутация: нет
Всего: 5



Читаю Портянкина. Он советует использовать внутренние классы для обработки событий, но (я не нашел) ничего не говорит о implements XxxxListener
В примерах у sun для обработки событий реализуется implements XxxxListener.
Подскажите, что и когда лучше использовать?
PM MAIL   Вверх
Foo
Дата 12.2.2007, 19:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 164
Регистрация: 20.10.2006

Репутация: 2
Всего: 3



Внутренние классы implements XxxxListener или extends XxxxAdapter. В зависимости от ситуации. Адаптеры это классы которые имплементят стандартные интерфейсы методами с пустой реализацией. Их удобно использовать если мы хотим переопределить только некоторые методы из листенер интерфейса.

пример листенера:
Код

myComponent.addMouseListener(new MyMouseListener());
 
Код

private class MyMouseListener implements MouseListener{
        public void mouseClicked(MouseEvent e) {
            
        }
        public void mousePressed(MouseEvent e) {
            
        }
        public void mouseReleased(MouseEvent e) {
            
        }
        public void mouseEntered(MouseEvent e) {
            
        }
        public void mouseExited(MouseEvent e) {
            
        }
    }


если не хотим использовать все методы, для большей читаемости и красивости кода юзаем адаптер:
Код

myComponent.addMouseListener(new MyMouseAdapter());

Код

private class MyMouseAdapter extends MouseAdapter{
        public void mouseClicked(MouseEvent e) {
            
        }
        public void mouseExited(MouseEvent e) {
            
        }
    }


Также для обработки событий очень удобно использовать Action и InputMap для более гибкой настройки событий.
пример:
Код

        amap = myComponent.getActionMap();
        imap = myComponent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "helpMap");
        amap.put("helpMap", helpAction);

Код

class helpAction implements AbstractAction(){
            public void actionPerformed(ActionEvent e) {
                // do some help action
            }
        });


здесь JComponent.WHEN_IN_FOCUSED_WINDOW - значит что действие актуально если компонент находится в окне с фокусом, есть ещё
JComponent.WHEN_FOCUSED, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT (думаю значение их ясно из названия).

Мы можем назничить практически любое сочетание клавиш на наш экшн. Вот еще примеры:
Код

KeyStroke.getKeyStroke("shift TAB")
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.CTRL_MASK)


Постоянно выполняющиеся экшны лучше выносить в примерно такие классы:
Код

public class OkAction extends AbstractAction{
    protected Handler handler;

    public OkAction(Handler handler) {
        super("ОК");
        putValue("DefaultAction", Boolean.TRUE);
        this.handler = handler;
    }

    public void actionPerformed(ActionEvent e) {
        if (this.handler != null && isEnabled()) {
            this.handler.doOkAction();
        }
    }

    public static interface Handler
    {
        void doOkAction();
    }
}


тогда в класе в котором мы хотим использовать этот action можно сделать так:

Код

class MyClass implements OkAction.Handler{
protected final Action okAction = new OkAction(this);
  public void doOkAction(){
    //actions realization
  }
}

Такую конструкцию например удобно использовать если в проекте много окон, наверняка на многих из них будет кнопка "Ок".


ЗЫ: ногами не бить, описал тут частично свои неопытные соображения по поводу обработки событий.

Это сообщение отредактировал(а) Foo - 12.2.2007, 20:20
--------------------
qip
PM MAIL   Вверх
JVM
Дата 13.2.2007, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 189
Регистрация: 30.10.2006

Репутация: нет
Всего: 5



Foo, спасибо, но это не совсем то что я хотел услышать.
Есть пример http://java.sun.com/docs/books/tutorial/ui...s/ListDemo.java
Я его изменил
Код

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

/* ListDemo.java requires no other files. */
public class ListDemo2 extends JPanel {
    private JList list;
    private DefaultListModel listModel;

    private static final String hireString = "Hire";
    private static final String fireString = "Fire";
    private JButton fireButton;
    private JTextField employeeName;

    public ListDemo2() {
        super(new BorderLayout());

        listModel = new DefaultListModel();
        listModel.addElement("Debbie Scott");
        listModel.addElement("Scott Hommel");
        listModel.addElement("Sharon Zakhour");

        //Create the list and put it in a scroll pane.
        list = new JList(listModel);
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.setSelectedIndex(0);
        MyListener ml = new MyListener();
        list.addListSelectionListener(ml);
        list.setVisibleRowCount(5);
        JScrollPane listScrollPane = new JScrollPane(list);

        JButton hireButton = new JButton(hireString);
        HireListener hireListener = new HireListener(hireButton);
        hireButton.setActionCommand(hireString);
        hireButton.addActionListener(hireListener);
        hireButton.setEnabled(false);

        fireButton = new JButton(fireString);
        fireButton.setActionCommand(fireString);
        fireButton.addActionListener(new FireListener());

        employeeName = new JTextField(10);
        employeeName.addActionListener(hireListener);
        employeeName.getDocument().addDocumentListener(hireListener);
        String name = listModel.getElementAt(
                              list.getSelectedIndex()).toString();

        //Create a panel that uses BoxLayout.
        JPanel buttonPane = new JPanel();
        buttonPane.setLayout(new BoxLayout(buttonPane,
                                           BoxLayout.LINE_AXIS));
        buttonPane.add(fireButton);
        buttonPane.add(Box.createHorizontalStrut(5));
        buttonPane.add(new JSeparator(SwingConstants.VERTICAL));
        buttonPane.add(Box.createHorizontalStrut(5));
        buttonPane.add(employeeName);
        buttonPane.add(hireButton);
        buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
        // buttonPane.setBorder(BorderFactory.createTitledBorder("asd"));

        add(listScrollPane, BorderLayout.CENTER);
        add(buttonPane, BorderLayout.PAGE_END);
    }

    class FireListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            //This method can be called only if
            //there's a valid selection
            //so go ahead and remove whatever's selected.
            int index = list.getSelectedIndex();
            listModel.remove(index);

            int size = listModel.getSize();

            if (size == 0) { //Nobody's left, disable firing.
                fireButton.setEnabled(false);

            } else { //Select an index.
                if (index == listModel.getSize()) {
                    //removed item in last position
                    index--;
                }

                list.setSelectedIndex(index);
                list.ensureIndexIsVisible(index);
            }
        }
    }

    //This listener is shared by the text field and the hire button.
    class HireListener implements ActionListener, DocumentListener {
        private boolean alreadyEnabled = false;
        private JButton button;

        public HireListener(JButton button) {
            this.button = button;
        }

        //Required by ActionListener.
        public void actionPerformed(ActionEvent e) {
            String name = employeeName.getText();

            //User didn't type in a unique name...
            if (name.equals("") || alreadyInList(name)) {
                Toolkit.getDefaultToolkit().beep();
                employeeName.requestFocusInWindow();
                employeeName.selectAll();
                return;
            }

            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(employeeName.getText(), index);
            //If we just wanted to add to the end, we'd do this:
            //listModel.addElement(employeeName.getText());

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

            //Select the new item and make it visible.
            list.setSelectedIndex(index);
            list.ensureIndexIsVisible(index);
        }

        //This method tests for string equality. You could certainly
        //get more sophisticated about the algorithm.  For example,
        //you might want to ignore white space and capitalization.
        protected boolean alreadyInList(String name) {
            return listModel.contains(name);
        }

        //Required by DocumentListener.
        public void insertUpdate(DocumentEvent e) {
            enableButton();
        }

        //Required by DocumentListener.
        public void removeUpdate(DocumentEvent e) {
            handleEmptyTextField(e);
        }

        //Required by DocumentListener.
        public void changedUpdate(DocumentEvent e) {
            if (!handleEmptyTextField(e)) {
                enableButton();
            }
        }

        private void enableButton() {
            if (!alreadyEnabled) {
                button.setEnabled(true);
            }
        }

        private boolean handleEmptyTextField(DocumentEvent e) {
            if (e.getDocument().getLength() <= 0) {
                button.setEnabled(false);
                alreadyEnabled = false;
                return true;
            }
            return false;
        }
    }


        class MyListener implements ListSelectionListener{
    //This method is required by ListSelectionListener.
        public void valueChanged(ListSelectionEvent e) {
            if (e.getValueIsAdjusting() == false) {

                if (list.getSelectedIndex() == -1) {
                //No selection, disable fire button.
                    fireButton.setEnabled(false);

                } else {
                //Selection, enable the fire button.
                    fireButton.setEnabled(true);
                }
            }
        }
        }
    /**
     * 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("ListDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        JComponent newContentPane = new ListDemo2();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        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();
            }
        });
    }
}

т.е. создал внутренний класс class MyListener implements ListSelectionListener и уже в нем реализовывал метод public void valueChanged(ListSelectionEvent e). И вопрос у меня в том, а какой подход лучше использовать тот, который на sun или который использует в своей книге Портянкин?
PM MAIL   Вверх
batigoal
Дата 13.2.2007, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 7
Всего: 151



Цитата(JVM @  13.2.2007,  10:40 Найти цитируемый пост)
И вопрос у меня в том, а какой подход лучше использовать тот, который на sun или который использует в своей книге Портянкин? 

С точки зрения производительности, или еще каких-нибудь объективных параметров, разницы нет. Что тебе кажется более удобным, то и возьми. Разница будет в том, что с помощью implements... ты сможешь обрабатывать события, приходящие от других компонентов, а через внутренние классы - только свои (ну и от дочерних компонентов).


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
JVM
Дата 13.2.2007, 10:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 189
Регистрация: 30.10.2006

Репутация: нет
Всего: 5



Т.е. насколько я понял подход, который использует sun более универсален и позволяет создавать более понятную структуру классов и проще повторно использовать уже написанный код? Или опять же зависит от архитектуры?
PM MAIL   Вверх
LSD
Дата 13.2.2007, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 38
Всего: 538



Я предпочитаю внутренние классы. Ибо нефиг посторонним дергать мои методы. Если я пишу implements..., то любой желающий может дернуть любой метод из этого интерфейса, а я на это не расчитывал.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
JVM
Дата 13.2.2007, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 189
Регистрация: 30.10.2006

Репутация: нет
Всего: 5



А что важнее, чтобы другой не дергал "мои методы"(да и кому нужно их дергать?  smile когда нельзя их дергать) или возможность более быстрой разработки продукта и (у меня такое ощущение) более быстрой работы продукта - одни классы становятся меньше, другие общими и их не надо по нескольку раз загружать?
PM MAIL   Вверх
AntonSaburov
Дата 13.2.2007, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 10
Всего: 118



Однозначного решения скорее всего нет.

Но можно отметить следующий факт - при реакции на определенный тип событий (мышка, кнопка) - наиболее часто бывает надо просто переопределить один самый важный метод. И в этом случае удобнее пользоваться уже готовыми адаптерами.
Я нередко пользуюсь анонимными классами - их-то точно никто дернуть не сможет smile Хотя это на любителя - обычно удобно для каких-либо быстрых локальных решений.

Если же класс может реагировать на несколько видов событий, то скорее всего придется имплементировать интерфейсы полностью. Хотя это встречается не часто.

PM MAIL WWW ICQ   Вверх
KOp4iK
Дата 13.2.2007, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 118
Регистрация: 26.11.2004
Где: Латвия

Репутация: 1
Всего: 3



Тоже задавался этим вопросом... 
С одной стороны когда главный клас implements ActionListener (например). Мы описываем тело метода 
Код

public void actionPerformed(ActionEvent e)

Если у нас один компонент, то получается то же как в случае использования отдельного (анонимного или нет) класса. Но если есть несколько компонентов, которые будет слушать этот листнер, то метод actionPerformed начинает разрастаться... при чём достаточно быстро... 

Кста а вот и пример... У вас есть формочка на ней куча кнопок (зарегистрироваться, отменить регистрацию, получить информацию, обновить таблицу.... итд).. Если следовать примеру Sun'a класс панельки на котором лежат эти кнопки implements ActionListener где в методе 
Код

public void actionPerformed(ActionEvent e)
 в зависимости от e.getActionCommand() выполняется то или иное действие... но представьте что у вас на другой панельке появляется ещё одна кнопка "Зарегицца" которая должна действовать АБСОЛЮТНО аналогично первой кнопке... Что вы будете делать? Повесите на неё огромный листнер? 

С другой стороны всё в одном месте - компактно... да и Sun плохого не посоветует! smile 

Что до меня обычно в конце класса с кнопками я описываю XXXButtonActionListener внутренними классами потом при необходимости выношу их в отдельные если начинаю их юзать из разных мест


PM MAIL   Вверх
LSD
Дата 13.2.2007, 14:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 38
Всего: 538



Цитата(JVM @  13.2.2007,  12:46 Найти цитируемый пост)
да и кому нужно их дергать?   когда нельзя их дергать

У объекта есть контракт - какие методы он предоставляет, и как они себя ведут. Если по контракту объект должен реагировать на actionPerformed(), то пусть будет, иначе этого метода быть не должно. 
Плюс представим себе случай, у нас есть некий сложный компонент, состоящий из нескольких кнопок, полей ввода и т.д. Обрабатывать события от них одним листенером неудобно, гораздо удобной создать по отдельному листенеру на каждое событие.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
force
Дата 21.2.2007, 01:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 71
Регистрация: 20.11.2005

Репутация: нет
Всего: нет



Зависит от ситуации. Если например у меня много кнопок, события нажатия на которые нужно обработать, то просто пишу 
Код

button.addActionListener(this);

И потом уже в actionPerformed проверяю, событие от какой кнопки поступило. Т.е. в меня класс, который содержит объект, у которого возникает событие, реализует соответствующий интерфейс. У нас такой корпоративный стандарт. ВРоде удобно.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   jk1
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, jk1.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: GUI и Java FX приложения | Следующая тема »


 




[ Время генерации скрипта: 0.0771 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.