使用 javafx 按下某个键时,从文本区域的特定行编辑文本?

Edit text from a specific line at text area when a key is pressed using javafx?

所以我正在使用 java、javaFx 构建文本编辑器,我必须在 (Editor VBox) 中打开一个文件并将这些行放入双链表中,然后编辑、删除、覆盖一行等。我在编辑器 VBox 中创建了一个名为 textAr 的文本区域,但是我在从 textAr 到达特定行中的文本时遇到问题,因此我可以编辑或插入文本双链表和新文本应该插入的位置,我必须使用 (I) 来插入所以我不能使用 getSelectedText()..,这是用户界面所需的图片..

这是我在按下键盘时尝试插入文本的方法,我从 textAr(编辑器 VBox 中的文本区域)中输入 getText,但它占用了该区域中的整个文本,不在特定的行或位置..除了当我在键盘上按 (I) 时崩溃并且黑屏出现在 java 应用程序

您可以看看这段代码,看看是否有帮助。

它并不是为了成为一个真正可用、功能齐全的文本编辑器而设计的,只是为了实现您问题中概述的主要功能。

此外,如果设计与提供的不符,我会采取不同的做法,例如不再使用编辑命令手动开始编辑行,而是在更改选择时自动开始编辑所选行。

提供的代码没有使用自定义链表结构,它只是使用数组列表。

要在编辑器中启动操作,需要结合要执行的命令使用系统特定的快捷键。如果需要,请参阅 KeyCombination 文档以获取更多信息。

如果您希望修改代码以使用自定义列表实现:

  1. 让您的自定义链表结构实现 List 接口。

  2. 将自定义列表的实例传递给 FXCollections 以将其包装在 UI 可以使用的可观察列表中:FXCollections.observableList(yourDoubleLinkedList)

    • 这样做而不是我通过 FXCollections.observableArrayList().
    • 使用 ArrayList 的地方

我不会就使用自定义列表调整实现提供任何进一步的帮助,如果您在这方面有困难,这些困难将由您来解决。

import javafx.application.*;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.*;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.*;
import javafx.stage.*;

import java.io.*;
import java.nio.file.*;
import java.util.Map;

public class LineEditor extends Application {
    private Document document;

    @Override
    public void init() throws Exception {
        Path path = Path.of(getParameters().getRaw().get(0));
        document = new Document(
                path.getFileName().toString(),
                FXCollections.observableArrayList(
                        Files.readAllLines(path)
                )
        );
    }

    @Override
    public void start(Stage stage) throws IOException {
        Editor editor = new Editor(document);
        Scene scene = new Scene(editor.getUI());
        stage.setScene(scene);

        scene.getAccelerators().putAll(
                Map.of(
                        KeyCombination.valueOf("SHORTCUT+I"),
                        editor::insert,
                        KeyCombination.valueOf("SHORTCUT+O"),
                        editor::overwrite,
                        KeyCombination.valueOf("SHORTCUT+D"),
                        editor::delete,
                        KeyCombination.valueOf("SHORTCUT+E"),
                        editor::edit,
                        KeyCombination.valueOf("SHORTCUT+C"),
                        editor::changeTitle,
                        KeyCombination.valueOf("SHORTCUT+S"),
                        () -> editor.save(scene.getWindow()),
                        KeyCombination.valueOf("SHORTCUT+Q"),
                        editor::quit
                )
        );

        stage.titleProperty().bind(
                Bindings.concat("Editing: ", document.titleProperty())
        );

        stage.show();
    }

    public static void main(String[] args) throws IOException {
        if (args.length == 0) {
            Path dirPath = Files.createTempDirectory(TEMP_DIR_PREFIX);
            Path filePath = dirPath.resolve(DEFAULT_TITLE);
            Files.writeString(filePath, DEFAULT_TEXT);
            args = new String[]{filePath.toString()};
        } else {
            if (!Files.isReadable(Path.of(args[0]))) {
                System.out.println("File " + args[0] + " is not readable.");
                System.exit(1);
            }
        }

        launch(args);
    }

