JavaFX – Jak zmienić lub ukryć kursor myszy w całej aplikacji (WebView + Scene)

JavaFX – Jak zmienić lub ukryć kursor myszy w całej aplikacji (WebView + Scene)

W tym poradniku prezentuję kolejne kroki, które umożliwiają wyłączenie bądź zmianę kursora myszki w całej aplikacji JavaFX. Znajdziesz tu rozwiązania problemów, z którymi zetknąłem się do tej pory implementując tytułowe wymaganie. W szczególności dowiesz się w jak sposób możemy wykryć zmianę kursora w kontrolce WebView, aby następnie móc go zmienić na dowolny inny lub też wyłączyć go całkowicie.

Agenda
  1. Zmiana kursora myszy na dowolnej kontrolce JavaFX
  2. Zmiana kursora myszy na komponencie WebView


Zmiana kursora myszy na dowolnej kontrolce JavaFX

Rozważmy przedstawioną poniżej aplikację JavaFX typu HelloWorld. Składa się ona z klasy Main, pełniącej również rolę kontrolera, oraz przykładowej formatki sample.fxml. W klasie znajdziemy uchwyty do kontrolek Pane oraz WebView, jak również metodę initialize, która wykonuje się już po spięciu wspomnianych kontrolek z kontrolerem.

package sample;

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class Main extends Application {

    @FXML
    private Pane myPane;

    @FXML
    private WebView myWebView;

    @FXML
    private void initialize() {

    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        Scene scene = new Scene(root, 300, 275);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.web.WebView?>


<HBox fx:controller="sample.Main"
      maxHeight="-Infinity"
      maxWidth="-Infinity"
      minHeight="-Infinity"
      minWidth="-Infinity"
      prefHeight="400.0"
      prefWidth="600.0"
      xmlns="http://javafx.com/javafx/8.0.121"
      xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Pane prefHeight="200.0" prefWidth="200.0" fx:id="myPane"/>
      <WebView prefHeight="200.0" prefWidth="200.0" fx:id="myWebView" />
   </children>
</HBox>

 

Rozwiązanie A: Zmiana kursora myszki dla aplikacji
Zmiana kursora dla sceny sprowadza się do wywołania na niej metody setCursor(). Poniżej zamieszczam przykład ukrycia kursora dla całej sceny. Wszystkie elementy, poza kontrolką  WebView odziedziczą ustawiony kursor. Przyczyna oraz rozwiązanie problemu z WebView opisałem w kolejnym punkcie.

package sample;

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class Main extends Application {

    @FXML
    private Pane myPane;

    @FXML
    private WebView myWebView;

    @FXML
    private void initialize() {
       
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        Scene scene = new Scene(root, 300, 275);
        scene.setCursor(Cursor.NONE);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


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

 

Rozwiązanie B: Zmiana kursora myszki na kontrolce
Zmianę kursora dla dowolnej kontrolki wykonujmy analogicznie jak w przypadku całej sceny – czyli wołając metodę setCursor na wybranej kontrolce. Poniżej przykład zmiany kursora na symbol otwartej dłoni.

package sample;

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class Main extends Application {

    @FXML
    private Pane myPane;

    @FXML
    private WebView myWebView;

    @FXML
    private void initialize() {
        myPane.setCursor(Cursor.OPEN_HAND);
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        Scene scene = new Scene(root, 300, 275);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


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

 

Zmiana kursora myszy na komponencie WebView

[quads id=1]
Komponent WebView pełni w JavaFX rolę przeglądarki internetowej. W związku z z tym jego głównym zadaniem jest wyświetlanie stron HTML. W przypadku kontrolki WebView problem ukrycia lub zmiany kursora staje się nieco bardziej skomplikowany, ponieważ kursor myszy podczas przeglądania stron internetowych zmienia się dość często a dodatkowo wywołanie metody setCursor na komponencie WebView wydaje się nie przynosić efektu.

Nie jest to jednak do końca prawda. Wywołując metodę myWebView.setCursor(Cursor.NONE) faktycznie ukrywamy kursor, jednak ruch myszki powoduje, że dostosowuje się on do zawartości przeglądanej strony zmieniając się na odpowiedni do danej sytuacji (np. wskazując na link).

Rozwiązanie C: Zmiana kursora myszki w WebView
Rozwiązaniem problemu jest dodanie listenera na atrybut cursor naszego WebView a następnie, gdy tylko wykryjemy zmianę, to natychmiast przestawiamy go z powrotem na docelowy kursor. W praktyce wygląda to jak poniżej:

package sample;

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class Main extends Application {

    @FXML
    private Pane myPane;

    @FXML
    private WebView myWebView;

    @FXML
    private void initialize() {
        myPane.setCursor(Cursor.CROSSHAIR);
        myWebView.setCursor(Cursor.MOVE);
        myWebView.cursorProperty().addListener((observable, oldValue, newValue) -> {
            myWebView.setCursor(Cursor.MOVE);
        });
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        Scene scene = new Scene(root, 300, 275);
        scene.setCursor(Cursor.OPEN_HAND);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


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

 

To byłoby na tyle jeśli chodzi o ten wpis. Jeśli podoba Ci się konwencja i chciałbyś więcej takich wpisów, zostaw mi komentarz z tematem, który Cię interesuje a ja postaram się go przygotować. Tymczasem możesz mi pomóc dotrzeć do większej liczby odbiorców udostępniając ten wpis – Dziękuję.

 

Leave a Reply

avatar
  Subscribe  
Notify of
Close Menu