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

Gar*_*hes 4 controls text javafx

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

我正在寻找这个小组的更多意见.

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

jew*_*sea 5

我对如何实现这一点感到好奇,所以我试了一下.这就是我提出的.

孤独

使用的方法与James在评论中提出的方法非常相似:

我会从Pane开始...,TextFields在编辑时表示文本.使用Pane和Text对象注册鼠标侦听器,并使用layoutX和layoutY属性来定位事物...只是为了使用文本字段,并使用CSS使它们在没有聚焦时看起来像标签,在聚焦时看起来像文本字段.

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

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

TextCreator.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;
        }
    }    
}
Run Code Online (Sandbox Code Playgroud)

编辑-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;
}
Run Code Online (Sandbox Code Playgroud)

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