英文:
JavaFX WebView: how do I change the default cursor?
问题
import javafx.application.Application;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX WebView Example");
WebView webView = new WebView();
webView.getEngine().loadContent("http://google.com");
VBox vBox = new VBox(webView);
Scene scene = new Scene(vBox, 960, 600);
scene.setCursor(Cursor.CLOSED_HAND); // Doesn't work, reverted to pointer
primaryStage.setScene(scene);
primaryStage.show();
}
}
英文:
How do I change WebView's default cursor? Every change I make is ignored, the icon always reverts back to the default pointer.
Example:
import javafx.application.Application;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX WebView Example");
WebView webView = new WebView();
webView.getEngine().loadContent("http://google.com");
VBox vBox = new VBox(webView);
Scene scene = new Scene(vBox, 960, 600);
scene.setCursor(Cursor.CLOSED_HAND); // Doesn't work, reverted to pointer
primaryStage.setScene(scene);
primaryStage.show();
}
}
I also tried to change the webView
cursor itself, but to no avail.
答案1
得分: 4
文档的 HTML 内容定义了光标,因此您可以在加载后修改文档的正文样式:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class WebViewCursorOverride extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX WebView Example");
WebView webView = new WebView();
webView.getEngine().getLoadWorker().stateProperty().addListener(
(o, old, state) -> {
if (state != Worker.State.SUCCEEDED) {
return;
}
Document doc = webView.getEngine().getDocument();
Element body = (Element)
doc.getElementsByTagName("body").item(0);
String style = body.getAttribute("style");
body.setAttribute("style", "cursor: grab;" + style);
});
webView.getEngine().load("https://google.com");
VBox vBox = new VBox(webView);
Scene scene = new Scene(vBox, 960, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
您还可以从图像创建自己的光标:
body.setAttribute("style",
"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:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class WebViewCursorOverride extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX WebView Example");
WebView webView = new WebView();
webView.getEngine().getLoadWorker().stateProperty().addListener(
(o, old, state) -> {
if (state != Worker.State.SUCCEEDED) {
return;
}
Document doc = webView.getEngine().getDocument();
Element body = (Element)
doc.getElementsByTagName("body").item(0);
String style = body.getAttribute("style");
body.setAttribute("style", "cursor: grab;" + style);
});
webView.getEngine().load("https://google.com");
VBox vBox = new VBox(webView);
Scene scene = new Scene(vBox, 960, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
You can also create your own cursor from an image:
body.setAttribute("style",
"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
以下是您提供的代码翻译部分:
@VGR的解决方案很优雅,但在我的机器上会引发闪烁问题。
一个更激进的解决方案是将`WebEngine`使用的`CursorManager`替换为其他内容。
例如,在Java10中,您可以基于默认的`CursorManagerImpl`创建这个`CursorManagerImpl2`类:
```java
import com.sun.webkit.CursorManager;
import com.sun.webkit.graphics.WCGraphicsManager;
import com.sun.webkit.graphics.WCImage;
import javafx.application.Application;
import javafx.scene.Cursor;
import javafx.scene.ImageCursor;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import java.util.*;
public class CursorManagerImpl2 extends CursorManager<javafx.scene.Cursor> {
// ... (略去部分代码)
}
然后您可以使用以下方式替换管理器:
CursorManager.setCursorManager(new CursorManagerImpl2(javafx.scene.Cursor.CROSSHAIR));
要更改默认光标,可以使用:
((CursorManagerImpl2) CursorManager.getCursorManager()).setDefaultCursor(javafx.scene.Cursor.MOVE);
注意,您可能需要将com.sun
包添加到您的Gradle依赖中:
compileJava {
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'])
}
run {
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']
}
通过这种方式,即使使用大型自定义光标,在移动鼠标时我不会遇到任何闪烁问题。
最大的缺点(除了com.sun
的导入之外)是CursorManager
是静态的;因此,所有的WebViews
将使用相同的光标管理。
<details>
<summary>英文:</summary>
The solution by @VGR is elegant, but induces flickering on my machine.
A more drastic solution is replacing the `CursorManager` used by `WebEngine` by something else.
For example, in Java10 you can create this `CursorManagerImpl2` class based on the default `CursorManagerImpl`:
```java
import com.sun.webkit.CursorManager;
import com.sun.webkit.graphics.WCGraphicsManager;
import com.sun.webkit.graphics.WCImage;
import javafx.application.Application;
import javafx.scene.Cursor;
import javafx.scene.ImageCursor;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import java.util.*;
public class CursorManagerImpl2 extends CursorManager<javafx.scene.Cursor> {
private final Map<String, javafx.scene.Cursor> map = new HashMap();
private ResourceBundle bundle;
private javafx.scene.Cursor defaultCursor = javafx.scene.Cursor.DEFAULT;
public CursorManagerImpl2() {}
public CursorManagerImpl2(javafx.scene.Cursor defaultCursor) {
this.defaultCursor = defaultCursor;
}
public javafx.scene.Cursor getDefaultCursor() {
return defaultCursor;
}
public void setDefaultCursor(javafx.scene.Cursor cursor) {
defaultCursor = cursor;
}
@Override
protected javafx.scene.Cursor getCustomCursor(WCImage image, int hotspotX, int hotspotY) {
return new ImageCursor(
com.sun.javafx.tk.Toolkit.getImageAccessor()
.fromPlatformImage(WCGraphicsManager.getGraphicsManager().toPlatformImage(image)),
hotspotX,
hotspotY);
}
@Override
protected javafx.scene.Cursor getPredefinedCursor(int type) {
switch (type) {
case 0:
default: return defaultCursor; // line changed
case 1: return javafx.scene.Cursor.CROSSHAIR;
case 2: return javafx.scene.Cursor.HAND;
case 3: return javafx.scene.Cursor.MOVE;
case 4: return javafx.scene.Cursor.TEXT;
case 5: return javafx.scene.Cursor.WAIT;
case 6: return this.getCustomCursor("help", javafx.scene.Cursor.DEFAULT);
case 7: return javafx.scene.Cursor.E_RESIZE;
case 8: return javafx.scene.Cursor.N_RESIZE;
case 9: return javafx.scene.Cursor.NE_RESIZE;
case 10: return javafx.scene.Cursor.NW_RESIZE;
case 11: return javafx.scene.Cursor.S_RESIZE;
case 12: return javafx.scene.Cursor.SE_RESIZE;
case 13: return javafx.scene.Cursor.SW_RESIZE;
case 14: return javafx.scene.Cursor.W_RESIZE;
case 15: return javafx.scene.Cursor.V_RESIZE;
case 16: return javafx.scene.Cursor.H_RESIZE;
case 17: return this.getCustomCursor("resize.nesw", javafx.scene.Cursor.DEFAULT);
case 18: return this.getCustomCursor("resize.nwse", javafx.scene.Cursor.DEFAULT);
case 19: return this.getCustomCursor("resize.column", javafx.scene.Cursor.H_RESIZE);
case 20: return this.getCustomCursor("resize.row", javafx.scene.Cursor.V_RESIZE);
case 21: return this.getCustomCursor("panning.middle", javafx.scene.Cursor.DEFAULT);
case 22: return this.getCustomCursor("panning.east", javafx.scene.Cursor.DEFAULT);
case 23: return this.getCustomCursor("panning.north", javafx.scene.Cursor.DEFAULT);
case 24: return this.getCustomCursor("panning.ne", javafx.scene.Cursor.DEFAULT);
case 25: return this.getCustomCursor("panning.nw", javafx.scene.Cursor.DEFAULT);
case 26: return this.getCustomCursor("panning.south", javafx.scene.Cursor.DEFAULT);
case 27: return this.getCustomCursor("panning.se", javafx.scene.Cursor.DEFAULT);
case 28: return this.getCustomCursor("panning.sw", javafx.scene.Cursor.DEFAULT);
case 29: return this.getCustomCursor("panning.west", javafx.scene.Cursor.DEFAULT);
case 30: return this.getCustomCursor("vertical.text", javafx.scene.Cursor.DEFAULT);
case 31: return this.getCustomCursor("cell", javafx.scene.Cursor.DEFAULT);
case 32: return this.getCustomCursor("context.menu", javafx.scene.Cursor.DEFAULT);
case 33: return this.getCustomCursor("no.drop", javafx.scene.Cursor.DEFAULT);
case 34: return this.getCustomCursor("not.allowed", javafx.scene.Cursor.DEFAULT);
case 35: return this.getCustomCursor("progress", javafx.scene.Cursor.WAIT);
case 36: return this.getCustomCursor("alias", javafx.scene.Cursor.DEFAULT);
case 37: return this.getCustomCursor("zoom.in", javafx.scene.Cursor.DEFAULT);
case 38: return this.getCustomCursor("zoom.out", javafx.scene.Cursor.DEFAULT);
case 39: return this.getCustomCursor("copy", javafx.scene.Cursor.DEFAULT);
case 40: return javafx.scene.Cursor.NONE;
case 41: return this.getCustomCursor("grab", javafx.scene.Cursor.OPEN_HAND);
case 42: return this.getCustomCursor("grabbing", javafx.scene.Cursor.CLOSED_HAND);
}
}
private javafx.scene.Cursor getCustomCursor(String cursorId, javafx.scene.Cursor defaultCursor) {
javafx.scene.Cursor customCursor = this.map.get(cursorId);
if (customCursor == null) {
try {
if (this.bundle == null) {
this.bundle =
ResourceBundle.getBundle("com.sun.javafx.webkit.Cursors", Locale.getDefault());
}
if (this.bundle != null) {
String fileName = this.bundle.getString(cursorId + ".file");
javafx.scene.image.Image image =
new Image(com.sun.javafx.webkit.CursorManagerImpl.class.getResourceAsStream(fileName));
fileName = this.bundle.getString(cursorId + ".hotspotX");
int hotspotX = Integer.parseInt(fileName);
fileName = this.bundle.getString(cursorId + ".hotspotY");
int hotspotY = Integer.parseInt(fileName);
customCursor = new ImageCursor(image, hotspotX, hotspotY);
}
} catch (MissingResourceException e) {
}
if (customCursor == null) {
customCursor = defaultCursor;
}
this.map.put(cursorId, customCursor);
}
return customCursor;
}
}
You can then replace the manager with
CursorManager.setCursorManager(new CursorManagerImpl2(javafx.scene.Cursor.CROSSHAIR));
To change the default cursor, you can use
((CursorManagerImpl2) CursorManager.getCursorManager()).setDefaultCursor(javafx.scene.Cursor.MOVE);
Note that you might have to add the com.sun
packages to your gradle:
compileJava {
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'])
}
run {
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']
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论