简体   繁体   English

Java Swing中具有自定义事件的接口后的.class

[英].class after an Interface with Custom Events in Java Swing

I'm learning about Java Swing and I have found an advanced code (in my opinion) about Swing using MVC and Observer patterns. 我正在学习Java Swing,并且发现了使用MVC和Observer模式的关于Swing的高级代码。 It is very difficult for me and I try to understand it. 这对我来说非常困难,我试图理解它。 And I have 2 questions: 我有两个问题:

  1. What exactly does DetailListener.class? DetailListener.class到底是什么? It is the first time when I use .class after an interface. 这是我第一次在接口后使用.class。 I have tried to search on stackoverflow about ".class syntax" and I see it can be used after a class, but I still don't understand what it does in this situation. 我试图搜索有关“ .class语法”的stackoverflow,但我发现它可以在使用一个类后使用,但是我仍然不了解它在这种情况下的作用。

  2. What exactly does the method fireDetailEvent()? 方法fireDetailEvent()到底是什么?

Thanks in advance! 提前致谢!

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 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 DetailListener

import java.util.EventListener;

public interface DetailListener extends EventListener {

    public void detailEventOccurred(DetailEvent event);
}

DetailEvent 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;
    }
}

1) What exactly does DetailListener.class? 1)DetailListener.class到底是什么?

From the API : API中

Instances of the class Class represent classes and interfaces in a running Java application. 类Class的实例表示正在运行的Java应用程序中的类和接口。

This is somewhat confusing so let's look at a an example. 这有点令人困惑,所以让我们看一个例子。 Calling DetailListener.class provides its Class representation. 调用DetailListener.class提供其Class表示形式。 In this specific case DetailListener.class provides a Class<DetailListener> so it's possible to do this: 在这种特定情况下, DetailListener.class提供了一个Class<DetailListener>因此可以执行以下操作:

Class<DetailListener> cdl = DetailListener.class;

cdl is just another variable similar to how frame is just another variable. cdl只是另一个变量,类似于frame只是另一个变量。 frame happens to be a JFrame which provides some methods, while cdl is a Class<DetailListener> which provides a different set of methods. frame恰好是提供某些方法的JFrame ,而cdl是提供不同方法集的Class<DetailListener>

cdl 's type is a Class<DetailListener> which represents the DetailListener class. cdl的类型是Class<DetailListener> ,它表示DetailListener类。

but I still don't understand what it does in this situation 但我仍然不明白在这种情况下它会做什么

Consider this code: 考虑以下代码:

listenerList.add(DetailListener.class, listener);

listenerList is of type EventListenerList . listenerList的类型为EventListenerList According to its API , the add(...) method parameters require a Class and a T instance. 根据其APIadd(...)方法参数需要一个Class和一个T实例。 In this case, the generic T is DetailListener. 在这种情况下,通用T为DetailListener。 So far the listener has been registered but it leads into your next question. 到目前为止,听众已经注册,但是它会引出您的下一个问题。

#2 What exactly does the method fireDetailEvent()? #2 fireDetailEvent()方法到底是什么?

When the listener was registered the listenerList keeps an internal array which can be referenced later. 注册listenerList器后, listenerList会保留一个内部数组,以后可以引用该数组。 The array holds both the Class and the actual listener instance. 该数组同时包含Class和实际的侦听器实例。 So invoking 如此调用

Object[] listeners = listenerList.getListenerList();

provides access to the array. 提供对阵列的访问。 In this case: 在这种情况下:

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

So the loop in fireDetailEvent(...) is guaranteed to be a multiple of 2 (0 also works if there are no registered listeners). 因此, fireDetailEvent(...)的循环保证为2的倍数(如果没有注册的侦听器,则0也适用)。 But listenerList could hold any type of listener, so 但是listenerList可以容纳任何类型的侦听器,因此

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

uses the Class to check for equality to make sure it's safe to caste to be able to pass the DetailEvent to the listener (which is the next element in the array). 使用Class检查是否相等,以确保能够安全地进行等级传递,以便能够将DetailEvent传递给侦听器(这是数组中的下一个元素)。 Using == (instead of .equals() ) is okay in this context since DetailListener.class always provides the same Class. 在这种情况下,可以使用== (而不是.equals() ),因为DetailListener.class始终提供相同的Class。

  1. What exactly does DetailListener.class ? DetailListener.class到底是DetailListener.class

    DetailListener.class is a so-called class literal. DetailListener.class是所谓的类文字。 Basically, it is a constant of type Class referring to the DetailListener type. 基本上,它是Class类型的常量,表示DetailListener类型。

    You can find more and better explanations about this at What is a class literal in Java? 您可以在Java什么是类文字中找到更多更好的解释 and its answers. 及其答案。

  2. What exactly does the method fireDetailEvent() ? 方法fireDetailEvent()到底是什么?

    Your DetailsPanel class uses an EventListenerList for handling event listeners and sending events to them. 您的DetailsPanel类使用EventListenerList来处理事件侦听器并将事件发送给他们。

    The comment given in class EventListenerList gives a detailed description how to use it. EventListenerList中给出的注释详细说明了如何使用它。 Read this description and you will recognize, that the methods addDetailListener , removeDetailListener and fireDetailEvent of your class DetailsPanel are written exactly following this description. 仔细阅读本说明,你会认识到,这些方法addDetailListenerremoveDetailListenerfireDetailEvent类的DetailsPanel写这正好说明如下。

    The method fireDetailEvent fires a DetailEvent to all those listeners which have registered themselves earlier by addDetailListener . 该方法fireDetailEvent触发一个DetailEvent所有那些已经由早期注册自己的听众addDetailListener

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM