2012-03-15 7 views
13

Tengo mi aplicación JavaFX 2.0, donde necesito hacer algo, después de que el usuario ha hecho clic en un elemento de ListView. Para construir usuario GUI que estoy usando FXML, en el que tengo algo como esto:¿Cómo se maneja la acción hecha clic en el elemento ListView?

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

Y aquí es lo que tengo en un controlador para este evento:

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

Y aquí es un error , que recibo, cuando la escena, que es para esta interfaz gráfica de usuario se construye:

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$5.handle(Unknown Source) 
at com.sun.javafx.scene.control.skin.SkinBase$5.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.access$1300(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.access$100(Unknown Source) 
at com.sun.glass.ui.win.WinApplication$2$1.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.access$2900(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$8.run(Unknown Source) 
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
at com.sun.glass.ui.win.WinApplication.access$100(Unknown Source) 
at com.sun.glass.ui.win.WinApplication$2$1.run(Unknown Source) 
at java.lang.Thread.run(Thread.java:722) 

Y el último bloque de esta excepción (de aquí java.lang.NullPointerException) forma un bucle.

Respuesta

26

Los atributos y valores de FXML se asignan directamente a FX API. Entonces, para averiguar cómo escribir el controlador, primero puede crear entidades requeridas por API.

Parece que desea agregar acción en el elemento ListView con el clic del mouse, por lo que debe agregar el controlador de clic del mouse. En la API se ve manera siguiente:

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()); 
     } 
    }); 

cuanto a que el código se puede descubrir lo que en FXML que necesita para atributo override onMouseClicked:

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

Y en el controlador que necesita para proporcionar manejador con MouseEvent parámetro :

@FXML 
private ListView listView; 

@FXML public void handleMouseClick(MouseEvent arg0) { 
    System.out.println("clicked on " + listView.getSelectionModel().getSelectedItem()); 
} 
+0

Hola. Si tengo un EventHandler que no está vinculado a un controlador, pero se puede usar de forma independiente en muchos lugares de mi aplicación. ¿Es posible asignar el manejador de eventos directamente en fxml en lugar de asignarle un método desde el controlador? –

+0

¡Esto es exactamente lo que estaba buscando! ¡Gracias! – Maslor

+0

No estoy seguro de cómo usar esto fuera de mi método de inicio. ¿Cómo puedo llamar al ownerStage desde un Controller por ejemplo? – santafebound

7

respuesta de @Sergey Grinev puede tener un problema. si su ListView no está lleno, es posible que tenga algún espacio en blanco. y luego pinchó el espacio en blanco no cambiará la selección. enter image description here

la solución: Use ListCell personalizado.

  1. definen una clase personalizada que extiende ListCell.
  2. en la función updateItem puede establecer el elemento al hacer clic en el controlador de eventos en el nodo raíz de la celda.

Si no sabe cuántos elementos tiene. no solo lo harás nunca. deberías usar el tiempo para el espacio.

demostramos:

en el segmento de código 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

Y luego se sorprenden de por qué la gente odia Java ... – shinzou

2

Una solución simple a la respuesta de Sergey, sin tener que crear un listCell completamente nuevo (en su caso lo hace, pero no es necesario en una caja de texto normal).

todo lo que necesita hacer es simplemente crear una variable de temperatura que sea igual al primer elemento de la lista al principio, y que se cambie a cada nuevo elemento en el que se haga clic. Una vez que intente hacer clic en el elemento de nuevo, la variable de temperatura sabe que es lo mismo, y con una instrucción if puede evitarlo.

temp artículo es un mundial que se pone encima de la tapa String tempItem = "admin";

para mí sabía que mi primer campo siempre va a ser etiquetado como "admin" así que me puse como tal. Tendría que obtener la primera entrada y configurarla fuera del método que va a utilizar para seleccionar la lista.

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

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

     tempItem = item;  
} 

lo que a mí me utilizó un documento FXML que llama mi método

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

}

En este caso, usted podría tomar todo el contenido de la selUser() método y ponerlo en el usuario, haga clic en el mouse.

1

También puede consumir eventos no deseados en el espacio en blanco.

en call() del complemento fábrica de células:

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

Esto desactivará click & dragStart también.

entero ejemplo cellFactory de mi proyecto:

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; 
     } 
    }; 
} 
Cuestiones relacionadas