Подтвердить что ты не робот

Как обрабатывать действие элемента ClickView с кликом?

У меня есть приложение JavaFX 2.0, где мне нужно сделать некоторые действия после того, как пользователь щелкнул элемент в элементе ListView. Чтобы создать пользовательский графический интерфейс, я использую FXML, в котором у меня есть что-то вроде этого:

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

И вот что я имею в контроллере для этого события:

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

И вот ошибка, которую я получаю, когда построена сцена, которая для этого 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)

И последний блок этого исключения (отсюда java.lang.NullPointerException) зацикливается.

4b9b3361

Ответ 1

Атрибуты и значения FXML напрямую отображаются в FX API. Итак, чтобы узнать, как писать обработчик, вы можете сначала создать необходимые объекты API.

Кажется, вы хотите добавить действие в элемент ListView при щелчке мыши, поэтому вам нужно добавить обработчик щелчка мыши. В API это выглядит следующим образом:

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

Глядя на этот код, вы можете узнать, что в FXML вам нужно переопределить атрибут onMouseClicked:

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

И в контроллере вам нужно предоставить обработчик с параметром MouseEvent:

@FXML
private ListView listView;

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

Ответ 2

Ответ от @Sergey Grinev может возникнуть. если ваш ListView заполнен недостаточно заполнен, другими словами, может быть пустое пространство. то вы закрыли пустое пространство, которое не изменит выбор тигра. enter image description here

решение: используйте собственный ListCell.

  • определяет пользовательский класс, который расширяет ListCell.
  • в функции updateItem вы можете установить обработчик события элемента item на корень ячейки node.

Если вы не знаете, сколько у вас предметов. вы никогда этого не сделаете. вы должны использовать время для пробела.

Demostrate:

в сегменте кода 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 setTag(Object).
        itemRoot.setUserData(app);
        label_AppName.setText(app.name);
        imgv_AppIcon.setImage(new Image(getClass().getResource("img/icon_64.png").toExternalForm()));
        setGraphic(itemRoot);
    }
}

}

Ответ 3

Простое решение для Сергея отвечает, не создавая целую новую listCell (в вашем случае вы это делаете, но мы не должны в регулярном текстовом случае).

все, что вам нужно просто сделать, это создать временную переменную, которая сначала будет равна первому элементу списка, и это будет изменено на каждый новый элемент с кликом. После того, как вы попытаетесь снова щелкнуть элемент, переменная temp знает то же самое, и с помощью оператора if вы можете обойти это.

temp Item является глобальным, и вы устанавливаете top String tempItem = "admin";

для меня Я знал, что мое первое поле всегда будет помечено как "admin", поэтому я установил его как таковой. вам нужно будет получить первую запись и установить ее вне метода, который вы собираетесь использовать для выбора списка.

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

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

        tempItem = item;    
}

Что касается меня, я использовал документ FXML, который вызвал мой метод

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

}

В этом случае вы можете просто взять все содержимое метода selUser() и поместить его в щелчок мышью userSel.

Ответ 4

Вы также можете использовать нежелательные события на пустом месте.

в call() ячейки factory добавить:

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

Это также отключит click и dragStart.

Пример Whole cellFactory из моего проекта:

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