简体   繁体   中英

JavaFX HTMLEditor text change listener

I'm fairly new to the JavaFX world, and I can't seem to figure out how to listen for events in the 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 has a textProperty() on which a listener can be attached. 具有textProperty() ,可以在其上附加侦听器。
Now what about the ? 呢?

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() .

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.

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));
    }
}

HtmlEditor is based on Web view

    HTMLEditor editor = getEditor();
    WebView webView = (WebView) getEditor().lookup("WebView");
    new WebViewEditorListener(webView, new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {

        }
    });

Add Callback for tracking html changes.

public static class WebViewEditorListener {

        private final ChangeListener<String> listener;

        private final WebPage webPage;

        private String htmlRef, innerText;

        public WebViewEditorListener(final WebView editor, ChangeListener<String> listener) {
            this.listener = listener;
            webPage = Accessor.getPageFor(editor.getEngine());

            editor.setOnMouseClicked(e -> onKeyTyped(webPage.getHtml(webPage.getMainFrame())));
            editor.addEventFilter(KeyEvent.KEY_TYPED, e -> onKeyTyped(webPage.getHtml(webPage.getMainFrame())));
        }

        public String getHtmlContent(){
            return htmlRef == null ? "" : htmlRef ;
        }

        private void onKeyTyped(final String html) {
            boolean isEqual = htmlRef != null ? htmlRef.length() == html.length() : html == null;
            if (!isEqual){
                String text = webPage.getInnerText(webPage.getMainFrame());
                listener.changed(null, innerText, text);
                innerText = text;
                htmlRef = html;
            }

        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM