ユーザーがListView要素内のアイテムをクリックした後に、JavaFX 2.0アプリケーションを使用します。ユーザーGUIを構築するには、FXMLを使用します。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)がループされます。
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());
}
@Sergey Grinevからの回答に問題がある可能性があります。 ListViewがいっぱいになっていない場合、言い換えると、いくつかの空白スペースがあるかもしれません。空白スペースを選択した場合、ティガーの選択は変更されません。
解決策:カスタムListCellを使用します。
持っているアイテムの数がわからない場合。あなたはそうするだけではありません。スペースに時間を使う必要があります。
Demostrate:
listViewコードセグメントで:
listView.setCellFactory(new AppListCellFactory());
AppListCellFactory.Java:
パブリッククラスAppListCellFactoryは、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);
}
}
}
空白スペースで不要なイベントを消費することもできます。
セルファクトリのcall()
に以下を追加します。
cell.setOnMousePressed((MouseEvent event) -> {
if (cell.isEmpty()) {
event.consume();
}
});
これにより、click
とdragStart
も無効になります。
私のプロジェクトからの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;
}
};
}
まったく新しいlistCellを作成することなく、Sergeyの答えを簡単に修正します(あなたの場合はそうしますが、通常のテキストの場合はそうする必要はありません)。
単純に行う必要があるのは、最初に最初のリスト項目に等しい一時変数を作成することです。この変数は、クリックされた新しい項目ごとに変更されます。もう一度アイテムをクリックしようとすると、temp変数はそれが同じであることを認識し、ifステートメントでそれを回避できます。
一時アイテムは、トップ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マウスクリックに入れるだけです。