why javax. swing.JComponent is inherited from java. awt. Container

I study Swing from the book by Ivan Portyankin "Swing effective user interfaces, 2nd edition" .

I read that the lightweight Swing components are based on the heavy-weight AWT components. Everything was clear.. it seems like the AWT components depend on the OS, and in Swing only the top-level containers depend on the OS, and all the other components are just a region in the space of the top - level container and they no longer depend on the OS. But in the same book it says, that the javax.swing.JComponent class, which is the parent of all these lightweight components, is inherited from java.awt.Container, which I understand is heavy?

How did it happen that lightweight components came from heavy-weight ones? Or is it done so that Swing components have the same methods as AWT components? And they somehow changed everything so cleverly that the Swing components became lightweight? I can't understand this.

Thank you all in advance for your help!

Author: LEQADA, 2015-11-10

1 answers

Look at the source code java.awt.Component. There you can see the field ComponentPeer peer, which, for heavy components such as java.awt.Button, contains a reference to the implementation of java.awt.ComponentPeer. The implementation depends on the platform on which the JVM is running, and works directly with the "heavy" object. For "light" objects, the implementation java.awt.LightweightPeer is used.

Methods java.awt.Component delegate the execution of actions, such as setting a color or text, to this peer (the "Bridge" design pattern). Thus, the class hierarchy It is itself free of native code and heavy components, and only some of its members from the java.awt package use native implementations.

The general hierarchy is built, most likely, because Swing depends on AWT in terms of working with operating system events (mouse, keyboard, redrawing), the clipboard, focus control, etc. The top-level container (JFrame , etc.), on which all other components are placed, also uses AWT. The same general hierarchy allows you to share Swing and AWT components.

Update:

I'll try the example of java.awt.Component.setForeground(Color c). For buttons, the method sets the text color. The method is defined in java.awt.Component as:

public void setForeground(Color c) {
    Color oldColor = foreground;
    ComponentPeer peer = this.peer;
    foreground = c;
    if (peer != null) {
        c = getForeground();
        if (c != null) {
            peer.setForeground(c);
        }
    }
    // This is a bound property, so report the change to
    // any registered listeners.  (Cheap if there are none.)
    firePropertyChange("foreground", oldColor, c);
}

In the code, the new color is assigned to the Component.foreground field, and if there is peer, peer.setForeground is called. The pir method for the "heavy" component in the Windows implementation can be viewed at grepcode, it takes the color in the form of int and calls the native method. For the" light " component, use implementation of the sun.awt.NullComponentPeer interface LightweightPeer, which does nothing. An event about the field change is also created and sent to all listeners.

Next, on the way to javax.swing.JButton, the setForeground method is redefined in JComponent as follows:

public void setForeground(Color fg) {
    Color oldFg = getForeground();
    super.setForeground(fg);
    if ((oldFg != null) ? !oldFg.equals(fg) : ((fg != null) && !fg.equals(oldFg))) {
        // foreground already bound in AWT1.2
        repaint();
    }
}

That is, first a method of the Component class is executed, in which a new color is assigned to the field, the peer does nothing, and an event is sent. Then, if the color has changed, a redraw of the space occupied by the component is requested, via Swing RepaintManager (a chain of Component.repaint() calling JComponent.repaint(long, int, int, int, int) by redefinition).

Now about where the feast comes from. For java.awt.Button, the feast is obtained in

public void addNotify() {
    synchronized(getTreeLock()) {
        if (peer == null)
            peer = getToolkit().createButton(this);
        super.addNotify();
    }
}

addNotify called when components are being prepared for display, for example, when pack() is called for the base window, or setVisible(true). getToolkit() returns the implementation for the current platform (sun.awt.windows.WToolkit for Windows), createButton creates a peer for the button. Since the user could call setForeground before the peer was created, when it was when creating foreground, it is copied.

For components that did not override addNotify, or did not create a peer, and called super.addNotify, inside Component.addNotify is called java.awt.Toolkit.createComponent, returning NullComponentPeer.

 2
Author: zRrr, 2015-11-15 00:04:04