Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4532893

Certain actions implicitly generate focus events in the new focus model

XMLWordPrintable

    • 01
    • x86
    • windows_nt


        Name: pa48320 Date: 11/29/2001

        (this bug is to track the JInitiator Replacement Project. please direct
        any questions to Peter Allenbach. Thank you)

        Implicit focus transfers in the AWT classes appear to combine
        with the new focus model in JDK 1.4 to cause several bugs
        encountered during the certification of Oracle Applications
        11i on the JDK 1.4 platform.

        Even if complete workarounds for these issues prove to be
        feasible, it looks like they will fall under the category of
        rearchitecting rather than bug fixing, so we would very much
        like to search for solutions to better preserve compatibility
        between 1.1.8 and 1.4.

        There are a set of "focus sensitive" actions the JDK allows on
        UI components, which are sensitive in the sense that if the
        component on which we?re performing them currently has focus,
        they implicitly generate focus changes. Examples of these
        behaviors include disabling, hiding, or removing a focused
        component from its container, all of which will cause the JDK to
        request focus on some other component.

        Performing these actions on components which currently have focus
        is a requirement for us because we are a tool which allows
        application developers to declaratively design a UI and set of
        behaviors the UI should have in response to user events. For
        example, within our model it is a completely valid UI design
        to respond to a user mouse click by disabling the button which
        has focus, just so long as focus is set on some other component.

        When it is time for us to actually implement this sort of
        sensitive action on a component at the java level, the question
        becomes how we can use java to accomplish that action and ensure
        focus ends up in the correct component, all within our event
        listener where we process the user action.

        In the context of JDK 1.1.8, our solution was to set focus to
        some other component (the ultimate recipient if it is already
        a valid focus recipient, or some temporary component otherwise)
        before performing the sensitive action. Since focus requests
        were resolved synchronously, this would avoid any focus transfers
        on the part of the JDK since by the time we performed the sensitive
        action, that target component was not currently the focus owner.
        We could then request focus to the correct component at the end
        of our processing, and all of this could happen in one block of
        code within a single event listener method.

        In JDK 1.4 this strategy no longer works, since requesting focus
        to another component no longer prevents the JDK from transferring
        focus, and because the order of focus requests is (1) Forms
        followed by (2) the JDK, focus will end up in the wrong component
        once both requests are resolved.


        The FocusTest testcase:
        -----------------------
        The FocusTest testcase contains a Frame with a Button and two
        TextFields. The Button starts with the focus, and when the user
        clicks it the application is designed to disable the button and
        set focus to the second TextField (TextField2). This demonstrates
        the issue described above.

        Our JDK 1.1.8 strategy for this is to requestFocus on the desired
        component (TextField2) and then disable the Button. Since focus
        requests are processed synchronously in 1.1.8, the sequence of
        events are as follows:

        1. TextField2 requests focus
        2. TextField2 receives focus
        3. Button calls setEnabled(false)
        4. Button becomes disabled

        If that same code is run in JDK 1.4 where focus requests happen
        asynchronously, the sequence of events is a little bit more
        complex, and runs as follows:

        1. TextField2 requests focus
        2. TextField2?s focus request (1) is queued
        3. Button calls setEnabled(false)
        4. _autoTransferFocus requests focus on TextField1 (the next
           focusable component)
        5. TextField1?s focus request (2) is queued
        6. Button becomes disabled
        7. The first focus request (1) is processed and TextField2
           receives focus
        8. The second focus request (2) is processed and TextField1
           receives focus
         
        [FocusTest.java]
        ----------------

        import java.awt.*;
        import java.awt.event.*;

        public class FocusTest extends Frame implements ActionListener
        {
            Panel panel = new Panel();
            MyButton button1 = new MyButton("Push!");
            MyTextField field1 = new MyTextField(" Field 1");
            MyTextField field2 = new MyTextField(" Field 2");

            FocusTest()
            {
                add(panel);
                addWindowListener(
                    new WindowAdapter() {
                        public void windowClosing(WindowEvent e) {
                            System.exit(0); } } );
                button1.addActionListener(this);
                panel.add(button1);
                panel.add(field1);
                panel.add(field2);
                pack();
            }

            public void actionPerformed(ActionEvent event)
            {
                if ( event.getSource() == button1 )
                {
                    field2.requestFocus();
                    button1.setEnabled(false);
                }
            }

            static public void main(String[] args)
            {
                (new FocusTest()).setVisible(true);
            }
        }

        class MyTextField extends TextField implements FocusListener
        {

            MyTextField(String s)
            {
                super(s);
                addFocusListener(this);
            }

            public void requestFocus()
            {
                System.out.println("[MyTextField] requestFocus() from "+
                                    this.getText());
                super.requestFocus();
            }

            public void focusGained(FocusEvent e)
            {
                System.out.println("[MyTextField] focusGained on " +
                                    ((MyTextField)(e.getComponent())).getText());
            }

            public void focusLost(FocusEvent e)
            {
                System.out.println("[MyTextField] focusLost on " +
                                    ((MyTextField)(e.getComponent())).getText());
            }
        }

        class MyButton extends Button implements FocusListener
        {
            MyButton(String s)
            {
                super(s);
                addFocusListener(this);
            }

            public void requestFocus()
            {
                System.out.println("[MyButton] requestFocus() from " +
                                    this.getLabel());
                super.requestFocus();
            }

            public void focusGained(FocusEvent e)
            {
                System.out.println("[MyButton] focusGained on " +
                                    ((MyButton)(e.getComponent())).getLabel());
            }

            public void focusLost(FocusEvent e)
            {
                System.out.println("[MyButton] focusLost on " +
                                    ((MyButton)(e.getComponent())).getLabel());
            }
        }
        (Review ID: 135397)
        ======================================================================

              son Oleg Sukhodolsky (Inactive)
              pallenba Peter Allenbach (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: