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

(fp.bugs 2043) requestFocus ADDS a focus instead of CHANGING the focus

    XMLWordPrintable

Details

    • Bug
    • Resolution: Not an Issue
    • P3
    • None
    • 1.0
    • client-libs
    • None
    • sparc
    • solaris_2.4

    Description

      t, x, insets.top + vgap, roww, maxheight - y,
      start, nmembers);
          }
          
          /**
           * Returns the String representation of this TileLayout's values.
           */
          public String toString() {
      String str = "";
      switch (align) {
      case TOP: str = ",align=top"; break;
      case CENTER: str = ",align=center"; break;
      case BOTTOM: str = ",align=bottom"; break;
      }
      return getClass().getName() + "[hgap="+hgap+",vgap="+vgap+str+"]";
          }
      }
      ----------
      >From: Mattias Mattsson <###@###.###>

      I have a stand-alone program that has several TextFields for a user to
      fill in. The user can press a button to ADD a textfield. When the
      button is pressed I creates a new text fieldand do a requestFocus on
      it. The text field gets focus alright but the other text fields doesn't
      loose it. I end up withseveral text fields with focus. Since several
      text fieldshave the focus the user can't write in any of them and
      can'tselect ONE with the mouse either. (The tab removes thefocuses
      after a while).

      I send you a slim version of the code that causes the problem. I am sorry
      that I couldn't slim it further but I tried to just create 2 text fields
      and request focus on them both but that worked fine. Therefore I have to
      send you a few files to get this to work. You only have to concentrate on
      the file 'BaseArgHandler' in the middle (the 'Add Argument' code).
      Do a search for the word 'broken' and you will end up in the right place.

      You compile and start the file FocusTest.

      Thanks for your attention.

      ----------
      FocusTest.java
      ----------
      import java.awt.*;

      public class FocusTest {

        static public void main(String args[]) {
          BaseArgHandler bah = new BaseArgHandler(Color.lightGray);

          bah.getArgs();
        }
      }

      ----------
      BaseArgHandler.java
      ----------

      /*
       * A basic argument handler
       */

      import java.awt.*;
      import java.util.*;

      /**
       * A basic argument handler that allows the input of an variable number
       * of arguments. If the user presses the button <b>Add Argument</b> or
       * presses the return key in the last entry, a new argument entry appears.
       *
       * @version 0.40 -- Last updated 95-10-03
       * @author Per Danvind
       * @author Mattias Mattsson
       */
      public class BaseArgHandler {
        // The static variables, global for the whole class.
        private static final Color defBg = Color.lightGray;
        private static String buttName1[] = { "Add Argument", "Remove Argument",
      " OK ", " Cancel " };

        // The object specific variables.
        private Frame frame;
        private TileLayout layout;
        private ButtonRow buttons;
        private Stack entryStack;
        private int entryCnt = 0;

        /**
         * Creates a basic argument handler with the specified
         * background colour. If it is null, the default values is used.
         * @param bg The background colour of the window
         */
        public BaseArgHandler(Color bg) {
          if(bg == null)
            bg = defBg;
          entryStack = new Stack();
          frame = new Frame("Arguments");
          frame.setBackground(bg);
          layout = new TileLayout();
          layout.keepCurrentSize(true);
          frame.setLayout(layout);
        }

        public String[] getArgs() {
          TextField textField;
          String result[] = null;
          int fieldWidth = 0;

          buttons = new ButtonRow(buttName1, ButtonRow.CENTER);
          frame.add(buttons);
          frame.pack();
          frame.show();

          fieldWidth = frame.size().width;

          while(!buttons.isPressed("Cancel") && !buttons.isPressed("OK"))
            {
      try {
      Thread.sleep(500);
      } catch(InterruptedException e) {
      }

      // When the user presses 'Add Argument' a new text field is created
      // and the focus is requested to that one.
      // --- THE BROKEN CODE -----
      if(buttons.isPressed("Add Argument"))
      {
      buttons.setButton("Add Argument", false);
      entryCnt++;
      textField = new TextField(null);
      entryStack.push(textField);
      frame.add(textField);
      textField.resize(fieldWidth, textField.preferredSize().height);
      textField.requestFocus(); // --- BROKEN ---
      frame.pack();
      frame.show();
      }
      if(buttons.isPressed("Remove Argument"))
      {
      buttons.setButton("Remove Argument", false);
      if(entryCnt > 0)
      {
      entryCnt--;
      textField = (TextField)entryStack.pop();
      frame.remove(textField);
      frame.pack();
      frame.show();
      }
      }
            }
        
          // Return the arguments...
          if(buttons.isPressed("OK"))
            {
      result = new String[entryCnt];
      for(int cnt=entryCnt-1;cnt >= 0;cnt--)
      result[cnt] = ((TextField)entryStack.pop()).getText();
            }
          frame.dispose();
          if(buttons.isPressed("Cancel"))
            return null;
          return result;
        }
      }
      ----------
       ButtonRow.java
      ----------

      import java.awt.*;

      /**
       * A help class that provides a simple type of buttons.
       */
      class AButton extends Button {
        private int privateNr;
        private ButtonRow toggleBar;
        
        public AButton(String text, ButtonRow row, int nr) {
          super(text);
          toggleBar = row;
          privateNr = nr;
        }
        
        public boolean action(Event e, Object act) {
          toggleBar.toggle[privateNr] = !toggleBar.toggle[privateNr];
          return true;
        }
      }

      /**
       * A class that creates a row of buttons if given an array of strings with
       * the names of the buttons. The buttons has two states, true or false. The
       * state is changed when the button is pressed or set. An array with strings
       * for a row of buttons may look like this:
       * <pre>
       * String buttonNames[] = { " Done ", " Abort " };
       * </pre>
       * The done button can then be queried by;
       * <pre>
       * Buttonrow.isPressed("Done");
       * </pre>
       * @version 0.2 -- Last updated 95-10-03
       * @author Per Danvind
       * @author Mattias Mattsson
       */
      public class ButtonRow extends Panel {
        protected boolean toggle[];
        private AButton btn[];
        private int nrButtons;

        // The alignment constants
        public static int LEFT = FlowLayout.LEFT;
        public static int CENTER = FlowLayout.CENTER;
        public static int RIGHT = FlowLayout.RIGHT;
        
        /**
         * Creates a row with buttons. The names of the buttons are given
         * as an array of strings. The align specifies which alignment the
         * buttons should have, LEFT, CENTER or RIGHT.<br>
         * Example call:
         * <ul>
         * String buttonNames[] = { "Ok", "Cancel" };
         * ButtonRow buttons = new ButtonRow(buttonNames, ButtonRow.CENTER);
         * </ul>
         * @param names The names of the buttons
         * @param align The alignment of the buttons
         */
        public ButtonRow(String names[], int align) {
          super();

          this.setLayout(new FlowLayout(align));
          nrButtons = names.length;
          btn = new AButton[nrButtons];
          toggle = new boolean[nrButtons];

          // Create the buttons.
          for(int cnt=0;cnt < btn.length;cnt++) {
            btn[cnt] = new AButton(names[cnt], this, cnt);
            add(btn[cnt]);
          }
        }

        /**
         * Queries if a button has been pressed. The name is the name given
         * the button, that is, the first of the two strings for the button.
         * If the button does not exist, false is returned.
         * @param name The name of the button
         * @return True if the button has been toggled, false otherwise
         */
        public boolean isPressed(String name) {
          for(int cnt=0;cnt < nrButtons;cnt++)
            if(name.trim().equals(btn[cnt].getLabel().trim()))
      return toggle[cnt];
          return false;
        }

        /**
         * Queries if a button has been pressed. The number is the number of
         * the button, starting with 0. If the button does not exist, false
         * is returned.
         * @param nr The number of the button
         * @return True if the button has been toggled, false otherwise
         */
        public boolean isPressed(int nr) {
          if(nr < nrButtons)
            return toggle[nr];
          return false;
        }

        /**
         * Sets the state of a button. The name is the name given
         * the button, that is, the first of the two strings for the button.
         * If the button does not exist, nothing happens.
         * @param name The name of the button
         * @return True if the button has been toggled, false otherwise
         */
        public void setButton(String name, boolean state) {
          for(int cnt=0;cnt < nrButtons;cnt++)
            if(name.trim().equals(btn[cnt].getLabel().trim()))
      toggle[cnt] = state;
        }

        /**
         * Sets the state of a button. The number is the number of
         * the button, starting with 0. If the button does not exist, nothing
         * happens.
         * @param nr The number of the button
         * @return True if the button has been toggled, false otherwise
         */
        public void setButton(int nr, boolean state) {
          if(nr < nrButtons)
            toggle[nr] = state;
        }

        /**
         * Returns the requested button. Used if one wants to change a given
         * button in the row, for example, disable it.
         * @param name The name of the button
         * @return The button or null if it was not found.
         */
        public AButton getButton(String name) {
          for(int cnt=0;cnt < nrButtons;cnt++)
            if(name.trim().equals(btn[cnt].getLabel().trim()))
      return btn[cnt];
          return null;
        }

        /**
         * Returns the requested button. Used if one wants to change a given
         * button in the row, for example, disable it.
         * @param nr The number of the button
         * @return The button or null if it was not found.
         */
        public AButton getButton(int nr) {
          if(nr < nrButtons)
            return btn[nr];
          return null;
        }
      }
      ----------
      TileLayout.java
      ----------

      /*
       * TileLayout.java - Lays out components top to bottom in a containter.
       */

      import java.awt.*;

      /**
       * Tile layout is used to layout a variable amount of components on
       * top of each other, a vertical flow layout.
       *
       * The tile layout is just a modification of the flow layout version
       * 1.15 written by Arthur van Hoff and Sami Shaio.
       *
       * @version 0.1 -- Last updated 95-10-05
       * @author Per Danvind
       * @author Mattias Mattsson
       */
      public class TileLayout implements LayoutManager {

          /**
           * The top alignment constant.
           */
          public static final int TOP = 0;

          /**
           * The center alignment constant.
           */
          public static final int CENTER = 1;

          /**
           * The bottom alignment constant.
           */
          public static final int BOTTOM = 2;

          int align;
          int hgap;
          int vgap;

          // Keep current size or use preferred size variable
          private boolean keepSize = false;
          
          /**
           * Constructs a new Tile Layout with a centered alignment.
           */
          public TileLayout() {
      this(CENTER, 5, 5);
          }

          /**
           * Constructs a new Tile Layout with the specified alignment.
           * @param align the alignment value
           */
          public TileLayout(int align) {
      this(align, 5, 5);
          }

          /**
           * Constructs a new Tile Layout with the specified alignment and gap
           * values.
           * @param align the alignment value
           * @param hgap the horizontal gap variable
           * @param vgap the vertical gap variable
           */
          public TileLayout(int align, int hgap, int vgap) {
      this.align = align;
      this.hgap = hgap;
      this.vgap = vgap;
          }

          /**
           * Specify whether current size should be kept or if the preferred
           * size shall be used instead (default).
           * @param keep True if the current size should be kept
           */
          public void keepCurrentSize(boolean keep) {
            keepSize = keep;
          }

          /**
           * Adds the specified component to the layout. Does not apply.
           * @param name the name of the component
           * @param comp the the component to be added
           */
          public void addLayoutComponent(String name, Component comp) {
          }

          /**
           * Removes the specified component from the layout. Does not apply.
           * @param comp the component to remove
           */
          public void removeLayoutComponent(Component comp) {
          }

          /**
           * Returns the preferred dimensions for this layout given the components
           * in the specified target container.
           * @param target the component which needs to be laid out
           * @see Container
           * @see minimumSize
           */
          public Dimension preferredLayoutSize(Container target) {
            Dimension dim = new Dimension(0, 0), d;
            int nmembers = target.countComponents();
            
            for (int i = 0 ; i < nmembers ; i++) {
      Component m = target.getComponent(i);
      if (m.isVisible()) {
      if(!keepSize || m.size().width == 0 || m.size().height == 0)
      d = m.preferredSize();
      else
      d = m.size();
      dim.width = Math.max(dim.width, d.width);
      if (i > 0) {
      dim.height += hgap;
      }
      dim.height += d.height;
      }
            }
            Insets insets = target.insets();
            dim.width += insets.left + insets.right + hgap*2;
            dim.height += insets.top + insets.bottom + vgap*2;
            return dim;
          }
          
          /**
           * Returns the minimum dimensions needed to layout the components
           * contained in the specified target container.
           * @param target the component which needs to be laid out
           * @see #preferredSize
           */
          public Dimension minimumLayoutSize(Container target) {
      Dimension dim = new Dimension(0, 0);
      int nmembers = target.countComponents();

      for (int i = 0 ; i < nmembers ; i++) {
      Component m = target.getComponent(i);
      if (m.isVisible()) {
      Dimension d = m.minimumSize();
      dim.width = Math.max(dim.width, d.width);
      if (i > 0) {
      dim.height += hgap;
      }
      dim.height += d.height;
      }
      }
      Insets insets = target.insets();
      dim.width += insets.left + insets.right + hgap*2;
      dim.height += insets.top + insets.bottom + vgap*2;
      return dim;
          }

          /**
           * Centers the elements in the specified row, if there is any slack.
           * @param target the component which needs to be moved
           * @param x the x coordinate
           * @param y the y coordinate
           * @param width the width dimensions
           * @param height the height dimensions
           * @param rowStart the beginning of the row
           * @param rowEnd the the ending of the row
           */
          private void moveComponents(Container target, int x, int y,
      int width, int height,
      int rowStart, int rowEnd) {
      switch (align) {
      case TOP:
      break;
      case CENTER:
      y += height / 2;
      break;
      case BOTTOM:
      y += height;
      break;
      }
      for (int i = rowStart ; i < rowEnd ; i++) {
      Component m = target.getComponent(i);
      if (m.isVisible()) {
      m.move(x + (width - m.size().width) / 2, y);
      y += vgap + m.size().height;
      }
      }
          }

          /**
           * Lays out the container. This method will actually reshape the
           * components in target in order to satisfy the constraints of
           * the BorderLayout object.
           * @param target the specified component being laid out.
           * @see Container
           */
          public void layoutContainer(Container target) {
            Dimension d;
            Insets insets = target.insets();
            int maxheight = target.size().height-(insets.top+insets.bottom+vgap*2);
            int nmembers = target.countComponents();
            int x = insets.left + hgap, y = 0;
            int roww = 0, start = 0;
            
            for (int i = 0 ; i < nmembers ; i++) {
      Component m = target.getComponent(i);
      if (m.isVisible()) {
      if(!keepSize || m.size().height == 0 || m.size().width == 0)
      {
      d = m.preferredSize();
      m.resize(d.width, d.height);
      }
      else
      d = m.size();
      if ((y == 0) || ((y + d.height) <= maxheight)) {
      if (y > 0) {
      y += vgap;
      }
      y += d.height;
      roww = Math.max(roww, d.width);
      } else {
      moveComponents(target, x, insets.top + vgap, roww,
      maxheight - y, start, i);
      x += vgap + roww;
      y = d.height;
      roww = d.width;
      start = i;
      }
      }
            }
            moveComponents(targe

      Attachments

        Activity

          People

            amfowler Anne Fowler (Inactive)
            duke J. Duke
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: