Comment gérer ListView action cliquée?

j'ai mon application JavaFX 2.0, où j'ai besoin de faire quelque chose, après que l'Utilisateur a cliqué sur un élément dans ListView element. Pour construire GUI utilisateur j'utilise FXML, dans lequel j'ai quelque chose comme ceci:

        <children>
            <ListView fx:id="listView" GridPane.columnIndex="0" 
            GridPane.rowIndex="1" labelFor="$pane" 
            onPropertyChange="#handleListViewAction"/>
        </children>

Et voici ce que j'ai dans un Contrôleur pour cet événement:

        @FXML protected void handleListViewAction(ActionEvent event) {
           System.out.println("OK");
        }

Et ici, c'est une erreur, j'obtiens, lors de la scène, ce qui est pour ce gui est construit:

javafx.fxml.LoadException: java.lang.String does not define a property model for "property".
at javafx.fxml.FXMLLoader$Element.processEventHandlerAttributes(Unknown Source)
at javafx.fxml.FXMLLoader$ValueElement.processEndElement(Unknown Source)
at javafx.fxml.FXMLLoader.processEndElement(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at fxmlexample.FXMLExampleController.handleSubmitButtonAction(FXMLExampleController.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Node.fireEvent(Unknown Source)
at javafx.scene.control.Button.fire(Unknown Source)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(Unknown Source)
at com.sun.javafx.scene.control.skin.SkinBase.handle(Unknown Source)
at com.sun.javafx.scene.control.skin.SkinBase.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.access00(Unknown Source)
at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.notifyMouse(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access0(Unknown Source)
at com.sun.glass.ui.win.WinApplication.run(Unknown Source)
at java.lang.Thread.run(Thread.java:722) java.lang.NullPointerException
at javafx.scene.Scene.doCSSPass(Unknown Source)
at javafx.scene.Scene.access00(Unknown Source)
at javafx.scene.Scene$ScenePulseListener.pulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.firePulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access0(Unknown Source)
at com.sun.glass.ui.win.WinApplication.run(Unknown Source)
at java.lang.Thread.run(Thread.java:722)

et le dernier bloc de cette exception (d'ici Java.lang.NullPointerException) est bouclé.

19
demandé sur user990423 2012-03-15 19:00:26

4 réponses

les attributs et les valeurs de FXML sont directement mis en correspondance avec L'API FX. Donc, pour savoir comment écrire handler, vous pouvez d'abord créer les entities nécessaires par API.

il semble que vous voulez ajouter de l'action sur L'élément ListView sur le clic de souris, donc vous devez ajouter le gestionnaire de clic de souris. Dans l'API, il semble façon suivante:

    final ListView lv = new ListView(FXCollections.observableList(Arrays.asList("one", "2", "3")));
    lv.setOnMouseClicked(new EventHandler<MouseEvent>() {

        @Override
        public void handle(MouseEvent event) {
            System.out.println("clicked on " + lv.getSelectionModel().getSelectedItem());
        }
    });

en regardant ce code, vous pouvez trouver ce que dans FXML vous devez modifier l'attribut onMouseClicked:

<ListView fx:id="listView" onMouseClicked="#handleMouseClick"/>

et dans controller vous devez fournir à handler MouseEvent paramètre:

@FXML
private ListView listView;

@FXML public void handleMouseClick(MouseEvent arg0) {
    System.out.println("clicked on " + listView.getSelectionModel().getSelectedItem());
}
35
répondu Sergey Grinev 2012-03-15 18:58:59

réponse de @Sergey Grinev peut y avoir un problème. si votre liste est remplie pas assez complet, en d'autres mots peuvent avoir un espace vide. ensuite, vous cliked espace blanc ne sera pas tigrer sélection changer. enter image description here

la solution: utiliser ListCell personnalisé.

  1. permet de définir une classe personnalisée s'étend ListCell.
  2. dans la fonction updateItem, vous pouvez définir le gestionnaire d'événements de clic d'élément au noeud de racine de cellule.

si vous ne le faites pas savoir combien de points vous avez. vous ne le ferez pas seulement. vous devez utiliser le temps pour l'espace.

Demostrate:

dans le segment de code ListView:

listView.setCellFactory(new AppListCellFactory());

AppListCellFactory.java:

public class AppListCellFactory implements Callback, ListCell> {

// only one global event handler
private EventHandler<MouseEvent> oneClickHandler;


public AppListCellFactory(){
    oneClickHandler = new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            Parent p = (Parent) event.getSource();
            //  do what you want to do with data.
            AppClickHandler.onAppBeanClicked((AppBean) p.getUserData());
        }
    };
}

@Override
public ListCell<AppBean> call(ListView<AppBean> param) {
    return new DemoListCell(oneClickHandler);
}

public static final class DemoListCell extends ListCell<AppBean> {

    private EventHandler<MouseEvent> clickHandler;

    /**
     * This is ListView item root node.
     */
    private Parent itemRoot;

    private Label label_AppName;
    private ImageView imgv_AppIcon;

    DemoListCell(EventHandler<MouseEvent> clickHandler) {
        this.clickHandler = clickHandler;
    }

    @Override
    protected void updateItem(AppBean app, boolean empty) {
        super.updateItem(app, empty);
        if (app == null) {
            setText(null);
            setGraphic(null);
            return;
        }
        if (null == itemRoot) {
            try {
                itemRoot = FXMLLoader.load(getClass().getResource(("fxml/appList_item.fxml")));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            label_AppName = (Label) itemRoot.lookup("#item_Label_AppName");
            imgv_AppIcon = (ImageView) itemRoot.lookup("#item_ImageView_AppIcon");
            itemRoot.setOnMouseClicked(clickHandler);
        }
        //  set user data. like android's setTag(Object).
        itemRoot.setUserData(app);
        label_AppName.setText(app.name);
        imgv_AppIcon.setImage(new Image(getClass().getResource("img/icon_64.png").toExternalForm()));
        setGraphic(itemRoot);
    }
}

}

7
répondu gordonpro 2014-04-17 06:47:36

un simple correctif à la réponse de Sergey, sans avoir à créer une toute nouvelle listCell (dans votre cas, vous le faites, mais nous n'avons pas à le faire dans un cas de texte régulier).

tout ce que vous devez simplement faire est de créer une variable temp qui est égale au premier élément de la liste au début, et qui est changée à chaque nouvel élément cliqué. Une fois que vous essayez de cliquer à nouveau sur l'élément, la variable temp sait que c'est la même chose, et avec une instruction if vous pouvez contourner cela.

temp Élément global de ce que vous mettre vers le haut en haut String tempItem = "admin";

pour moi, je savais que mon premier champ serait toujours étiqueté "admin" donc je l'ai défini comme tel. vous auriez à obtenir la première entrée et de lui en dehors de la méthode que vous allez utiliser pour la liste de sélection.

private void selUser() throws IOException
    {
    String item = userList.getSelectionModel().getSelectedItem().toString();

        if(item != tempItem)
        {
           //click, do something
        }

        tempItem = item;    
}

quant à moi j'ai utilisé un document FXML qui a appelé ma méthode

@FXML 
public void userSel(MouseEvent mouse) throws IOException
{
selUser();

}

dans ce cas vous pouvez simplement prendre tout le contenu de la méthode selUser() et le mettre dans la souris userSel cliquer.

2
répondu XaolingBao 2014-10-11 19:17:14

Vous pouvez également consommer des événements indésirables sur l'espace vide.

call() de la cellule de l'usine d'ajouter:

cell.setOnMousePressed((MouseEvent event) -> {
    if (cell.isEmpty()) {
       event.consume();
    }
});

désactiver click& dragStart trop.

exemple entier de cellFactory de mon projet:

public static Callback<ListView<BlockFactory>, ListCell<BlockFactory>> getCellFactory() {
    return new Callback<ListView<BlockFactory>, ListCell<BlockFactory>>() {

        @Override
        public ListCell<BlockFactory> call(ListView<BlockFactory> param) {
            ListCell<BlockFactory> cell = new ListCell<BlockFactory>() {

                @Override
                protected void updateItem(BlockFactory item, boolean empty) {
                    super.updateItem(item, empty);
                    if (item != null) {
                        ImageView img = new ImageView(item.img);
                        Label label = new Label(item.desc);
                        HBox bar = new HBox(img, label);
                        bar.setSpacing(15);
                        bar.setAlignment(Pos.CENTER_LEFT);
                        setGraphic(bar);
                    }
                }
            };
            cell.setOnMousePressed((MouseEvent event) -> {
                if (cell.isEmpty()) {
                    event.consume();
                }
            });
            return cell;
        }
    };
}
2
répondu Steel Talon 2014-11-03 22:24:49