JavaFX WebView:如何更改默认光标?

huangapple go评论130阅读模式
英文:

JavaFX WebView: how do I change the default cursor?

问题

  1. import javafx.application.Application;
  2. import javafx.scene.Cursor;
  3. import javafx.scene.Scene;
  4. import javafx.scene.layout.VBox;
  5. import javafx.scene.web.WebView;
  6. import javafx.stage.Stage;
  7. public class Main extends Application {
  8. public static void main(String[] args) {
  9. launch(args);
  10. }
  11. public void start(Stage primaryStage) {
  12. primaryStage.setTitle("JavaFX WebView Example");
  13. WebView webView = new WebView();
  14. webView.getEngine().loadContent("http://google.com");
  15. VBox vBox = new VBox(webView);
  16. Scene scene = new Scene(vBox, 960, 600);
  17. scene.setCursor(Cursor.CLOSED_HAND); // Doesn't work, reverted to pointer
  18. primaryStage.setScene(scene);
  19. primaryStage.show();
  20. }
  21. }
英文:

How do I change WebView's default cursor? Every change I make is ignored, the icon always reverts back to the default pointer.

Example:

  1. import javafx.application.Application;
  2. import javafx.scene.Cursor;
  3. import javafx.scene.Scene;
  4. import javafx.scene.layout.VBox;
  5. import javafx.scene.web.WebView;
  6. import javafx.stage.Stage;
  7. public class Main extends Application {
  8. public static void main(String[] args) {
  9. launch(args);
  10. }
  11. public void start(Stage primaryStage) {
  12. primaryStage.setTitle("JavaFX WebView Example");
  13. WebView webView = new WebView();
  14. webView.getEngine().loadContent("http://google.com");
  15. VBox vBox = new VBox(webView);
  16. Scene scene = new Scene(vBox, 960, 600);
  17. scene.setCursor(Cursor.CLOSED_HAND); // Doesn't work, reverted to pointer
  18. primaryStage.setScene(scene);
  19. primaryStage.show();
  20. }
  21. }

I also tried to change the webView cursor itself, but to no avail.

答案1

得分: 4

文档的 HTML 内容定义了光标,因此您可以在加载后修改文档的正文样式:

  1. import org.w3c.dom.Document;
  2. import org.w3c.dom.Element;
  3. import javafx.application.Application;
  4. import javafx.concurrent.Worker;
  5. import javafx.scene.Scene;
  6. import javafx.scene.layout.VBox;
  7. import javafx.scene.web.WebView;
  8. import javafx.stage.Stage;
  9. public class WebViewCursorOverride extends Application {
  10. public static void main(String[] args) {
  11. launch(args);
  12. }
  13. public void start(Stage primaryStage) {
  14. primaryStage.setTitle("JavaFX WebView Example");
  15. WebView webView = new WebView();
  16. webView.getEngine().getLoadWorker().stateProperty().addListener(
  17. (o, old, state) -> {
  18. if (state != Worker.State.SUCCEEDED) {
  19. return;
  20. }
  21. Document doc = webView.getEngine().getDocument();
  22. Element body = (Element)
  23. doc.getElementsByTagName("body").item(0);
  24. String style = body.getAttribute("style");
  25. body.setAttribute("style", "cursor: grab;" + style);
  26. });
  27. webView.getEngine().load("https://google.com");
  28. VBox vBox = new VBox(webView);
  29. Scene scene = new Scene(vBox, 960, 600);
  30. primaryStage.setScene(scene);
  31. primaryStage.show();
  32. }
  33. }

您还可以从图像创建自己的光标:

  1. body.setAttribute("style",
  2. "cursor: url('https://upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Pixel_51_icon_cursor_click_top_right.svg/36px-Pixel_51_icon_cursor_click_top_right.svg.png') 27 9, default;" + style);

完整的 cursor CSS 属性定义在这里。以下是当前预定义光标的完整列表;请注意,并非所有光标在每个系统上都受支持:

  • auto
  • default
  • none
  • context-menu
  • help
  • pointer
  • progress
  • wait
  • cell
  • crosshair
  • text
  • vertical-text
  • alias
  • copy
  • move
  • no-drop
  • not-allowed
  • grab
  • grabbing
  • e-resize
  • n-resize
  • ne-resize
  • nw-resize
  • s-resize
  • se-resize
  • sw-resize
  • w-resize
  • ew-resize
  • ns-resize
  • nesw-resize
  • nwse-resize
  • col-resize
  • row-resize
  • all-scroll
  • zoom-in
  • zoom-out
英文:

