text - 如何在 javafx 2.2 中创建可编辑标签

标签 text javafx controls

我希望在我正在书写的 Pane 上的任意位置创建一个可编辑的标签。我的印象是 TextField 或 TextArea 对象是我可以用来实现该功能的。显然还有更多,因为我不知道在创建对象时如何定位对象。我在“Chaotic Java”网站上找到了一个例子,但我需要做更多的工作来了解那里发生了什么。 http://chaoticjava.com/posts/another-javafx-example-the-editable-label/

我正在寻找来自这个小组的更多意见。

(没有错误,因为我没有写任何代码。)

最佳答案

我对如何实现这一点有点好奇,所以我试了一下。这就是我想出的。

lonely

使用的方法与 James 在他的评论中建议的方法非常相似:

I would start with a Pane, . . ., TextFields to represent text while being edited. Register mouse listeners with the Pane and Text objects, and use the layoutX and layoutY properties to position things . . . just to use text fields, and to use CSS to make them look like labels when not focused and text fields when focused.



唯一非常棘手的部分是确定如何正确调整文本字段的大小,因为文本字段内的文本不会通过公共(public) API 公开以允许您收听它的布局边界。您也许可以使用 css 查找函数来获取包含的文本,但我选择使用私有(private) sun FontMetrics API(将来可能会弃用)来获取文本的大小。在 Java 9 的 future ,您应该能够在不使用私有(private) API 的情况下执行任务。

该解决方案不会尝试做任何棘手的事情,例如处理多格式或多行文本,它只是针对可以放置在场景中的几个单词的简短单行注释。

文本创建者.java
// ## CAUTION: beware the com.sun imports...
import com.sun.javafx.tk.FontMetrics;
import com.sun.javafx.tk.Toolkit;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * Displays a map of the lonely mountain upon which draggable, editable labels can be overlaid.
 */
public class TextCreator extends Application {
    private static final String MAP_IMAGE_LOC =
            "http://images.wikia.com/lotr/images/archive/f/f6/20130209175313!F27c_thorins_map_from_the_hobbit.jpg";

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

    @Override
    public void start(final Stage stage) throws Exception {
        Pane pane = new Pane();

        pane.setOnMouseClicked(event -> {
            if (event.getTarget() == pane) {
                pane.getChildren().add(
                        new EditableDraggableText(event.getX(), event.getY())
                );
            }
        });

        EditableDraggableText cssStyled = 
                new EditableDraggableText(439, 253, "Style them with CSS");
        cssStyled.getStyleClass().add("highlighted");

        pane.getChildren().addAll(
                new EditableDraggableText(330, 101, "Click to add a label"),
                new EditableDraggableText(318, 225, "You can edit your labels"),
                cssStyled,
                new EditableDraggableText(336, 307, "And drag them"),
                new EditableDraggableText(309, 346, "Around The Lonely Mountain")
        );

        StackPane layout = new StackPane(
            new ImageView(
                    new Image(
                            MAP_IMAGE_LOC
                    )
            ),
            pane
        );

        Scene scene = new Scene(layout);
        scene.getStylesheets().add(getClass().getResource(
            "editable-text.css"
        ).toExternalForm());

        stage.setScene(scene);
        stage.setResizable(false);
        stage.show();
    }

    /**
     * A text field which has no special decorations like background, border or focus ring.
     *   i.e. the EditableText just looks like a vanilla Text node or a Label node.
     */
    class EditableText extends TextField {
        // The right margin allows a little bit of space
        // to the right of the text for the editor caret.
        private final double RIGHT_MARGIN = 5;

        EditableText(double x, double y) {
            relocate(x, y);
            getStyleClass().add("editable-text");

            //** CAUTION: this uses a non-public API (FontMetrics) to calculate the field size
            //            the non-public API may be removed in a future JavaFX version.
            // see: https://bugs.openjdk.java.net/browse/JDK-8090775
            //      Need font/text measurement API
            FontMetrics metrics = Toolkit.getToolkit().getFontLoader().getFontMetrics(getFont());
            setPrefWidth(RIGHT_MARGIN);
            textProperty().addListener((observable, oldTextString, newTextString) ->
                setPrefWidth(metrics.computeStringWidth(newTextString) + RIGHT_MARGIN)
            );

            Platform.runLater(this::requestFocus);
        }
    }

