Hello all. I am new to this discussion forum and would greatly appreciate anyone's help on this one. This is a great site!! Thank you all for being here.

Here's my problem:

I'm working on an application that has a JPanel that is a grid layout with three columns of jtextfields (among other things). I have created a custom focus traversal policy to be able to transfer focus between these textfields as applicable. When I test my code in the getComponentAfter method, returning any specific element in any of the arrays it works fine..focus is transferred like it should.

example:

[ return bstextfields[3] ]

but since i have a variable number of elements in these arrays, determined by the user at the beginning of the application, the getComponentAfter method looks through the arrays for a match to decide what textfield element to return and then must return the textfield element with a variable subscript like this:

[ return bstextfields ]

The program freezes when i do this. Focus is not transferred to any of these textfields...in fact it is lost entirely (no blinking cursor in any of the textfields).

If there were a way to use macro substitution...or something like that, I think that would fix it. For example, if i was 7, I would grin from ear to ear if I could substitute that 7 and return a literal value, like the compiler apparently needs..like this:

[ return bstextfields[7] ]

Sorry so long winded. Anyway, here's the chunk of code:


public Component getComponentAfter(Container focusCycleRoot, Component aComponent)
{

    int i;

    for (i=0; i<=SETUPS; i++)
    {
         if (aComponent == bsTextFields[i]) // aComponent is losing the focus
         {
	   i = SETUPS;
	   return fsTextFields[i];
         }

         if (aComponent == fsTextFields[i])			
         {
	    i = SETUPS;
	    return descripTextFields[i+1];
         }

         if (aComponent == descripTextFields[i]) 
         {    
	    i = SETUPS;
	    return bsTextFields[i];
         }
    }

     // if problem, fall through to this to make compiler smile :)

    System.out.println("bsTextFields[5] returned");
    return bsTextFields[5]; // MAKE COMPILER HAPPY !!

} // end getComponentAfter

Thank you all so much.

Dani AI

Generated

A variable array index is fine — Java will happily return myFields[i] at run time — so the freeze you saw usually means the focus went to a component that the UI could not give focus to (out of view, not focusable, not added to the container, etc.) or an index/out-of-bounds logic error. resolved the immediate issue (misplaced SETUPS) and correctly flagged the common off-by-one/length pitfalls. The checklist below covers the other causes that commonly look like “focus disappears.”

  • Confirm indexes: use array.length (or explicit bounds checks) and iterate with < length, not <=.
  • Make sure the returned Component is in the same focus-cycle root and actually added/visible/enabled/focusable: isVisible(), isEnabled(), isFocusable() and isDisplayable().
  • If a field is inside a JScrollPane, focus can be given but the field may be scrolled out of view. Call scrollRectToVisible(...) on the JComponent before requesting focus.
  • Always run focus requests on the EDT (SwingUtilities.invokeLater) and prefer requestFocusInWindow() over the deprecated requestFocus().

Small, safe pattern to bring a JComponent into view and request focus on the EDT:

final JComponent jc = (JComponent) component;
SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        jc.scrollRectToVisible(new Rectangle(0,0,jc.getWidth(), jc.getHeight()));
        jc.requestFocusInWindow();
    }
});

Extra tips: add logging in your traversal method to print the chosen index and component identity, or step through it in the debugger to confirm which component is returned. For API reference and best practices see the Java docs for FocusTraversalPolicy and Swing focus methods: FocusTraversalPolicy, JComponent.requestFocusInWindow and JComponent.scrollRectToVisible.

Recommended Answers

All 2 Replies

First is "SETUPS" equal to the length of the arrays, or to the last index (which is one less than the length, of course), or some other number, like the index of the second to last element.

If it is equal to the length, than every one of those returns should throw an ArrayIndexOutOfBoundsException.

If equals to the last index, then the second return will throw an ArrayIndexOutOfBoundsException.

If equal to the second to last element (or a smaller index) than none will throw that.

Also, do you really want to return the element at "SETUPS" index every time? Somehow I don't think so.

Also, you can avoid that "MAKE COMPILER HAPPY" BS by doing the following (and I am assuming you don't want to always return the last element, and I am assuming that "SETUPS" is actually the length of the arrays, and not the last index):

public Component getComponentAfter(Container focusCycleRoot, Component aComponent) {
    Component retComponent = aComponent;  // Original by default
    for (int i=0; i < SETUPS; i++) {
        if (aComponent == bsTextFields[i]) {
            retComponent = fsTextFields[i];
            break;
        } else if (aComponent == fsTextFields[i]) {
            if ((i + 1) == SETUPS) {
                retComponent = descripTextFields[0];
            } else {
                retComponent = descripTextFields[i+1];
            }
            break;
        } else if (aComponent == descripTextFields[i]) {    
            retComponent = bsTextFields[i];
            break;
        }
    }
    return retComponent;
}

Fixed a few other assumed errors, as well. And I don't usually "give out" code as I find it, usually, counter-productive to the receivers learning.

First is "SETUPS" equal to the length of the arrays, or to the last index (which is one less than the length, of course), or some other number, like the index of the second to last element.

If it is equal to the length, than every one of those returns should throw an ArrayIndexOutOfBoundsException.

If equals to the last index, then the second return will throw an ArrayIndexOutOfBoundsException.

If equal to the second to last element (or a smaller index) than none will throw that.

Also, do you really want to return the element at "SETUPS" index every time? Somehow I don't think so.

Also, you can avoid that "MAKE COMPILER HAPPY" BS by doing the following (and I am assuming you don't want to always return the last element, and I am assuming that "SETUPS" is actually the length of the arrays, and not the last index):

public Component getComponentAfter(Container focusCycleRoot, Component aComponent) {
    Component retComponent = aComponent;  // Original by default
    for (int i=0; i < SETUPS; i++) {
        if (aComponent == bsTextFields[i]) {
            retComponent = fsTextFields[i];
            break;
        } else if (aComponent == fsTextFields[i]) {
            if ((i + 1) == SETUPS) {
                retComponent = descripTextFields[0];
            } else {
                retComponent = descripTextFields[i+1];
            }
            break;
        } else if (aComponent == descripTextFields[i]) {    
            retComponent = bsTextFields[i];
            break;
        }
    }
    return retComponent;
}

Fixed a few other assumed errors, as well. And I don't usually "give out" code as I find it, usually, counter-productive to the receivers learning.

Thank you masijade for your help. As it turns out, the getComponentAfter method works fine with arrays of JTextFields. I was rushing it at the end there when I put the SETUPS variable where I did. I simply didn't notice that the focus was transferred to the last textfield on the Panel (the panel has a scrollbar and I didn't scroll quite all the way down). I feel like a dummy but, I guess that's part of the process of learning a new language.

I have a lot of programming experience but Java is still rather new to me. However, one thing I'm reminded of is how powerful it is to bounce things off of other people. Even if both parties are on the wrong track, many times just the act of bouncing it off someone else "flushes" out what the REAL problem is...then it often is so simple after that.

Thanks again for your help, I do appreciate it.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.