The document’s HTML content defines the cursor, so you can modify the document’s body style after it loads:

  1. import org.w3c.dom.Document;
  2. import org.w3c.dom.Element;
  3. import javafx.application.Application;
  4. import javafx.concurrent.Worker;
  5. import javafx.scene.Scene;
  6. import javafx.scene.layout.VBox;
  7. import javafx.scene.web.WebView;
  8. import javafx.stage.Stage;
  9. public class WebViewCursorOverride extends Application {
  10. public static void main(String[] args) {
  11. launch(args);
  12. }
  13. public void start(Stage primaryStage) {
  14. primaryStage.setTitle("JavaFX WebView Example");
  15. WebView webView = new WebView();
  16. webView.getEngine().getLoadWorker().stateProperty().addListener(
  17. (o, old, state) -> {
  18. if (state != Worker.State.SUCCEEDED) {
  19. return;
  20. }
  21. Document doc = webView.getEngine().getDocument();
  22. Element body = (Element)
  23. doc.getElementsByTagName("body").item(0);
  24. String style = body.getAttribute("style");
  25. body.setAttribute("style", "cursor: grab;" + style);
  26. });
  27. webView.getEngine().load("https://google.com");
  28. VBox vBox = new VBox(webView);
  29. Scene scene = new Scene(vBox, 960, 600);
  30. primaryStage.setScene(scene);
  31. primaryStage.show();
  32. }
  33. }

You can also create your own cursor from an image:

  1. body.setAttribute("style",
  2. "cursor: url('https://upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Pixel_51_icon_cursor_click_top_right.svg/36px-Pixel_51_icon_cursor_click_top_right.svg.png') 27 9, default;" + style);

The full definition of the cursor CSS property is here. Here is the current list of predefined cursors; note that not all of them are supported on every system:

  • auto
  • default
  • none
  • context-menu
  • help
  • pointer
  • progress
  • wait
  • cell
  • crosshair
  • text
  • vertical-text
  • alias
  • copy
  • move
  • no-drop
  • not-allowed
  • grab
  • grabbing
  • e-resize
  • n-resize
  • ne-resize
  • nw-resize
  • s-resize
  • se-resize
  • sw-resize
  • w-resize
  • ew-resize
  • ns-resize
  • nesw-resize
  • nwse-resize
  • col-resize
  • row-resize
  • all-scroll
  • zoom-in
  • zoom-out

答案2

得分: 1