    private static final String TEMP_DIR_PREFIX = "line-editor";
    private static final String TEXT_EXTENSION = "txt";
    private static final String DEFAULT_TITLE = "sonnet-148." + TEXT_EXTENSION;
    private static final String DEFAULT_TEXT = """
            O me, what eyes hath Love put in my head,
            Which have no correspondence with true sight!
            Or, if they have, where is my judgment fled,
            That censures falsely what they see aright?
            If that be fair whereon my false eyes dote,
            What means the world to say it is not so?
            If it be not, then love doth well denote
            Love's eye is not so true as all men's 'No.'
            How can it? O, how can Love's eye be true,
            That is so vex'd with watching and with tears?
            No marvel then, though I mistake my view;
            The sun itself sees not till heaven clears.
               O cunning Love! with tears thou keep'st me blind,
               Lest eyes well-seeing thy foul faults should find.
            """;
}

class Document {
    private final SimpleStringProperty title;
    private final ObservableList<String> lines;

    public Document(String title, ObservableList<String> lines) {
        this.title = new SimpleStringProperty(title);
        this.lines = lines;
    }

    public SimpleStringProperty titleProperty() {
        return title;
    }

    public ObservableList<String> getLines() {
        return lines;
    }
}

class Editor {
    private final Pane layout;
    private final ListView<String> display;
    private final TextArea input;
    private final Document document;
    
    private final static String INSTRUCTION_TEXT = """
            Shortcut
              + Key   Command
                I     Insert
                O     Overwrite
                D     Delete
                E     Edit
                C     Change Title
                S     Save
                Q     Quit
            """;

    private final static String UNTITLED_DOCUMENT_TITLE = "Untitled.txt";

    public Editor(Document document) {
        this.document =
                (document != null)
                    ? document
                    : new Document(
                            UNTITLED_DOCUMENT_TITLE,
                            FXCollections.observableArrayList()
                    );

        assert document != null;
        display = new ListView<>(document.getLines());
        display.setPrefSize(350, 300);
        input = new TextArea();

        Label instructions = new Label(INSTRUCTION_TEXT);
        instructions.setStyle("-fx-font-family: monospace;");

        HBox displayWithInstructions = new HBox(10,
                instructions,
                display
        );

        SplitPane splitPane = new SplitPane(
                displayWithInstructions,
                input
        );
        splitPane.setOrientation(Orientation.VERTICAL);
        splitPane.setDividerPositions(.8);

        layout = new StackPane(splitPane);
        layout.setPadding(new Insets(10));
    }

    public Pane getUI() {
        return layout;
    }

    public void insert() {
        int selectedIndex = display.getSelectionModel().getSelectedIndex();
        document.getLines().add(selectedIndex + 1, input.getText());
    }

    public void overwrite() {
        int selectedIndex = display.getSelectionModel().getSelectedIndex();
        if (selectedIndex != -1) {
            document.getLines().set(selectedIndex, input.getText());
        }
    }

    public void delete() {
        int selectedIndex = display.getSelectionModel().getSelectedIndex();
        if (selectedIndex != -1) {
            document.getLines().remove(selectedIndex);
        }
    }

    public void edit() {
        int selectedIndex = display.getSelectionModel().getSelectedIndex();
        if (selectedIndex != -1) {
            input.setText(document.getLines().get(selectedIndex));
        }
    }

    public void changeTitle() {
        TextInputDialog titleDialog = new TextInputDialog(document.titleProperty().get());
        titleDialog.setTitle("Set Title");
        titleDialog.showAndWait()
                .ifPresent(result -> document.titleProperty().set(result));
    }

    public void save(Window owner) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().setAll(
                new FileChooser.ExtensionFilter("Text Files", "txt")
        );
        fileChooser.setTitle("Save Document");
        fileChooser.setInitialFileName(document.titleProperty().get());

        File saveFile = fileChooser.showSaveDialog(owner);

        if (saveFile != null && Files.isWritable(saveFile.toPath())) {
            document.titleProperty().set(saveFile.getName());

            try {
                Files.writeString(
                        saveFile.toPath(),
                        String.join("\n", document.getLines())
                );
            } catch (IOException e) {
                e.printStackTrace();

                Alert alert = new Alert(
                        Alert.AlertType.ERROR,
                        "Unable to save " + document.titleProperty().get()
                );
                alert.initOwner(owner);
                alert.showAndWait();
            }
        }
    }

    public void quit() {
        Platform.exit();
    }
}