JavaFX HTMLEditor text change listener


Question

I'm fairly new to the JavaFX world, and I can't seem to figure out how to listen for text-modify events in the HTMLEditor component.

I need this since I'm hooking this widget to a model, which needs updating.

The addEventFilter API, with a KeyEvent.KEY_TYPED event type doesn't seem to be working as it should. When its handler is called, the getHTMLText() isn't updated yet with the most recent character (if someone doesn't understand this paragraph, I'll provide a step-by-step example).

The TextField has a textProperty() on which a listener can be attached.
Now what about the HTMLEditor?

Also, it would be nice to have the listener called ONLY on text modify events (and not on CTRL+A, for example). You know... like SWT Text's addModifyListener().

1
2
3/2/2014 1:27:08 PM

Accepted Answer

While using JavaFX HTMLEditor in one of my project application, I also faced a similar situation. I ended up adding a button, upon whose click the parsing of the HTML text would happen, and further tasks executed. With AnchorPane, I was able to add the button on the HTMLEditor seamlessly, and it looked like a part of it.

Anyways, here's a little example of how you can achieve what you want without any extra button:

package application;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.web.HTMLEditor;
import javafx.stage.Stage;

public class Main extends Application
{
  @Override
  public void start(Stage primaryStage)
  {
    try
    {
      final HTMLEditor editor = new HTMLEditor();
      Scene scene = new Scene(editor);
      primaryStage.setScene(scene);

      editor.setOnKeyReleased(new EventHandler<KeyEvent>()
      {
        @Override
        public void handle(KeyEvent event)
        {
          if (isValidEvent(event))
          {
            System.out.println(editor.getHtmlText());
          }
        }

        private boolean isValidEvent(KeyEvent event)
        {
          return !isSelectAllEvent(event)
              && ((isPasteEvent(event)) || isCharacterKeyReleased(event));
        }

        private boolean isSelectAllEvent(KeyEvent event)
        {
          return event.isShortcutDown() && event.getCode() == KeyCode.A;
        }

        private boolean isPasteEvent(KeyEvent event)
        {
          return event.isShortcutDown() && event.getCode() == KeyCode.V;
        }

        private boolean isCharacterKeyReleased(KeyEvent event)
        {
          // Make custom changes here..
          switch (event.getCode())
          {
            case ALT:
            case COMMAND:
            case CONTROL:
            case SHIFT:
              return false;
            default:
              return true;
          }
        }
      });

      primaryStage.show();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }

  public static void main(String[] args)
  {
    launch(args);
  }
}

UPDATE: Upon a bit more of thinking, I found a way to get event handling done even on those button clicks. Here's how:

EventHandler<MouseEvent> onMouseExitedHandler = new EventHandler<MouseEvent>()
{
  @Override
  public void handle(MouseEvent event)
  {
    System.out.println(editor.getHtmlText());
  }
};

for (Node node : editor.lookupAll("ToolBar"))
{
  node.setOnMouseExited(onMouseExitedHandler);
}

If you see the HTMLEditor, it has two ToolBars.
What I'm doing in the code is looking up for those two toolbars, and setting an onMouseExited event handler. The analogy is that if the user enters and makes some changes on the HTML Text and exits the toolbar, an event will be fired, which can then be handled.

You can even set different kind of event handlers on these two toolbars, based on your needs, but in my opinion, these onMouseExited event handlers provide a very wide coverage when used with the onKeyReleased event handlers. The coverage based on onMouseExited handler is not exact though.

3
3/3/2014 10:38:50 AM

here is a simple one

public class HtmlEditorListener {
    private final BooleanProperty editedProperty;

    private String htmlRef;

    public HtmlEditorListener(final HTMLEditor editor) {
        editedProperty = new SimpleBooleanProperty();
        editedProperty.addListener((ov, o, n) -> htmlRef = n? null: editor.getHtmlText());
        editedProperty.set(false);

        editor.setOnMouseClicked(e -> checkEdition(editor.getHtmlText()));
        editor.addEventFilter(KeyEvent.KEY_TYPED, e -> checkEdition(editor.getHtmlText()));
    }

    public BooleanProperty editedProperty() {
        return editedProperty;
    }

    private void checkEdition(final String html) {
        if (editedProperty.get()) {
            return;
        }
        editedProperty.set(htmlRef != null
                && html.length() != htmlRef.length()
                || !html.equals(htmlRef));
    }
}

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon