TextField Document model
Mark Claassen
markclaassenx at gmail.com
Thu Oct 18 13:00:48 PDT 2012
> BTW, if you find that changing it dynamically works perfect, I'd be happy
to do the code review (including Jonathan).
Sure. How do I proceed with this? Create a Jira issue and then submit the
changes that way?
> Content should be pluggable on a given TextInputControl, or whether it
should require subclassing.
Subclassing seems a bit inconvenient. To control the input on every text
field on a form, all the fields would need to be custom components. This
would mean that there would be very few TextFields in my app, I would have
just MyTextField everywhere. Also, how would I code it? If I was just
using setContent() I would do something like:
firstField.setContent(new
RestrictedLengthContent(Person.FIRST_NAME_LENGTH));
lastField.setContent(new RestrictedLengthContent(Person.LAST_NAME_LENGTH));
How would I do that in subclasses and still use SceneBuilder? Maybe there
would be a way in SceneBuilder to allow the use of a parameterized
constructor with a custom parameter, but that seems pretty complex.
> In your case I'm guessing the content is set before...
I just provided you with one easy case. In reality, we try to be far more
clever. ;-)
However, that is mostly right, and with all these new tools in FX, I think
we will make different choices when that time comes.
> might fail in the control & in the skin
I am pretty new to this, and I have not really addressed the Skin and
Behavior aspects of everything. Is there a good place to learn how this
all is intended to work together? It sounds like this is to break apart
the PLAF Look and the PLAF Feel. (Also, a FX skin is more about how things
are painted, and is not the definition that some products use where a
different skin completely rearranges the UI.)
Mark
On Thu, Oct 18, 2012 at 3:28 PM, Richard Bair <richard.bair at oracle.com>wrote:
> I think Greg did make it all mutable initially, and I probably made them
> final. This was likely due to the fact that the text controls were being
> rewritten only weeks before the 2.0 release and it was easier to prove
> correctness when the Content wasn't changing. Note that "Content" is
> protected already, so from our perspective it is public API, so making it
> public isn't a big change for us. The question is whether Content should be
> pluggable on a given TextInputControl, or whether it should require
> subclassing.
>
> I think I remember at one point the theory being, just subclass and
> provide your own Content in the call to super's constructor. However there
> was a problem with this, because TextInputControlSkin wasn't public, and
> TextFieldSkin etc require a specific subtype of TextInputControl, and as
> such, you couldn't realistically create any subclass of TextInputControl
> (crap!). I discovered that problem after we shipped 2.0.
>
> I think if we want to make content mutable, then we need to do a
> comprehensive review to see where it might fail in the control & in the
> skin. That is, does the skin get a reference to the content and hold on to
> it? Or does it always call getContent() when it needs a reference? If the
> content changes, do we need to clean any state on the skin or on the
> control? In your case I'm guessing the content is set before the skin is,
> and never thereafter changed, and so it acts as though it is an immutable
> property still, so things work great. I'm guessing though that dynamically
> changing the content at runtime might cause some issues?
>
> I don't have any philosophical reason for not having content be mutable.
> My only concern here is that having it mutable introduces some additional
> complexity in the class / skin -- or at least it might.
>
> BTW, if you find that changing it dynamically works perfect, I'd be happy
> to do the code review (including Jonathan).
>
> Thanks
> Richard
>
> On Oct 18, 2012, at 12:03 PM, Mark Claassen wrote:
>
> > My initial proof of concept worked perfectly... limited to 10 characters,
> > forced upper case
> >
> > Altering the source I did the following:
> > Made TextInputControl.Content public
> > Made a setContent(Content content) method in TextInputControl
> > Made the member variable "content" in TextInputControl to be non-final
> > Made TextFieldContent in TextField public
> > Made TextFieldContent in TextField non-static
> >
> > In my source code, I then did:
> > TextInputControl.Content content = new
> TextField.TextFieldContent()
> > {
> > @Override
> > public void insert(int i, String string, boolean bln) {
> > if (10 - length() => string.length())
> > super.insert(i, string.toUpperCase(), bln);
> > }
> > };
> >
> > I don't know why the designers made these things final and
> > private/protected. I would imagine they had a reason, so my JFX source
> > changes would probably need to be more carefully considered. I just
> wanted
> > tom show it was possible.
> >
> > Mark
> >
> >
> > On Thu, Oct 18, 2012 at 2:37 PM, Mark Claassen <markclaassenx at gmail.com
> >wrote:
> >
> >> I got the source and figured it out...or at least found a problem.
> >>
> >> The TextInputControl.Content seems to be exactly what I need. However,
> it
> >> is not public. Further, the instance variable is a final member in
> >> TextInputControl.
> >>
> >> First, Content, and the default implementations, need to be public so
> they
> >> can be easily extended. I have feeling these were intended to be public
> >> when the time was right.
> >>
> >> Second, there needs to be some way to plug this behavior. If it is
> going
> >> to remain final, then there needs to be a way to specify the Content
> class
> >> in the FXML. The SceneBuilder is clearly the way most UIs are supposed
> to
> >> be designed, so, therefore, it needs to be pretty all-encompassing.
> >>
> >> Mark
> >>
> >>
> >> On Wed, Oct 17, 2012 at 5:05 PM, Scott Palmer <swpalmer at gmail.com>
> wrote:
> >>
> >>> Using the override mechanism that Will suggested is probably easier for
> >>> converting to uppercase.
> >>>
> >>> final TextField allCapsTextField = new TextField() {
> >>> @Override
> >>> public void replaceText(int start, int end, String text) {
> >>> super.replaceText(start, end, text.toUppercase());
> >>> }
> >>> @Override
> >>> public void replaceSelection(String text) {
> >>> super.replaceSelection(text.toUppercase());
> >>> }
> >>> };
> >>>
> >>> or you could still use the Event Filter and handle the insertion of the
> >>> characters manually if they are lowercase
> >>> and then consume the event. I think that will be more work and be more
> >>> error-prone though. As you mention you would have to handle pasting
> and
> >>> drag and drop and all ugly details. Overriding seems cleaner.
> >>>
> >>> Perhaps you should take a look at the source code to TextInputControl.
> >>> Instead of the Document they have a Content interface. Maybe you can
> do
> >>> some of what you want by overriding getContent().
> >>>
> >>> Scott
> >>>
> >>> On 2012-10-17, at 4:41 PM, Mark Claassen <markclaassenx at gmail.com>
> wrote:
> >>>
> >>>> Thanks for the tips. The overriding method does not seem very
> >>> pluggable,
> >>>> so I started with the event filter.
> >>>>
> >>>> I like the idea of an event filter, and I really like the how JavaFX
> >>>> defined the process and the order in which items will receive events.
> >>>>
> >>>> So, I quickly implemented my event filter like this:
> >>>> input.addEventFilter(KeyEvent.
> >>>> KEY_TYPED, new EventHandler<KeyEvent>() {
> >>>> @Override
> >>>> public void handle(KeyEvent t) {
> >>>> if (input.getText().length() >=10)
> >>>> t.consume();
> >>>> }
> >>>> });
> >>>>
> >>>> This works for typing, but, of course, I can paste whatever I wanted.
> >>>> (Perhaps I need to find a second filter for that? How about DnD?)
> >>>>
> >>>> All input events go through the Swing Document, so with that, there
> was
> >>>> just one method to mess with.
> >>>>
> >>>> Further, I currently have a Document implementation that takes user
> >>> input
> >>>> and converts it to upper case. (It doesn't force the user to type in
> an
> >>>> upper case character, it just converts it if it is not.) Since, in
> the
> >>>> case of a Document, I can control exactly what the data is, this is
> >>> pretty
> >>>> straightforward. How is that accomplished here? Consume the event,
> and
> >>>> then first a new modified copy of the original. Or do I need to start
> >>>> overriding various methods?
> >>>>
> >>>>
> >>>> On Wed, Oct 17, 2012 at 4:40 PM, Mark Claassen <
> markclaassenx at gmail.com
> >>>> wrote:
> >>>>
> >>>>> Thanks for the tips. The overriding method does not seem very
> >>> pluggable,
> >>>>> so I started with the event filter.
> >>>>>
> >>>>> I like the idea of an event filter, and I really like the how JavaFX
> >>>>> defined the process and the order in which items will receive events.
> >>>>>
> >>>>> So, I quickly implemented my event filter like this:
> >>>>> input.addEventFilter(KeyEvent.KEY_TYPED, new
> >>>>> EventHandler<KeyEvent>() {
> >>>>> @Override
> >>>>> public void handle(KeyEvent t) {
> >>>>> if (input.getText().length() >=10)
> >>>>> t.consume();
> >>>>> }
> >>>>> });
> >>>>>
> >>>>> This works for typing, but, of course, I can paste whatever I wanted.
> >>>>> (Perhaps I need to find a second filter for that? How about DnD?)
> >>>>>
> >>>>> All input events go through the Swing Document, so with that, there
> was
> >>>>> just one method to mess with.
> >>>>>
> >>>>> Further, I currently have a Document implementation that takes user
> >>> input
> >>>>> and converts it to upper case. (It doesn't force the user to type in
> >>> an
> >>>>> upper case character, it just converts it if it is not.) Since, in
> the
> >>>>> case of a Document, I can control exactly what the data is, this is
> >>> pretty
> >>>>> straightforward. How is that accomplished here? Consume the event,
> >>> and
> >>>>> then first a new modified copy of the original. Or do I need to
> start
> >>>>> overriding various methods?
> >>>>>
> >>>>> Mark
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>> On Wed, Oct 17, 2012 at 2:13 PM, Will Hoover <java.whoover at gmail.com
> >>>> wrote:
> >>>>>
> >>>>>> Have you tried:
> >>>>>>
> >>>>>> final TextField tf = new TextField() {
> >>>>>> final String restictTo = "[A-Z\\s]*";
> >>>>>> @Override
> >>>>>> public void replaceText(int start, int end, String text) {
> >>>>>> if (matchTest(text)) {
> >>>>>> super.replaceText(start, end, text);
> >>>>>> }
> >>>>>> }
> >>>>>> @Override
> >>>>>> public void replaceSelection(String text) {
> >>>>>> if (matchTest(text)) {
> >>>>>> super.replaceSelection(text);
> >>>>>> }
> >>>>>> }
> >>>>>> private boolean matchTest(String text) {
> >>>>>> return text.isEmpty() || text.matches(restictTo);
> >>>>>> }
> >>>>>> };
> >>>>>>
> >>>>>> -----Original Message-----
> >>>>>> From: openjfx-dev-bounces at openjdk.java.net
> >>>>>> [mailto:openjfx-dev-bounces at openjdk.java.net] On Behalf Of Mark
> >>> Claassen
> >>>>>> Sent: Wednesday, October 17, 2012 1:08 PM
> >>>>>> To: openjfx-dev at openjdk.java.net
> >>>>>> Subject: TextField Document model
> >>>>>>
> >>>>>> JTextComponents (like JTextField) has a javax.swing.text.Document
> >>> model
> >>>>>> that
> >>>>>> made it pretty easy to create a text field that only allowed a
> certain
> >>>>>> number of characters in it. Similarly, it was also easy to make a
> >>>>>> Document
> >>>>>> model that took all input, but forced characters to upper case.
> >>>>>>
> >>>>>> @Override
> >>>>>> public void insertString(int offs, String str, AttributeSet a)
> throws
> >>>>>> BadLocationException {
> >>>>>> <Do stuff>
> >>>>>> }
> >>>>>>
> >>>>>> What is there going to be in JavaFX to accomplish the same goals?
> >>>>>>
> >>>>>> Mark
> >>>>>>
> >>>>>>
> >>>>>
> >>>
> >>>
> >>
>
>
More information about the openjfx-dev
mailing list