如何在 JavaFX 中实现节点的选择 [英] How to implement selection of Nodes in JavaFX

查看:26
本文介绍了如何在 JavaFX 中实现节点的选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 JavaFX 新手,昨天开始学习.花了一整天的时间阅读文档,但什么也没学到……

这就是我想要做的,制作一个简单的 JavaFX 应用程序来创建一个圆圈.单击时,其笔划变为橙色(某些颜色).在未单击(单击该圆圈以外的任何内容)时,笔划变为(某种颜色)白色.

这是我目前的伪代码.我想创建一个单独的类来创建一个圆圈并处理事件(重要).

public class something extends Application {@覆盖公共无效开始(阶段primaryStage){MyCircle c1 = new MyCircle();c1.setCircle(20, 0, 0);TilePane root = new TilePane();root.getChildren().add(c1.getCircle());//某种鼠标事件监听器,不确定应该是哪个c1.getCircle().addEventListener();//伪代码场景场景 = 新场景(root, 400, 400);primaryStage.setTitle("圆");primaryStage.setScene(场景);primaryStage.show();}公共静态无效主(字符串 [] args){发射(参数);}}

该类应该创建一个圆并处理所有事件,例如鼠标单击、鼠标位置、单击和拖动等.

公共类 MyCircle 实现了 EventHandler{Circle circle = new Circle();public void setCircle(int 半径,int x,int y){circle.setRadius(半径);位置(x,y);circle.setStrokeWidth(3);circle.setStroke(Color.valueOf("white"));}公共圈getCircle(){回圈;}公共无效位置(int x,int y){circle.setTranslateX(x);circle.setTranslateY(y);}公共无效选择(){circle.setStroke(Color.valueOf("orange"));}公共无效未选择(){circle.setStroke(Color.valueOf("white"));}@覆盖公共无效句柄(事件事件){if (event == MOUSE_CLICKED){//伪代码选择();}else if(event == MOUSE_UNCLICKED){//伪代码未选中();}}}

由于我对 JavaFX 非常陌生,我也非常感谢您的解释.谢谢!

<小时>

这是我的伪代码,我想将其转换为实际的工作代码.我不知道我会怎么做.任何帮助将不胜感激.

<小时>

另一个除了 3 个标记的地方外,一切都是代码.请在代码中查找我的评论Psuedo Code,在那里我需要帮助将伪代码更改为实际代码.

解决方案

处理节点的选择状态需要一些节点内不可用的知识.您将需要知道鼠标事件是否发生在其他地方(例如其他节点或根窗格),因此您可能必须向其传递有问题的参数.

一般来说,将鼠标事件处理委托给 MyCircle 并不是一个好主意.相反,最好在该类中指定选择行为,并将选择处理委托给具有足够知识来处理问题的单独帮助类.我创建了这个

I am very new JavaFX, started learning it yesterday. Spent the whole day reading through the documentation, but learned nothing...

Here is what I want to do, make a simple JavaFX application that creates a circle. On click its stroke turns orange (some color). On unlicked (click on anything other than that circle), the stroke turns (some color) white.

Here is my pseudo code what I have so far. I want to make a separate class that creates a circle and handle the events (important).

public class Something extends Application {

    @Override
    public void start(Stage primaryStage) {
        MyCircle c1 = new MyCircle();
        c1.setCircle(20, 0, 0);

        TilePane root = new TilePane();
        root.getChildren().add(c1.getCircle());
        //Some kind of mouse event listener, not sure which one should be
        c1.getCircle().addEventListener(); //pseudo code

        Scene scene = new Scene(root, 400, 400);

        primaryStage.setTitle("Circle");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

}

This the class that should create a circle and handle all the events, such as, mouse click, mouse location, click and drag and stuff like that.

public class MyCircle implements EventHandler{
    Circle circle = new Circle();

    public void setCircle(int radius, int x, int y){
        circle.setRadius(radius);
        position(x,y);
        circle.setStrokeWidth(3);
        circle.setStroke(Color.valueOf("white"));
    }

    public Circle getCircle(){
        return circle;
    }

    public void position(int x, int y){
        circle.setTranslateX(x);
        circle.setTranslateY(y);
    }

    public void selected(){
        circle.setStroke(Color.valueOf("orange"));
    }

    public void unselected() {
        circle.setStroke(Color.valueOf("white"));
    }

    @Override
    public void handle(Event event) {
        if (event == MOUSE_CLICKED){ //pseudo code
            selected();
        }
        else if(event == MOUSE_UNCLICKED){ //pseudo code
            unselected();
        }
    }
}

Since I am very new to JavaFX, I'd much appreciate explanation as well. Thanks!


EDIT: This is my pseudo code, and I want to convert it into an actual working code. I am not sure how would I do that. Any help would be appreciated.


ANOTHER EDIT: Everything is a code except 3 marked places. Please look for my comment Psuedo Code within the code, where I need help to change the pseudo code into an actual code.

解决方案

Handling selection status of a Node requires some knowledge not available within the Node. You'll going to need to know whether the mouse event happened somewhere else (e.g. other Nodes or the root Pane), so you may have to pass questionable arguments to it.

In general, it's not a good idea to delegate mouse event handling to MyCircle. Instead it's better to specify the selection behavior in that class and delegate selection handling to a separate helper class which has enough knowledge to handle the problem. I created this gist to show how this task can be done.

public class SelectionDemo extends Application {
    @Override
    public void start(Stage primaryStage) {
        Scene scene = new Scene(createPane(), 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private Parent createPane() {
        BorderPane root = new BorderPane();
        SelectionHandler selectionHandler = new SelectionHandler(root);
        root.addEventHandler(MouseEvent.MOUSE_PRESSED, selectionHandler.getMousePressedEventHandler());

        MyCircle c1 = new MyCircle(40, 40, 20);
        MyCircle c2 = new MyCircle(40, 100, 20);
        MyCircle c3 = new MyCircle(40, 160, 20);
        root.getChildren().addAll(c1, c2, c3);

        return root;
    }

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

I borrowed and modified an interface from jfxtras-labs to represent a selectable Node. It's good to have this interface to differentiate between selectable nodes and unselectable ones:

/**
 * This interface is based on jfxtras-labs <a href="https://github.com/JFXtras/jfxtras-labs/blob/8.0/src/main/java/jfxtras/labs/scene/control/window/SelectableNode.java">SelectableNode</a>
 */
public interface SelectableNode {
    public boolean requestSelection(boolean select);

    public void notifySelection(boolean select);
}

classes who wish to be selectable must implement this interface and specify their selection behavior in implementation of notifySelection method:

public class MyCircle extends Circle implements SelectableNode {
    public MyCircle(double centerX, double centerY, double radius) {
        super(centerX, centerY, radius);
    }

    @Override
    public boolean requestSelection(boolean select) {
        return true;
    }

    @Override
    public void notifySelection(boolean select) {
        if(select)
            this.setFill(Color.RED);
        else
            this.setFill(Color.BLACK);
    }
}

And finally the selection handler class:

public class SelectionHandler {
    private Clipboard clipboard;

    private EventHandler<MouseEvent> mousePressedEventHandler;

    public SelectionHandler(final Parent root) {
        this.clipboard = new Clipboard();
        this.mousePressedEventHandler = new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                SelectionHandler.this.doOnMousePressed(root, event);
                event.consume();
            }
        };
    }

    public EventHandler<MouseEvent> getMousePressedEventHandler() {
        return mousePressedEventHandler;
    }

    private void doOnMousePressed(Parent root, MouseEvent event) {
        Node target = (Node) event.getTarget();
        if(target.equals(root))
            clipboard.unselectAll();
        if(root.getChildrenUnmodifiable().contains(target) && target instanceof SelectableNode) {
            SelectableNode selectableTarget = (SelectableNode) target;
            if(!clipboard.getSelectedItems().contains(selectableTarget))
                clipboard.unselectAll();
            clipboard.select(selectableTarget, true);
        }
    }

    /**
     * This class is based on jfxtras-labs
     *  <a href="https://github.com/JFXtras/jfxtras-labs/blob/8.0/src/main/java/jfxtras/labs/scene/control/window/Clipboard.java">Clipboard</a>
     *  and 
     *  <a href="https://github.com/JFXtras/jfxtras-labs/blob/8.0/src/main/java/jfxtras/labs/util/WindowUtil.java">WindowUtil</a>
     */
    private class Clipboard {
        private ObservableList<SelectableNode> selectedItems = FXCollections.observableArrayList();

        public ObservableList<SelectableNode> getSelectedItems() {
            return selectedItems;
        }

        public boolean select(SelectableNode n, boolean selected) {
            if(n.requestSelection(selected)) {
                if (selected) {
                    selectedItems.add(n);
                } else {
                    selectedItems.remove(n);
                }
                n.notifySelection(selected);
                return true;
            } else {
                return false;
            }
        }

        public void unselectAll() {
            List<SelectableNode> unselectList = new ArrayList<>();
            unselectList.addAll(selectedItems);

            for (SelectableNode sN : unselectList) {
                select(sN, false);
            }
        }
    }
}

这篇关于如何在 JavaFX 中实现节点的选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