    /**
     * An EditableText (a text field which looks like a label), which can be dragged around
     * the screen to reposition it.
     */
    class EditableDraggableText extends StackPane {
        private final double PADDING = 5;
        private EditableText text = new EditableText(PADDING, PADDING);

        EditableDraggableText(double x, double y) {
            relocate(x - PADDING, y - PADDING);
            getChildren().add(text);
            getStyleClass().add("editable-draggable-text");

            // if the text is empty when we lose focus,
            // the node has no purpose anymore
            // just remove it from the scene.
            text.focusedProperty().addListener((observable, hadFocus, hasFocus) -> {
                if (!hasFocus && getParent() != null && getParent() instanceof Pane &&
                    (text.getText() == null || text.getText().trim().isEmpty())) {
                    ((Pane) getParent()).getChildren().remove(this);
                }
            });

            enableDrag();
        }

        public EditableDraggableText(int x, int y, String text) {
            this(x, y);
            this.text.setText(text);
        }

        // make a node movable by dragging it around with the mouse.
        private void enableDrag() {
            final Delta dragDelta = new Delta();
            setOnMousePressed(mouseEvent -> {
                this.toFront();
                // record a delta distance for the drag and drop operation.
                dragDelta.x = mouseEvent.getX();
                dragDelta.y = mouseEvent.getY();
                getScene().setCursor(Cursor.MOVE);
            });
            setOnMouseReleased(mouseEvent -> getScene().setCursor(Cursor.HAND));
            setOnMouseDragged(mouseEvent -> {
                double newX = getLayoutX() + mouseEvent.getX() - dragDelta.x;
                if (newX > 0 && newX < getScene().getWidth()) {
                    setLayoutX(newX);
                }
                double newY = getLayoutY() + mouseEvent.getY() - dragDelta.y;
                if (newY > 0 && newY < getScene().getHeight()) {
                    setLayoutY(newY);
                }
            });
            setOnMouseEntered(mouseEvent -> {
                if (!mouseEvent.isPrimaryButtonDown()) {
                    getScene().setCursor(Cursor.HAND);
                }
            });
            setOnMouseExited(mouseEvent -> {
                if (!mouseEvent.isPrimaryButtonDown()) {
                    getScene().setCursor(Cursor.DEFAULT);
                }
            });
        }

        // records relative x and y co-ordinates.
        private class Delta {
            double x, y;
        }
    }    
}

可编辑-text.css
.editable-text {
    -fx-background-color: transparent;
    -fx-background-insets: 0;
    -fx-background-radius: 0;
    -fx-padding: 0;
}

.editable-draggable-text:hover .editable-text {
    -fx-background-color: yellow;
}

.editable-draggable-text {
    -fx-padding: 5;
    -fx-background-color: rgba(152, 251, 152, 0.2); // translucent palegreen
}

.editable-draggable-text:hover {
    -fx-background-color: orange;
}

.highlighted {
    -fx-background-color: rgba(255, 182, 93, 0.3);  // translucent mistyrose
    -fx-border-style: dashed;
    -fx-border-color: firebrick;
}

如果您有时间,您可以清理示例实现并将其捐赠给 ControlsFX项目。

关于text - 如何在 javafx 2.2 中创建可编辑标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25572398/

相关文章:

Java - 将值从 TextField 添加到另一个类的对象构造函数

java - 使用字符串的控制流结构的问题

html - svg 文本的颜色属性不起作用

python - 将 PDF 转换为文本 : remove word breaks

xaml - 如何在 UWP 中对 TextBlock 的比例进行动画处理

java - 正则表达式将引用与最小字数匹配

animation - 更新JavaFx中的应用程序线程以绘制节点

java - Linux Mint Java 和 JavaFX

C# 刷新动态标签上的值

git - "unknown revision or path not in the working tree"尝试获取特定提交到新目录时