我想问一个小问题。事实上,我想自定义当我们在文本区域或文本字段中右键单击时出现的菜单。我的目标是通过添加我想要的按钮来保持基本菜单(复制、粘贴、剪切…(。
我发现这篇文章解释了如何做到这一点:JavaFX附加到TextField 的右键菜单
import com.sun.javafx.scene.control.skin.TextFieldSkin;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
public class GiveMeContext extends Application {
@Override
public void start(final Stage stage) throws Exception {
TextField textField = new TextField();
TextFieldSkin customContextSkin = new TextFieldSkin(textField) {
@Override
public void populateContextMenu(ContextMenu contextMenu) {
super.populateContextMenu(contextMenu);
contextMenu.getItems().add(0, new SeparatorMenuItem());
contextMenu.getItems().add(0, new MenuItem("Register"));
}
};
textField.setSkin(customContextSkin);
stage.setScene(new Scene(textField));
stage.show();
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
经过尝试,它在java8中运行得非常好,但正如他们当时所说的那样,在java9之后,它就不再运行了。
我试图替换有问题的方法(populateContextMenu(,但不幸的是,我找不到任何方法。
如果有人教我如何使用java9+,我将非常感谢
由于模块化,您的代码无法在JavaFX9+中工作。有关详细信息,请阅读本文。您唯一能做的就是使用上下文菜单并用您自己的值填充它。下面是在JavaFX17中执行此操作的完整示例。
步骤1。创建新项目。
Pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>mavenproject1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.9.0</version>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>17.0.2-ea+2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>17.0.2-ea+2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>17.0.2-ea+2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>17.0.2-ea+2</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
模块信息:
module Mavenproject1 {
requires javafx.controls;
requires javafx.base;
requires javafx.fxml;
requires javafx.graphics;
opens com.mycompany;
}
主要类别:
package com.mycompany;
import javafx.scene.control.skin.TextFieldSkin;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
public class NewMain2 extends Application {
@Override
public void start(final Stage stage) throws Exception {
TextField textField = new TextField();
ContextMenu contextMenu = new ContextMenu();
MenuItem menuItem1 = new MenuItem("Choice 1");
MenuItem menuItem2 = new MenuItem("Choice 2");
MenuItem menuItem3 = new MenuItem("Choice 3");
contextMenu.getItems().addAll(menuItem1, menuItem2, menuItem3);
textField.setContextMenu(contextMenu);
stage.setScene(new Scene(textField));
stage.show();
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
步骤2。构建您的项目。
步骤3。从这里下载JavaFX SDK。
步骤4以这种方式运行您的项目
java --module-path ./mavenproject1-1.0-SNAPSHOT.jar:/opt/javafx-sdk-17.0.2/lib --add-modules=javafx.controls,javafx.fxml -m Mavenproject1/com.mycompany.NewMain2
经过长时间的编程,我找到了一种方法"延伸";TextInputControl的默认上下文菜单。我必须从头开始重建它,但它并不像看上去那么复杂。
我的代码:
import java.util.Collection;
import java.util.ResourceBundle;
import java.util.function.Consumer;
import org.apache.commons.lang3.StringUtils;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.IndexRange;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.TextInputControl;
public interface JFXTextUtils {
static void initializeContextMenu(TextInputControl textField) {
final MenuItem undoMI = new ContextMenuItem("Undo", textField, TextInputControl::undo);
final MenuItem redoMI = new ContextMenuItem("Redo", textField, TextInputControl::redo);
final MenuItem cutMI = new ContextMenuItem("Cut", textField, TextInputControl::cut);
final MenuItem copyMI = new ContextMenuItem("Copy", textField, TextInputControl::copy);
final MenuItem pasteMI = new ContextMenuItem("Paste", textField, TextInputControl::paste);
final MenuItem selectAllMI = new ContextMenuItem("SelectAll", textField, TextInputControl::selectAll);
final MenuItem deleteMI = new ContextMenuItem("DeleteSelection", textField, JFXTextUtils::deleteSelectedText);
textField.undoableProperty().addListener((obs, oldValue, newValue) -> undoMI.setDisable(!newValue));
textField.redoableProperty().addListener((obs, oldValue, newValue) -> redoMI.setDisable(!newValue));
textField.selectionProperty().addListener((obs, oldValue, newValue) -> {
cutMI.setDisable(newValue.getLength() == 0);
copyMI.setDisable(newValue.getLength() == 0);
deleteMI.setDisable(newValue.getLength() == 0);
selectAllMI.setDisable(newValue.getLength() == newValue.getEnd());
});
undoMI.setDisable(true);
redoMI.setDisable(true);
cutMI.setDisable(true);
copyMI.setDisable(true);
deleteMI.setDisable(true);
selectAllMI.setDisable(true);
textField.setContextMenu(ContextMenu(undoMI, redoMI, cutMI, copyMI, pasteMI, deleteMI, new SeparatorMenuItem(), selectAllMI,
new SeparatorMenuItem()));
}
static void deleteSelectedText(TextInputControl t) {
IndexRange range = t.getSelection();
if (range.getLength() == 0) {
return;
}
String text = t.getText();
String newText = text.substring(0, range.getStart()) + text.substring(range.getEnd());
t.setText(newText);
t.positionCaret(range.getStart());
}
class ContextMenuItem extends MenuItem {
ContextMenuItem(final String action, TextInputControl textField, Consumer<TextInputControl> function) {
super(ResourceBundle.getBundle("com/sun/javafx/scene/control/skin/resources/controls")
.getString("TextInputControl.menu." + action));
setOnAction(e -> function.accept(textField));
}
}
}
这段代码完全重新创建了默认的上下文菜单,并准备在最后一个MenuSeparator之后接受更多MenuItem。