listview - reales - libro de android studio en español pdf
¿Cómo manejar el elemento ListView hecho clic en la acción? (4)
Tengo mi aplicación JavaFX 2.0, donde necesito realizar alguna acción, después de que el usuario haya hecho clic en un elemento en el elemento ListView. Para construir la GUI del usuario estoy usando FXML, en el que tengo algo como esto:
<children>
<ListView fx:id="listView" GridPane.columnIndex="0"
GridPane.rowIndex="1" labelFor="$pane"
onPropertyChange="#handleListViewAction"/>
</children>
Y aquí está lo que tengo en un controlador para este evento:
@FXML protected void handleListViewAction(ActionEvent event) {
System.out.println("OK");
}
Y aquí hay un error, recibo, cuando se construye la escena, que es para este gui:
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 (desde aquí java.lang.NullPointerException) está en bucle.
La respuesta de @Sergey Grinev puede tener un problema. Si su ListView no está lo suficientemente lleno, en otras palabras, puede tener algún espacio en blanco. entonces cliked el espacio en blanco no cambiará la selección tigger.
La solución: Use ListCell personalizado.
- definir una clase personalizada extiende ListCell.
- en la función updateItem puede configurar el controlador de eventos de clic de elemento en el nodo raíz de la celda.
Si no sabes cuántos artículos tienes. No siempre lo harás. Deberías usar el tiempo para el espacio.
Demostrado:
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);
}
}
}
Los atributos y valores de FXML se asignan directamente a FX API. Entonces, para averiguar cómo escribir el controlador, primero puede crear las entidades requeridas por API.
Parece que desea agregar acción en el elemento ListView al hacer clic con el mouse, por lo que necesita agregar el controlador de clic con el mouse. En API se ve a continuación:
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());
}
});
Mirando ese código, puede averiguar qué en FXML necesita anular el atributo onMouseClicked
:
<ListView fx:id="listView" onMouseClicked="#handleMouseClick"/>
Y en el controlador debe proporcionar el controlador con MouseEvent
parámetro MouseEvent
:
@FXML
private ListView listView;
@FXML public void handleMouseClick(MouseEvent arg0) {
System.out.println("clicked on " + listView.getSelectionModel().getSelectedItem());
}
También puede consumir eventos no deseados en el espacio en blanco.
en la call()
de la fábrica de células agregar:
cell.setOnMousePressed((MouseEvent event) -> {
if (cell.isEmpty()) {
event.consume();
}
});
Esto deshabilitará click
& dragStart
también.
Ejemplo completo de 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;
}
};
}
Una solución simple a la respuesta de Sergey, sin tener que crear una nueva listaCell (en su caso, sí, pero no tenemos que hacerlo en un caso de texto regular).
todo lo que necesita hacer es crear una variable temporal 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 intenta hacer clic en el elemento nuevamente, la variable temporal sabe que es la misma, y con una sentencia if puede evitar eso.
temp Item es un elemento global que String tempItem = "admin";
arriba String tempItem = "admin";
para mí sabía que mi primer campo siempre será etiquetado como "admin", así que lo configuré como tal. tendría que obtener la primera entrada y establecerla 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;
}
En cuanto a mí, utilicé un documento FXML que llamaba mi método.
@FXML
public void userSel(MouseEvent mouse) throws IOException
{
selUser();
}
En este caso, puede tomar todo el contenido del método selUser () y ponerlo en el clic del mouse del usuario.