我写了以下代码。
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
import javafx.util.Callback;
public class App extends Application {
private ListView<String> listView;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
List<String> friendList = new ArrayList<String>();
friendList.add("Alice");
friendList.add("Bob");
listView = new ListView<>(FXCollections.observableArrayList(friendList));
listView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
@Override
public ListCell<String> call(ListView<String> p) {
ListCell<String> cell = new ListCell<String>() {
@Override
protected void updateItem(String t, boolean empty) {
super.updateItem(t, empty);
if (t != null) {
Label usernameLabel = new Label(t);
usernameLabel.setFont(Font.font("Arial", FontWeight.BOLD, 12));
Button callButton = new Button("Call");
callButton.setOnAction(e -> System.out.println("action")); // not working
callButton.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> System.out.println("entered"));
callButton.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("clicked")); // not working
HBox usernameBox = new HBox(5);
usernameBox.setAlignment(Pos.CENTER_LEFT);
usernameBox.getChildren().addAll(usernameLabel);
BorderPane borderPane = new BorderPane();
borderPane.setLeft(usernameBox);
borderPane.setRight(callButton);
VBox vbox = new VBox(3);
vbox.getChildren().addAll(borderPane);
setGraphic(vbox);
}
}
};
return cell;
}
});
stage.setScene(new Scene(listView));
stage.show();
}
}
如果你看一下callButton,你会发现它有三个不同的处理程序。但是,实际上只触发了MOUSE_ENTERED事件处理程序。其他的完全被忽略了。可能是什么问题?
编辑:添加并删除了一些代码,以使其可以运行。
答案 0 :(得分:3)
这是JavaFX 8中的known bug,已在最新的ea版本(1.8.0_20)中修复。
作为一种解决方法,创建一次控件并使用它们注册处理程序,然后只需在updateItem(...)方法中更新它们的状态:
listView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
@Override
public ListCell<String> call(ListView<String> p) {
Label usernameLabel = new Label();
usernameLabel.setFont(Font.font("Arial", FontWeight.BOLD, 12));
Button callButton = new Button("Call");
HBox usernameBox = new HBox(5);
usernameBox.setAlignment(Pos.CENTER_LEFT);
usernameBox.getChildren().addAll(usernameLabel);
BorderPane borderPane = new BorderPane();
borderPane.setLeft(usernameBox);
borderPane.setRight(callButton);
VBox vbox = new VBox(3);
vbox.getChildren().addAll(borderPane);
ListCell<String> cell = new ListCell<String>() {
@Override
protected void updateItem(String t, boolean empty) {
super.updateItem(t, empty);
if (t != null) {
usernameLabel.setText(t);
setGraphic(vbox);
} else {
setGraphic(null); // you will have weird bugs without this: don't omit it
}
}
};
callButton.setOnAction(e -> System.out.println("action: "+cell.getItem()));
callButton.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> System.out.println("entered "+ cell.getItem()));
callButton.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("clicked "+ cell.getItem()));
return cell;
}
});
请注意,这种“解决方法”无论如何都是首选方法,也是“虚拟化”控件设计者所期望的方法,如ListView
,TableView
等。重点是应用程序可能经常调用updateItem(...)
,而很少创建单元格。通过在updateItem(...)
方法中创建新控件,可能会引入性能问题。为单元格创建一次,然后在updateItem(...)
中配置它们。另请注意我如何只注册事件处理程序一次,并让处理程序引用cell.getItem()
以查看单元格当前表示的项目。
最后一件事:你的代码中有一个错误(我修复过)。由于单元格可以重复使用,包括显示项目的单元格被重用于空单元格的情况,因此始终处理项目为空的情况(通常通过将文本和/或图形设置为null)非常重要。 / p>
答案 1 :(得分:2)
您可以添加getIconAndResizeTo16( String s )
的代码吗?我猜你返回的节点会消耗鼠标点击次数。
这是一个演示该问题的可运行示例。这只是猜测。
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class App extends Application {
public static void main(String[] args) { launch(args); }
@Override
public void start(Stage stage) throws Exception {
Button callButton = new Button("", getIconAndResizeTo16("Phone"));
callButton.setOnAction(e -> System.out.println("clicked1")); // not working
callButton.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> System.out.println("entered"));
callButton.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("clicked")); // not working
Button chatButton = new Button("", getIconAndResizeTo16("Chat") );
chatButton.setOnAction(e -> System.out.println("clicked2")); // not working
HBox callIconBox = new HBox(3);
callIconBox.setAlignment(Pos.CENTER_RIGHT);
callIconBox.getChildren().addAll(callButton, chatButton);
stage.setScene(new Scene(callIconBox));
stage.show();
}
private Node getIconAndResizeTo16(String s) {
Label l = new Label("Consumes " + s + " Events");
l.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> { e.consume(); });
l.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> { e.consume(); });
return l;
}
}