以下是您提供的代码翻译部分:

  1. @VGR的解决方案很优雅但在我的机器上会引发闪烁问题
  2. 一个更激进的解决方案是将`WebEngine`使用的`CursorManager`替换为其他内容
  3. 例如Java10您可以基于默认的`CursorManagerImpl`创建这个`CursorManagerImpl2`
  4. ```java
  5. import com.sun.webkit.CursorManager;
  6. import com.sun.webkit.graphics.WCGraphicsManager;
  7. import com.sun.webkit.graphics.WCImage;
  8. import javafx.application.Application;
  9. import javafx.scene.Cursor;
  10. import javafx.scene.ImageCursor;
  11. import javafx.scene.Scene;
  12. import javafx.scene.image.Image;
  13. import javafx.scene.layout.VBox;
  14. import javafx.scene.web.WebView;
  15. import javafx.stage.Stage;
  16. import java.util.*;
  17. public class CursorManagerImpl2 extends CursorManager<javafx.scene.Cursor> {
  18. // ... (略去部分代码)
  19. }

然后您可以使用以下方式替换管理器:

  1. CursorManager.setCursorManager(new CursorManagerImpl2(javafx.scene.Cursor.CROSSHAIR));

要更改默认光标,可以使用:

  1. ((CursorManagerImpl2) CursorManager.getCursorManager()).setDefaultCursor(javafx.scene.Cursor.MOVE);

注意,您可能需要将com.sun包添加到您的Gradle依赖中:

  1. compileJava {
  2. options.compilerArgs.addAll(['--add-exports=javafx.web/com.sun.webkit=ALL-UNNAMED', '--add-exports=javafx.web/com.sun.javafx.webkit=ALL-UNNAMED', '--add-exports=javafx.web/com.sun.webkit.graphics=ALL-UNNAMED', '--add-exports=javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED'])
  3. }
  4. run {
  5. jvmArgs = ['--add-exports=javafx.web/com.sun.webkit=ALL-UNNAMED', '--add-exports=javafx.web/com.sun.javafx.webkit=ALL-UNNAMED', '--add-exports=javafx.web/com.sun.webkit.graphics=ALL-UNNAMED', '--add-exports=javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED']
  6. }

通过这种方式,即使使用大型自定义光标,在移动鼠标时我不会遇到任何闪烁问题。

最大的缺点(除了com.sun的导入之外)是CursorManager是静态的;因此,所有的WebViews将使用相同的光标管理。

  1. <details>
  2. <summary>英文:</summary>
  3. The solution by @VGR is elegant, but induces flickering on my machine.
  4. A more drastic solution is replacing the `CursorManager` used by `WebEngine` by something else.
  5. For example, in Java10 you can create this `CursorManagerImpl2` class based on the default `CursorManagerImpl`:
  6. ```java
  7. import com.sun.webkit.CursorManager;
  8. import com.sun.webkit.graphics.WCGraphicsManager;
  9. import com.sun.webkit.graphics.WCImage;
  10. import javafx.application.Application;
  11. import javafx.scene.Cursor;
  12. import javafx.scene.ImageCursor;
  13. import javafx.scene.Scene;
  14. import javafx.scene.image.Image;
  15. import javafx.scene.layout.VBox;
  16. import javafx.scene.web.WebView;
  17. import javafx.stage.Stage;
  18. import java.util.*;
  19. public class CursorManagerImpl2 extends CursorManager&lt;javafx.scene.Cursor&gt; {
  20. private final Map&lt;String, javafx.scene.Cursor&gt; map = new HashMap();
  21. private ResourceBundle bundle;
  22. private javafx.scene.Cursor defaultCursor = javafx.scene.Cursor.DEFAULT;
  23. public CursorManagerImpl2() {}
  24. public CursorManagerImpl2(javafx.scene.Cursor defaultCursor) {
  25. this.defaultCursor = defaultCursor;
  26. }
  27. public javafx.scene.Cursor getDefaultCursor() {
  28. return defaultCursor;
  29. }
  30. public void setDefaultCursor(javafx.scene.Cursor cursor) {
  31. defaultCursor = cursor;
  32. }
  33. @Override
  34. protected javafx.scene.Cursor getCustomCursor(WCImage image, int hotspotX, int hotspotY) {
  35. return new ImageCursor(
  36. com.sun.javafx.tk.Toolkit.getImageAccessor()
  37. .fromPlatformImage(WCGraphicsManager.getGraphicsManager().toPlatformImage(image)),
  38. hotspotX,
  39. hotspotY);
  40. }
  41. @Override
  42. protected javafx.scene.Cursor getPredefinedCursor(int type) {
  43. switch (type) {
  44. case 0:
  45. default: return defaultCursor; // line changed
  46. case 1: return javafx.scene.Cursor.CROSSHAIR;
  47. case 2: return javafx.scene.Cursor.HAND;
  48. case 3: return javafx.scene.Cursor.MOVE;
  49. case 4: return javafx.scene.Cursor.TEXT;
  50. case 5: return javafx.scene.Cursor.WAIT;
  51. case 6: return this.getCustomCursor(&quot;help&quot;, javafx.scene.Cursor.DEFAULT);
  52. case 7: return javafx.scene.Cursor.E_RESIZE;
  53. case 8: return javafx.scene.Cursor.N_RESIZE;
  54. case 9: return javafx.scene.Cursor.NE_RESIZE;
  55. case 10: return javafx.scene.Cursor.NW_RESIZE;
  56. case 11: return javafx.scene.Cursor.S_RESIZE;
  57. case 12: return javafx.scene.Cursor.SE_RESIZE;
  58. case 13: return javafx.scene.Cursor.SW_RESIZE;
  59. case 14: return javafx.scene.Cursor.W_RESIZE;
  60. case 15: return javafx.scene.Cursor.V_RESIZE;
  61. case 16: return javafx.scene.Cursor.H_RESIZE;
  62. case 17: return this.getCustomCursor(&quot;resize.nesw&quot;, javafx.scene.Cursor.DEFAULT);
  63. case 18: return this.getCustomCursor(&quot;resize.nwse&quot;, javafx.scene.Cursor.DEFAULT);
  64. case 19: return this.getCustomCursor(&quot;resize.column&quot;, javafx.scene.Cursor.H_RESIZE);
  65. case 20: return this.getCustomCursor(&quot;resize.row&quot;, javafx.scene.Cursor.V_RESIZE);
  66. case 21: return this.getCustomCursor(&quot;panning.middle&quot;, javafx.scene.Cursor.DEFAULT);
  67. case 22: return this.getCustomCursor(&quot;panning.east&quot;, javafx.scene.Cursor.DEFAULT);
  68. case 23: return this.getCustomCursor(&quot;panning.north&quot;, javafx.scene.Cursor.DEFAULT);
  69. case 24: return this.getCustomCursor(&quot;panning.ne&quot;, javafx.scene.Cursor.DEFAULT);
  70. case 25: return this.getCustomCursor(&quot;panning.nw&quot;, javafx.scene.Cursor.DEFAULT);
  71. case 26: return this.getCustomCursor(&quot;panning.south&quot;, javafx.scene.Cursor.DEFAULT);
  72. case 27: return this.getCustomCursor(&quot;panning.se&quot;, javafx.scene.Cursor.DEFAULT);
  73. case 28: return this.getCustomCursor(&quot;panning.sw&quot;, javafx.scene.Cursor.DEFAULT);
  74. case 29: return this.getCustomCursor(&quot;panning.west&quot;, javafx.scene.Cursor.DEFAULT);
  75. case 30: return this.getCustomCursor(&quot;vertical.text&quot;, javafx.scene.Cursor.DEFAULT);
  76. case 31: return this.getCustomCursor(&quot;cell&quot;, javafx.scene.Cursor.DEFAULT);
  77. case 32: return this.getCustomCursor(&quot;context.menu&quot;, javafx.scene.Cursor.DEFAULT);
  78. case 33: return this.getCustomCursor(&quot;no.drop&quot;, javafx.scene.Cursor.DEFAULT);
  79. case 34: return this.getCustomCursor(&quot;not.allowed&quot;, javafx.scene.Cursor.DEFAULT);
  80. case 35: return this.getCustomCursor(&quot;progress&quot;, javafx.scene.Cursor.WAIT);
  81. case 36: return this.getCustomCursor(&quot;alias&quot;, javafx.scene.Cursor.DEFAULT);
  82. case 37: return this.getCustomCursor(&quot;zoom.in&quot;, javafx.scene.Cursor.DEFAULT);
  83. case 38: return this.getCustomCursor(&quot;zoom.out&quot;, javafx.scene.Cursor.DEFAULT);
  84. case 39: return this.getCustomCursor(&quot;copy&quot;, javafx.scene.Cursor.DEFAULT);
  85. case 40: return javafx.scene.Cursor.NONE;
  86. case 41: return this.getCustomCursor(&quot;grab&quot;, javafx.scene.Cursor.OPEN_HAND);
  87. case 42: return this.getCustomCursor(&quot;grabbing&quot;, javafx.scene.Cursor.CLOSED_HAND);
  88. }
  89. }
  90. private javafx.scene.Cursor getCustomCursor(String cursorId, javafx.scene.Cursor defaultCursor) {
  91. javafx.scene.Cursor customCursor = this.map.get(cursorId);
  92. if (customCursor == null) {
  93. try {
  94. if (this.bundle == null) {
  95. this.bundle =
  96. ResourceBundle.getBundle(&quot;com.sun.javafx.webkit.Cursors&quot;, Locale.getDefault());
  97. }
  98. if (this.bundle != null) {
  99. String fileName = this.bundle.getString(cursorId + &quot;.file&quot;);
  100. javafx.scene.image.Image image =
  101. new Image(com.sun.javafx.webkit.CursorManagerImpl.class.getResourceAsStream(fileName));
  102. fileName = this.bundle.getString(cursorId + &quot;.hotspotX&quot;);
  103. int hotspotX = Integer.parseInt(fileName);
  104. fileName = this.bundle.getString(cursorId + &quot;.hotspotY&quot;);
  105. int hotspotY = Integer.parseInt(fileName);
  106. customCursor = new ImageCursor(image, hotspotX, hotspotY);
  107. }
  108. } catch (MissingResourceException e) {
  109. }
  110. if (customCursor == null) {
  111. customCursor = defaultCursor;
  112. }
  113. this.map.put(cursorId, customCursor);
  114. }
  115. return customCursor;
  116. }
  117. }

