.class после интерфейса с пользовательскими событиями в Java Swing - PullRequest
0 голосов
/ 15 мая 2018

Я изучаю Java Swing и обнаружил расширенный (на мой взгляд) код Swing с использованием шаблонов MVC и Observer. Это очень сложно для меня, и я пытаюсь это понять. И у меня есть 2 вопроса:

  1. Что именно делает DetailListener.class? Это первый раз, когда я использую .class после интерфейса. Я попытался выполнить поиск по стеку на предмет «синтаксиса .class» и вижу, что его можно использовать после класса, но я до сих пор не понимаю, что он делает в этой ситуации.

  2. Что именно делает метод fireDetailEvent ()?

Заранее спасибо!

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class App {

    public static void main(String args[]) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {

                JFrame frame = new MainFrame("Hello world Swing");
                frame.setSize(500, 400);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
                frame.setVisible(true);
            }
        });
    }
}

MainFrame

import java.awt.BorderLayout;
import java.awt.Container;

import javax.swing.JFrame;
import javax.swing.JTextArea;

public class MainFrame extends JFrame {

    private JTextArea textArea;

    public MainFrame(String title) {

        super(title);

        Container c = getContentPane();

        c.setLayout(new BorderLayout()); 

        textArea = new JTextArea();

        DetailsPanel detailsPanel = new DetailsPanel();

        detailsPanel.addDetailListener(new DetailListener() {

            public void detailEventOccurred(DetailEvent event) {

                String text = event.getText();
                textArea.append(text); 
            }
        });

        c.add(textArea, BorderLayout.CENTER);
        c.add(detailsPanel, BorderLayout.WEST);
    }
}

DetailsPanel

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.EventListenerList;

public class DetailsPanel extends JPanel {

    private static final long serialVersionUID = -5115286206114930420L;

    private EventListenerList listenerList = new EventListenerList();

    public DetailsPanel() {

        Dimension size = getPreferredSize();
        size.width = 250;
        setPreferredSize(size); 

        setBorder(BorderFactory.createTitledBorder("Personal details"));

        JLabel nameLabel = new JLabel("Name:");
        JLabel occupationLabel = new JLabel("Occupation:");

        JTextField nameField = new JTextField(10);
        JTextField occupationField = new JTextField(10);

        JButton addBtn = new JButton("Add");

        setLayout(new GridBagLayout());

        GridBagConstraints gc = new GridBagConstraints();

        ////// First column /////
        gc.anchor = GridBagConstraints.LINE_END;


        gc.weightx = 0.5;
        gc.weighty = 0.5;

        gc.gridx = 0;
        gc.gridy = 0;
        add(nameLabel, gc);

        gc.gridy = 1;
        add(occupationLabel, gc);

        ////// Second column /////

        gc.anchor = GridBagConstraints.LINE_START;

        gc.gridx = 1;
        gc.gridy = 0;
        add(nameField, gc);

        gc.gridy = 1;
        add(occupationField, gc);

        //////  Final row /////

        gc.anchor = GridBagConstraints.FIRST_LINE_START;
        gc.weightx = 10;
        gc.weighty = 10;
        gc.gridy = 2;
        add(addBtn, gc); 

        addBtn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                String name = nameField.getText();
                String occupation = occupationField.getText();

                String text = name + ": " + occupation + "\n";
                System.out.println(text); 

                fireDetailEvent(new DetailEvent(this, text));

            }
        });
    }

    public void fireDetailEvent(DetailEvent event) {

        Object[] listeners = listenerList.getListenerList();

        for (int i = 0; i < listeners.length; i += 2) {

            if (listeners[i] == DetailListener.class) {

                ((DetailListener)listeners[i+1]).detailEventOccurred(event);
            }
        }
    }

    public void addDetailListener(DetailListener listener) {

        listenerList.add(DetailListener.class, listener);
    }

    public void removeDetailListener(DetailListener listener) {

        listenerList.remove(DetailListener.class, listener); 
    }
}

DetailListener

import java.util.EventListener;

public interface DetailListener extends EventListener {

    public void detailEventOccurred(DetailEvent event);
}

DetailEvent

import java.util.EventObject;

public class DetailEvent extends EventObject {

    private String text;

    public DetailEvent(Object source, String text) { 

        super(source);
        this.text = text;
    } 

    public String getText() {

        return text;
    }
}

Ответы [ 2 ]

0 голосов
/ 15 мая 2018
  1. Что именно означает DetailListener.class?

    DetailListener.class - это так называемый литерал класса.По сути, это константа типа Class, относящаяся к типу DetailListener.

    Более подробные объяснения можно найти в Что такое литерал класса в Java? иего ответы.

  2. Что именно делает метод fireDetailEvent()?

    Ваш класс DetailsPanel использует EventListenerList для обработки прослушивателей событийи отправка им событий.

    Комментарий, приведенный в классе EventListenerList , дает подробное описание, как его использовать.Прочитайте это описание, и вы поймете, что методы addDetailListener, removeDetailListener и fireDetailEvent вашего класса DetailsPanel написаны точно в соответствии с этим описанием.

    Метод fireDetailEvent запускает DetailEvent всем слушателям, которые ранее зарегистрировались на addDetailListener.

0 голосов
/ 15 мая 2018

1) Что именно делает DetailListener.class?

Из API :

Экземпляры класса Class представляют классы и интерфейсы в работающем приложении Java.

Это несколько сбивает с толку, поэтому давайте рассмотрим пример. Вызов DetailListener.class предоставляет его представление Class. В данном конкретном случае DetailListener.class предоставляет Class<DetailListener>, поэтому возможно сделать это:

Class<DetailListener> cdl = DetailListener.class;

cdl - это просто еще одна переменная, аналогичная тому, как frame - это просто еще одна переменная. frame это JFrame, который предоставляет некоторые методы, в то время как cdl это Class<DetailListener>, который предоставляет другой набор методов.

Тип

cdl - это Class<DetailListener>, представляющий класс DetailListener.

но я до сих пор не понимаю, что он делает в этой ситуации

Рассмотрим этот код:

listenerList.add(DetailListener.class, listener);

listenerList относится к типу EventListenerList. Согласно его API , для параметров метода add(...) требуется экземпляр класса и T. В этом случае универсальным T является DetailListener. Пока слушатель зарегистрирован, но это приводит к вашему следующему вопросу.

# 2 Что именно делает метод fireDetailEvent ()?

Когда слушатель был зарегистрирован, listenerList сохраняет внутренний массив, на который можно ссылаться позже. Массив содержит и класс, и фактический экземпляр прослушивателя. Итак, ссылаясь

Object[] listeners = listenerList.getListenerList();

обеспечивает доступ к массиву. В этом случае:

listeners[0] = DetailListener.class
listeners[1] = reference to the anonymous inner class instance created from detailsPanel.addDetailListener(...)

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

if (listeners[i] == DetailListener.class) {

использует класс для проверки на равенство, чтобы убедиться, что безопасно кастовать, чтобы иметь возможность передать DetailEvent слушателю (который является следующим элементом в массиве). Использование == (вместо .equals()) вполне допустимо в этом контексте, поскольку DetailListener.class всегда предоставляет один и тот же класс.

...