2014-05-09 71 views
3

我寫了下面的代碼。JavaFX處理程序未觸發

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

你能通過工作實例更新你的問題嗎? –

+0

剛更新了帖子。現在它應該運行。 – r0f1

回答

3

這是JavaFX的8,其被固定在最新EA釋放(1.8.0_20)一個known bug

作爲一種變通方法,創建控件一次,並與他們註冊的處理程序,然後就更新自己的的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; 
     } 
    }); 

請注意,此「解決辦法」確實是首選無論如何,以及「虛擬化」控件的設計者所打算的那個,如ListViewTableView等。關鍵是updateItem(...)可能被應用程序非常頻繁地調用,而單元格很少被創建。通過在updateItem(...)方法中創建新控件,您可能會引入性能問題。爲單元格創建一次,然後在updateItem(...)中配置它們。另請注意,我只註冊了一次事件處理程序,並讓處理程序參考cell.getItem()以查看單元當前由哪個項目表示。

最後一件事:你的代碼有一個bug(我修正了)。由於單元格可以重複使用,包括單元格顯示一個項目被重新用於空單元格的情況,所以重要的是您始終處理項目爲空的情況(通常通過將文本和/或圖形設置爲空)。

+0

感謝您的留言,現在有效。並感謝你做得比我所要求的還要多;) – r0f1

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; 
    } 
} 
相關問題