You can then replace the manager with

  1. CursorManager.setCursorManager(new CursorManagerImpl2(javafx.scene.Cursor.CROSSHAIR));

To change the default cursor, you can use

  1. ((CursorManagerImpl2) CursorManager.getCursorManager()).setDefaultCursor(javafx.scene.Cursor.MOVE);

Note that you might have to add the com.sun packages to your gradle:

  1. compileJava {
  2. options.compilerArgs.addAll([&#39;--add-exports=javafx.web/com.sun.webkit=ALL-UNNAMED&#39;, &#39;--add-exports=javafx.web/com.sun.javafx.webkit=ALL-UNNAMED&#39;, &#39;--add-exports=javafx.web/com.sun.webkit.graphics=ALL-UNNAMED&#39;, &#39;--add-exports=javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED&#39;])
  3. }
  4. run {
  5. jvmArgs = [&#39;--add-exports=javafx.web/com.sun.webkit=ALL-UNNAMED&#39;, &#39;--add-exports=javafx.web/com.sun.javafx.webkit=ALL-UNNAMED&#39;, &#39;--add-exports=javafx.web/com.sun.webkit.graphics=ALL-UNNAMED&#39;, &#39;--add-exports=javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED&#39;]
  6. }

With this, I do not suffer from any flickering while moving the mouse, even when using large custom cursors.

The big downside (beside the com.sun imports) is that the CursorManager is static; as such, all WebViews will use the same cursor management.

huangapple
  • 本文由 发表于 2020年4月4日 07:24:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/61021849.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定