3

Trying to do a requestFocus() on the WebView does not work until the user has first clicked on the control.

I know this must be possible as htmlEditor can be focused this way (and I suspect it is based on a contenteditable WebView).

I am coding my own specialized htmlEditor using a webview with "contenteditable" and I would really like to be able to focus it like I can do with the standard htmlEditor.

I believe this must be an issue with Javafx and I have already submitted it to Jira, but I wonder if anyone can think of a work-around for this.

UPDATE: Issue number in jira: RT-21695

Short demostration code:

/* Demo webview */

public class WebViewConteneditableDemo extends Application {


String initialEditview = "<html><head>"
        + "</head><body contenteditable='true'>"
        +"</body></html>";

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

@Override
public void start(Stage primaryStage) {
    primaryStage.setTitle("Webview focus demo");


    final WebView editor = new WebView();

    Button btn = new Button();
    btn.setText("Test Webview focus");
    btn.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {
           editor.requestFocus();
        }
    });

    BorderPane root = new BorderPane();
    root.setTop(btn);

    root.setCenter(editor);
    editor.getEngine().loadContent(initialEditview);

    primaryStage.setScene(new Scene(root, 500, 450));
    primaryStage.show();
}

}

betaman
  • 1,865
  • 5
  • 25
  • 30
  • 1
    Add also the Jira issue number/link. – Uluk Biy May 21 '12 at 12:55
  • I can't reproduce the issue you refer to, can you add a short, compilable example which demonstrates the issue. – jewelsea May 21 '12 at 17:45
  • Added, as you can see, I used a button to set focus, but you can try to do it in any other way, it will not work until the editor is clicked manually... then it does work. – betaman May 22 '12 at 01:03

2 Answers2

4

The requestFocus api is just a request for focus, it does not guarantee focus.

Sometimes the internal implementation of other JavaFX controls request focus before or after you have requested focus which ends up in your requestFocus call not having any effect.

Often you can make the requestFocus call take effect by either wrapping it in a Platform.runLater or using a Timeline with a KeyFrame which invokes requestFocus after a delay.

If neither of those work, then there is likely a bug in the requestFocus processing for WebView which the JavaFX team can address in the context of the jira you filed.

Update

The specific issue in the sample code in the question was that, although the WebView was focused, the editable content element in the WebView was not focused.

I tried loading just the html from the sample code <html><head></head><body contenteditable='true'></body></html> into firefox and it behaved exactly the same as the JavaFX WebView (i.e. the editable content element was not focused until it was clicked on). So I don't believe this is an issue with WebView.

To get the editable element focused, you need to execute some script when you want it focused, for example in the javascript onload hook <body onLoad='document.body.focus();' contenteditable='true'/>

Here is an executable sample application which demonstrates programmatic control of focus behaviour of contenteditable elements in a JavaFX WebView:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class WebViewEditable extends Application {
  String content = "<body bgcolor='cornsilk' onLoad='document.body.focus();' contenteditable='true'/>";
  public static void main(String[] args) { launch(args); }
  @Override public void start(Stage stage) {
    final WebView editor = new WebView();
    editor.getEngine().loadContent(content);

    Button webviewFocusButton = new Button("Focus on WebView");
    webviewFocusButton.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent event) {
        editor.getEngine().executeScript("document.body.focus()");
        editor.requestFocus();
      }
    });
    Button selfFocusButton = new Button("Focus on this Button");

    Label focusLabel = new Label();
    focusLabel.textProperty().bind(Bindings
      .when(editor.focusedProperty())
        .then("WebView has the focus.")
        .otherwise("WebView does not have the focus.")
    );
    focusLabel.setMaxWidth(Double.MAX_VALUE);
    focusLabel.setStyle("-fx-background-color: coral; -fx-padding: 5;");

    BorderPane layout = new BorderPane();
    layout.setTop(HBoxBuilder.create().spacing(10).children(webviewFocusButton, selfFocusButton).style("-fx-padding: 10; -fx-background-color: palegreen").build());
    layout.setCenter(editor);
    layout.setBottom(focusLabel);
    stage.setScene(new Scene(layout));
    stage.show();
  }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • There must be a way to focus an object programatically. I tried a Platform.runLater, a Timer, and even tried from a button to make sure it had nothing to do with timing. Nothing works, but after you give focus with a click... it does take focus with a requestFocus. – betaman May 22 '12 at 00:43
  • Perhaps if you add a listener to the document property of the webengine, and, once the document has been loaded either requestFocus in java or run an executescript on the webengine to [focus using javascript](http://www.w3schools.com/jsref/met_html_focus.asp) – jewelsea May 22 '12 at 00:53
  • Yes, I tried the listener and nothing. But I have not tried it from javascript... let me try it fast... – betaman May 22 '12 at 01:09
  • I have posted the complete demo code now... just noticed it was missing some parts – betaman May 22 '12 at 01:24
  • Yes! This solution works great. Thank you very much jewelsea for providing use with this code. Javafx is a pleasure to work with. – betaman May 23 '12 at 08:57
4

you can focus the webview of the HTMLEditor this way:

import com.sun.javafx.scene.web.skin.HTMLEditorSkin;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.web.HTMLEditor;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class FocusTest extends Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        final HTMLEditor editor = new HTMLEditor();
        final WebView editorView = (WebView) editor.lookup(".web-view");

        primaryStage.setScene(new Scene(editor));
        primaryStage.sizeToScene();
        primaryStage.show();

        Platform.runLater(() -> {
            view.fireEvent(new MouseEvent(MouseEvent.MOUSE_PRESSED, 100, 100, 200, 200, MouseButton.PRIMARY, 1, false, false, false, false, false, false, false, false, false, false, null));
            editor.requestFocus();
            view.fireEvent(new MouseEvent(MouseEvent.MOUSE_RELEASED, 100, 100, 200, 200, MouseButton.PRIMARY, 1, false, false, false, false, false, false, false, false, false, false, null));
        });
    }

}
Fred
  • 79
  • 3