JavaFx自动将侦听器添加到动态添加的项目中

时间:2014-11-13 04:00:57

标签: java events javafx event-listener

在jquery中,有on功能会自动将事件绑定到以后添加的项目(例如ajax调用),它看起来像这样:

$(document).on("click", ".my-class", function(){
    // Do my event task here
});

现在每次将具有班级my-class的项目添加到自动附加事件的dom中。

JavaJavaFx中有类似的内容吗?我想将我的事件保存在我的控制器中,并且在我喜欢用我正在处理的代码调用Helper Classes时使用其他方法我不知道如何实现这一点。

所以我在控制器中有这个:

Tree tree = new Tree(currentMysqlConn);
tree.addDatabases(treeItem);

然后创建TreeItem然后创建子项,并且这些子项在单击时具有事件。这是一个例子:

TreeItem<String> tableNode = new TreeItem<>("Tables", tableIcon);
tableNode.expandedProperty().addListener(new ChangeListener(){

    @Override
    public void changed(ObservableValue observable, Object oldValue, Object newValue){
        if((boolean) newValue){
            TableActions ta = new TableActions(tableNode);
            ta.getTables(conn);
        }
    }
});

问题是,我在Helper Class中有这个问题,那么我可以做些什么来将其移植到我的控制器中?因为那是在一个循环中。

2 个答案:

答案 0 :(得分:3)

您可以使用任何可观察列表(例如,从TreeItem.getChildren()Parent.getChildren()获得的列表)注册侦听器,并递归地让该侦听器向添加到列表中的任何子项注册相同的侦听器。

以下示例更新显示树视图中节点总数的标签。为此,我们需要知道何时将子节点添加到任何节点,因此我们需要与动态添加的节点关联的侦听器。您的用例可能略有不同,但如果您了解其工作原理,您应该能够实现所需。请注意,虽然我在这里没有任何其他类,但如果UI的内容从任何地方更改,控制器将通过听众适当地通知。

CountingTreeViewController.java:

import java.util.concurrent.atomic.AtomicInteger;

import javafx.beans.binding.Bindings;
import javafx.beans.binding.IntegerBinding;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;


public class CountingTreeViewController {
    @FXML
    private TextField itemTextField ;
    @FXML
    private TreeView<String> tree ;
    @FXML
    private Label countLabel ;

    // binding that contains the total count of all nodes
    // the computeValue() method recursively counts the number of children
    // of each node
    // This binding needs to be invalidated if the list of child nodes of any
    // tree node changes...
    private final IntegerBinding count = new IntegerBinding() {

        @Override
        protected int computeValue() {
            // Note the AtomicInteger here is just used as a mutable wrapper.
            // We don't care about the atomicity since it's only updated from 
            // one thread
            return countNodes(tree.getRoot(), new AtomicInteger());
        }

        private int countNodes(TreeItem<?> node, AtomicInteger count) {
            count.incrementAndGet();
            for (TreeItem<?> child : node.getChildren()) {
                countNodes(child, count);
            }
            return count.intValue();
        }
    };

    // A ListChangeListener that will be associated with any tree node. It does two things:
    // First, it invalidates the count binding above if the number of child nodes changes.
    // Second, it adds the same listener to any new child nodes, and removes it from any nodes
    // that are removed from the tree.
    private final ListChangeListener<TreeItem<String>> childrenChanged 
        = new ListChangeListener<TreeItem<String>>() {

            @Override
            public void onChanged(
                    javafx.collections.ListChangeListener.Change<? extends TreeItem<String>> change) {
                while (change.next()) {
                    if (change.wasAdded() || change.wasRemoved()) {
                        count.invalidate();
                    }
                    if (change.wasAdded()) {
                        for (TreeItem<String> item : change.getAddedSubList()) {
                            item.getChildren().addListener(childrenChanged);
                        }
                    } else if (change.wasRemoved()) {
                        for (TreeItem<String> item : change.getRemoved()) {
                            item.getChildren().removeListener(childrenChanged);
                        }
                    }
                }
            }

    };

    public void initialize(){ 
        tree.getRoot().getChildren().addListener(childrenChanged);
        countLabel.textProperty().bind(Bindings.format("Count: %s", count));
    }


    // add a new child node to the selected node (or the root if nothing's selected)
    @FXML
    private void addItem() {
        TreeItem<String> item = tree.getSelectionModel().getSelectedItem();
        if (item == null) {
            item = tree.getRoot();
        }
        TreeItem<String> newItem = new TreeItem<>(itemTextField.getText());
        newItem.setExpanded(true);
        item.getChildren().add(newItem);
        itemTextField.setText("");
        itemTextField.requestFocus();
    }
}

CountingTree.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.TreeView?>
<?import javafx.scene.control.TreeItem?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.geometry.Insets?>

<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="CountingTreeViewController">
    <center>
        <TreeView fx:id="tree">
            <root>
                <TreeItem value="Root" expanded="true" />
            </root>
        </TreeView>
    </center>
    <right>
        <HBox alignment="CENTER" spacing="5">
            <padding>
                <Insets top="10" right="10" left="10" bottom="10"/>
            </padding>
            <TextField fx:id="itemTextField" onAction="#addItem"/>
            <Button text="Add" onAction="#addItem"/>
        </HBox>
    </right>
    <bottom>
        <Label text="Count: 1" fx:id="countLabel"/>
    </bottom>
</BorderPane>

CountingTree.java:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class CountingTree extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("CountingTree.fxml"));
        primaryStage.setScene(new Scene(loader.load(), 800, 600));
        primaryStage.show();
    }

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

答案 1 :(得分:0)

如果您可以访问TreeView的根节点,则可以非常简单地完成:

查看TreeItemTreeModificationEvent文档。您可以为childrenModificationEvent的根节点添加侦听器。每当在根节点下添加或删除节点时,您将获得TreeModificationEvent,您可以在其中检索添加和删除的节点。