<AWT Dev> <Swing Dev> Public RequestFocusController/AWTAccessor API

Reto Merz reto.merz at abacus.ch
Thu Apr 14 18:25:16 UTC 2016


This is a small part of our focus/validation framework.
I just try to explain it as simple as possible.

javax.swing.InputVerifier gives only access to the source component.

We need to know the target component.

Would it be possible to overload verify(..) (or introduce another 
method) which has the "to"/target component as a argument too?

Thanks
Reto Merz


On 14.04.2016 16:52, Semyon Sadetsky wrote:
> Thank for explanation.
> It seems to me such functionality belongs to the input validation domain
> and should not be mixed up with the Swing focus transfer internals.
> Swing has javax.swing.InputVerifier which you could extend and set to
> each component of your framework. I suppose it would be better design
> choice for you because it decouples your code from the focus transfer
> details which may be changed in future JDK releases. While the
> javax.swing.InputVerifier functionality will be preserved.
>
> --Semyon
>
> On 4/14/2016 4:58 PM, Reto Merz wrote:
>> Exactly, the target can reject the focus transfer (and the source too).
>> All our UI components support "FocusRequestEnterExit" listeners
>> which has a requestEnter(EnterExitEvent) and requestExit(EnterExitEvent) method (among others focusGained/focusLost methods).
>> The EnterExitEvent has a reject() and accept() method.
>>
>> requestEnter is invoked on the target component and requestExit on the source component listeners.
>> The focus is only transferred after all source/target listeners have accept it.
>> This can be used for simple user input validation.
>>
>> It is far more complex because our RIA is ULC based (https://ulc.canoo.com/developerzone/technicalconcept.html)
>> which split UI components into client- and server-side half objects,
>> but, basically this is how parts of our focus/validation framework works.
>>
>> Open Component#requestFocusInWindow(CausedFocusEvent.Cause) does not work
>> because this allows only conditional invoking super.requestFocusInWindow.
>> At this point it is not yet clear if the focus can be really transferred (see isRequestFocusAccepted).
>> And after super.requestFocusInWindow it is to late because
>> KeyboardFocusManager.setMostRecentFocusOwner is already invoked.
>>
>>  From my point of view the best (and easiest to maintain) solution is
>> introducing a isRequestFocusAccepted() method which is invoked
>> by isRequestFocusAccepted(boolean,boolean,CausedFocusEvent.Cause) at the end.
>> So the new isRequestFocusAccepted makes the final decision to transfer focus or not.
>> Furthermore that dont require to make CausedFocusEvent.Cause public (which looks a bit creepy).
>>
>> Best Regards
>> Reto Merz
>>
>>> On 14/04/16 14:49, Semyon Sadetsky wrote:
>>>
>>> Okay... You said the you need to intercept the focus request in the place
>>> where the target is set.
>>>   From my point of view opening
>>> Component#requestFocusInWindow(CausedFocusEvent.Cause cause)
>>> resolves that.
>>> But it looks like you need extra. What is the final purpose? Maybe you want
>>> to reject focus transfer depending on the target?
>>>
>>> --Semyon
>>>
>>> On 4/14/2016 3:19 PM, Reto Merz wrote:
>>>> Thanks for your investigation Semyon.
>>>>
>>>> Make Component#requestFocusInWindow(CausedFocusEvent.Cause
>>> cause) public/protected will not help us.
>>>> I can explain it more detailed if you want.
>>>>
>>>> What would help is to introduce a "protected boolean
>>> Component#isRequestFocusAccepted()"
>>>> which is invoked by
>>>>
>>> Component#isRequestFocusAccepted(boolean,boolean,CausedFocusEvent.
>>> Caus
>>>> e) after the "Component.requestFocusController.acceptRequestFocus"
>>>> statement (and only if acceptRequestFocus has returned true).
>>>>
>>>> This way you also don't have to make CausedFocusEvent.Cause public.
>>>>
>>>> Best Regards
>>>> Reto Merz
>>>>
>>>> On 14/04/16 13:09, Semyon Sadetsky wrote:
>>>>
>>>> The FocusTraversalPolicy can be obtained using public API. It may give you
>>> the target. But I believe this is not what you would like to do...
>>>> It seem sensible to make
>>> Component#requestFocusInWindow(CausedFocusEvent.Cause cause)
>>> public. Will it be enough for you?
>>>> I could start to implement this right after the 8080395 push.
>>>>
>>>> --Semyon
>>>>
>>>> On 4/14/2016 12:30 PM, Reto Merz wrote:
>>>> Hello Semyon,
>>>>
>>>> We need to know the target component: "which component will be
>>> focused".
>>>> Target component means the component which should be "really"
>>> focused,
>>>> so this can only be known after all the FocusCycle / FocusTraversalPolicy
>>> logic has processed.
>>>> DefaultKeyboardFocusManager
>>> focusNextComponent/focusPreviousComponent
>>>> provides only the source component. Not the target.
>>>>
>>>> The second argument of RequestFocusController#acceptRequestFocus is
>>> the "real" target component.
>>>> We use only this argument in our custom RequestFocusController
>>> implementation.
>>>> Thanks
>>>> Reto Merz
>>>>
>>>> On 14/04/16 08:31, Semyon Sadetsky wrote:
>>>> Hi Reto,
>>>>
>>>> It is unlikely that AWTAccessor API may be opened. It gives access to
>>> internal undocumented methods not to even mention that those methods
>>> have private and package accesses.
>>>> As I understand you need the way to intercept focus transfer initiated by a
>>> traversal key. Why to subclass the DefaultKeyboardFocusManager to
>>> override its focusNextComponent/ focusPreviousComponent methods?
>>>> --Semyon
>>>>
>>>> On 4/12/2016 2:37 PM, Reto Merz wrote:
>>>> Hello Alexandr,
>>>>
>>>> Basically we need to detect and intercept focus changes.
>>>>
>>>> java.awt.Component allows to override this methods:
>>>> requestFocus()
>>>> requestFocus(boolean)
>>>> requestFocusInWindow()
>>>> requestFocusInWindow(boolean)
>>>>
>>>> requestFocus() is only invoked when the component is focused by a mouse
>>> click.
>>>> But no requestFocus* method is invoked when a FocusTraversalPolicy is
>>>> involed (f. e. the user press TAB to focus next component).
>>>>
>>>> sun.awt.RequestFocusController#acceptRequestFocus is invoked in both
>>> cases.
>>>> Attached a demo to reproduce it:
>>>> - if TextField is focused by a mouse click "requestFocus" and
>>>> "acceptRequestFocus" is logged
>>>> - if TextField is focused by TAB only "acceptRequestFocus" is logged
>>>>
>>>> Some more notes about the test program:
>>>> ComponentAccessorDelegator delegates all calls to the original
>>> ComponentAccessor implementation.
>>>> Only ComponentAccessor#setRequestFocusController is changed to keep
>>> our RequestFocusController implementation.
>>>> I have just filled a RFE onhttp://bugreport.java.com/bugreport
>>>>
>>>> Thanks
>>>> Reto Merz
>>>>
>>>>
>>>> On 11/04/16 21:02, Alexander Scherbatiy wrote:
>>>>    Hello Reto,
>>>>
>>>>    Could you provide use cases which illustrate tasks the requested API is
>>> intended to solve in your application?
>>>>    Please, also create a request in the bug system
>>>> http://bugreport.java.com/bugreport
>>>>
>>>>    Thanks,
>>>> Alexandr.
>>>>
>>>> On 11/04/16 12:26, Alexander Scherbatiy wrote:
>>>>
>>>>    Resending the request to awt-dev alias.
>>>>
>>>>    Thanks,
>>>>    Alexandr.
>>>>
>>>> On 4/4/2016 4:54 PM, Reto Merz wrote:
>>>> Hello,
>>>>
>>>> Jigsaw will disallow access to internal packages.
>>>> We have written a complex validation and focus management
>>>> implementation for our closed-source RIA and maintain it since JRE
>>>> 1.4.
>>>>
>>>> For this we use some internal API. We have a custom implementation of
>>>> these interfaces:
>>>>
>>>> sun.awt.RequestFocusController
>>>> sun.awt.AWTAccessor.ComponentAccessor
>>>>
>>>> And use this getter and setter:
>>>>
>>>>
>>> sun.awt.AWTAccessor#setComponentAccessor(AWTAccessor.ComponentAc
>>> cesso
>>>> r)
>>>> sun.awt.AWTAccessor#getComponentAccessor()
>>>>
>>> sun.awt.AWTAccessor.ComponentAccessor#setRequestFocusController(Req
>>> ue
>>>> stFocusController)
>>>>
>>>>
>>>> Please make this API public.
>>>>
>>>> Furthermore we need to call
>>>> java.awt.Component#revalidateSynchronously().
>>>> We do this with reflection. It would be nice to have a public API for
>>>> this.
>>>> Maybe a new static method on AWTAccessor:
>>>> AWTAccessor.revalidateSynchronously(Component)
>>>>
>>>> Best Regards
>>>> Reto Merz
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>
>


More information about the awt-dev mailing list