Toggle Theme Editor
Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate Charcoal

Java Events And Threads

Discussion in 'Java Update' started by Joe, 25/6/19.

  1. Joe

    Joe Thành viên VIP

    JAVA newbies and career-jumpers who jump laterally into OO-Software development field are often lack of OO-imagination and Operation System understanding. Their thinking process is driven by examples and that causes a lot of troubles to them. Especially, OO-events and their listeners because JAVA events and Listeners are numerous and versatile. Further: JAVA allows developers to create their own events and their related listeners. All that requires, of course, an excellent OS-Understanding. An OS Understanding of their nature.

    Event is a reaction triggered by an action. For example: If you strike a Guitar String (action) a sound is echoed (reaction). The OO Understanding here is the event that can only triggered by a certain object. The event is the sound and the certain object is the Guitar string. If you strike a brick, no sound is echoed and you hear nothing, right? Exactly like that, JAVA events are only meaningful and useful when they are correctly applied. If an event is wrongly applied its related listener stays mute (or hears nothing). Let me list the most common-used JAVA events, their listeners and where they should be applied.
    PHP:
    +----------------------+------------------------------------+--------------------------+
    !  
    Event               Listener                           applied to               !
    +----------------------+------------------------------------+--------------------------+
    ActionEvent          ActionListener                     any JAVA Component that  !
    !                      !                                    ! 
    requires an action.      !
    +----------------------+------------------------------------+--------------------------+
    KeyEvent             KeyListener                        editable components like !
    !                      !                                    ! 
    JTextFieldJTextArea,.. !
    +----------------------+------------------------------------+--------------------------+
    MouseEvent           MouseListener                      any JAVA area            !
    +----------------------+------------------------------------+--------------------------+
    ItemEvent            ItemListener                       any JAVA component that  !
    !                      !                                    ! 
    provides selection of    !
    !                      !                                    ! 
    items (JComboBoxetc.)  !
    +----------------------+------------------------------------+--------------------------+
     
    The realization of Event-Listener is a straight-forward action. It depends on the requirements of your application:

    - Direct implementation,
    - Using Adapter,
    - Embedded implementation (or Lambda Expression -up JDK8),
    - Your own Listening object.

    Whatever implementation you prefer, you should pay more intention on:

    - Performance: better with direct implementation (using the keyword "implements")
    - Adapter or your own listening object should be used if it is needed for several different JAVA components.
    - Embedded or Lambda is good if event and listener are used only once on a certain JAVA component. The performance is second after direct-implementation.

    Example:
    Direct Implementation
    PHP:
    import javax.swing.*;
    import java.awt.event.*;
    import javax.sound.midi.*;
    // Direct Implementation
    public class WithInte extends JFrame implements ActionListener {
        public static 
    void main(String... athrows Exception {
            
    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            
    WithInte wi = new WithInte();
        }
        private 
    MidiChannel midi;
        public 
    WithInte() {
            
    setTitle("Direct With Interface");
            
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
    JButton jA = new JButton("DRUM");
            
    jA.addActionListener(this);
            
    add("North"jA);
            
    setSize(10070);
            
    setLocation(100100);
            
    setVisible(true);
            try {
                
    Synthesizer syn MidiSystem.getSynthesizer( );
                
    syn.open( );
                
    midi syn.getChannels( )[9];
            } catch (
    Exception e) { }
        }
        
    // implement the Interface
        
    public void actionPerformed(ActionEvent a) {
            
    midi.noteOn(64500); // make a "BUM"
        
    }
    }
    Own Listening object
    PHP:
    import javax.swing.*;
    import java.awt.event.*;
    import javax.sound.midi.*;
    // Own Listening Object
    public class WithImpl extends JFrame {
        public static 
    void main(String... athrows Exception {
            
    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            
    WithImpl wi = new WithImpl();
        }
        private 
    MidiChannel midi;
        public 
    WithImpl() {
            
    setTitle("Direct With Implement");
            
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
    JButton jA = new JButton("DRUM");
            
    jA.addActionListener(bum);
            
    add("North"jA);
            
    setSize(10070);
            
    setLocation(100100);
            
    setVisible(true);
            try {
                
    Synthesizer syn MidiSystem.getSynthesizer( );
                
    syn.open( );
                
    midi syn.getChannels( )[9];
            } catch (
    Exception e) { }
        }
        
    // My own listening object
        
    ActionListener bum = new ActionListener() {
            public 
    void actionPerformed(ActionEvent a) {
                
    midi.noteOn(64500); // make a "BUM"
            
    }
        };
    }
    With Lambda Expression
    PHP:
    import javax.swing.*;
    import java.awt.event.*;
    import javax.sound.midi.*;
    // With Lambda Expression
    public class WithLamb extends JFrame {
        public static 
    void main(String... athrows Exception {
            
    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            
    WithLamb wl = new WithLamb();
        }
        private 
    MidiChannel midi;
        public 
    WithLamb() {
            
    setTitle("Direct With LambdaExp");
            
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
    JButton jA = new JButton("DRUM");
            
    jA.addActionListener(-> {
                    
    midi.noteOn(64500); // make a "BUM"
            
    });
            
    add("North"jA);
            
    setSize(10070);
            
    setLocation(100100);
            
    setVisible(true);
            try {
                
    Synthesizer syn MidiSystem.getSynthesizer( );
                
    syn.open( );
                
    midi syn.getChannels( )[9];
            } catch (
    Exception e) { }
        }
    }
    Embedded Implementation
    PHP:
    import javax.swing.*;
    import java.awt.event.*;
    import javax.sound.midi.*;
    // Embedded Implementation
    public class WithIDir extends JFrame {
        public static 
    void main(String... athrows Exception {
            
    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            
    WithIDir wid = new WithIDir();
        }
        private 
    MidiChannel midi;
        public 
    WithIDir() {
            
    setTitle("Direct With DirImplmt");
            
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
    JButton jA = new JButton("DRUM");
            
    jA.addActionListener(new ActionListener() {
                public 
    void actionPerformed(ActionEvent a) {
                    
    midi.noteOn(64500); // make a "BUM"
                
    }
            });
            
    add("North"jA);
            
    setSize(10070);
            
    setLocation(100100);
            
    setVisible(true);
            try {
                
    Synthesizer syn MidiSystem.getSynthesizer( );
                
    syn.open( );
                
    midi syn.getChannels( )[9];
            } catch (
    Exception e) { }
        }
    }
    The different implementations produce different physical sizes (more codes). More codes mean more work. More work means more time. More time means long waiting. Long waiting means bad performance.

    Further: Most SWING developers (especially newbies) usually don't care about the events that are bound to some SWING components (e.g. JTextField, JTextArea, JComboBox, etc.). But have they ever thought about the events ? What are the events ? How the events are triggered ? etc.

    The first question is as clear as the sun's shining. Event's a happening that occurs unexpectedly and arbitrarily. The second question leads to the surmise that event is triggered by a ghost that lurks somewhere in the darkness and storms out when it's disturbed...A ghost ? Yes for the religious it's a ghost, but for JAVA developers it's just a THREAD. A (SWING) event thread to be exact.

    When an event is a thread then it runs fully independent from the main thread (app) and sometimes event needs to be tamed or controlled. Otherwise your app might run amok and goes on the rampage. The following example with a JComboBox that needs to be set to the default item at position 0...and terror happens because the ghost is insulted impolitely.
    PHP:
    public class JavaBadEvent extends JFrame implements ItemListener {
    2     public static void main(String... athrows Exception {
    3        UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
    4        JavaBadEvent je = new JavaBadEvent();
    5    }
    6    private JTextField jtf;
    7    private JComboBox<Stringjcb;
    8    private JLabel jlab;
    9    public JavaBadEvent() {
    10        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    11        jlab = new JLabel();
    12        jcb = new JComboBox<String>("Item_1!Item_2!Item_3!Item_4".split("!"));
    13        jcb.addItemListener(this);
    14        add("North",(new JPanel()).add(jcb));
    15        add("Center",(new JPanel()).add(jlab));
    16        setSize(200100);
    17        setLocation(150150);
    18        setResizable(false);
    19        setVisible(true);
    20   }
    21   public void itemStateChanged(ItemEvent e) {
    22        jlab.setText("Your selected Item:"+(String)jcb.getSelectedItem());
    23        jcb.setSelectedIndex(0);
    24   }
    }
    Everything and every line look quite good and quite proper...but the terror
    [​IMG]

    Why that ? Let study the codes:

    - line 1: the class is an implementation of ItemListener, also an Event-Thread that listens to the CHANGE of Items.
    - line 13: attach the ItemListener thread to JComboBox jcb
    - line 21-24: the implementation of the required method. In this implementation the ItemListener thread is still active...and if any change is made (here: setSelectedItem) it will trigger another action...an endless loop arises till all resources are consumed: Terror occurs.

    So, how can one set a JComboBox after a Selection of an item back to a predefined default without making the ItemListener thread going amok ? Well, first of all: Thread programming requires an understanding of Synchronization, then the Thread management. Let's take a brief look at the JComboBox< E > API1 and what we can see is that the method addItemListener(ItemListener aListener) has an "arch enemy" named: removeItemListener(ItemListener aListener). Let's modify the codes using the arch enemy and rename the codes as JavaGoodEvent (see line 22a and 23a)
    PHP:
    public class JavaGoodEvent extends JFrame implements ItemListener {
    2     public static void main(String... athrows Exception {
    3        UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
    4        JavaGoodEvent je = new JavaGoodEvent();
    5    }
    6    private JTextField jtf;
    7    private JComboBox<Stringjcb;
    8    private JLabel jlab;
    9    public JavaBadEvent() {
    10        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    11        jlab = new JLabel();
    12        jcb = new JComboBox<String>("Item_1!Item_2!Item_3!Item_4".split("!"));
    13        jcb.addItemListener(this);
    14        add("North",(new JPanel()).add(jcb));
    15        add("Center",(new JPanel()).add(jlab));
    16        setSize(200100);
    17        setLocation(150150);
    18        setResizable(false);
    19        setVisible(true);
    20   }
    21   public void itemStateChanged(ItemEvent e) {
    22a       jcb.removeItemListener(this);
    22        jlab.setText("Your selected Item:"+(String)jcb.getSelectedItem());
    23        jcb.setSelectedIndex(0);
    23a       jcb.addItemListener(this);
    24   }
    }
    and see what happens...
    [​IMG]
     
    Last edited: 25/6/19

Chia sẻ trang này

Loading...