2014-08-28 61 views
1

如果有問題,我正在使用JDK 1.7.0_51。我有以下改編的示例代碼來演示我看到的不尋常行爲。JavaFX TableView TableRow焦點行爲奇怪

我已經以編程方式選擇了表格中的第0行,然後在0位置插入了添加的行。我希望選定的行向下移動一個,但相反它會下降兩個。另外,當我監視表格行上的焦點屬性時,我發現它在添加單行時發生了很大變化。當插入完成後,第2行有深藍色背景表示選擇,但第3行有一個藍色突出顯示的邊界。我不確定那是什麼。

我正在進行數據驗證時,錶行焦點丟失,以便我可以防止用戶離開當前條目,直到它正確形成。但是,這種選擇和關注行爲正在導致我的申請行爲失當。這是我能夠創建的最簡單的測試用例,它顯示了正在發生的事情。

import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ListChangeListener; 
import javafx.collections.ObservableList; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.geometry.Insets; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TablePosition; 
import javafx.scene.control.TableRow; 
import javafx.scene.control.TableView; 
import javafx.scene.control.TextField; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.layout.HBox; 
import javafx.scene.layout.VBox; 
import javafx.scene.text.Font; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

public class TableViewTest extends Application 
{ 

    private final TableView<Person> table = new TableView<Person>(); 
    private final ObservableList<Person> data = 
     FXCollections.observableArrayList(
      new Person("Jacob", "Smith", "[email protected]"), 
      new Person("Isabella", "Johnson", "[email protected]"), 
      new Person("Ethan", "Williams", "[email protected]"), 
      new Person("Emma", "Jones", "[email protected]"), 
      new Person("Michael", "Brown", "[email protected]")); 
    final HBox hb = new HBox(); 

    public static void main(String[] args) 
    { 
    launch(args); 
    } 

    @Override 
    public void start(Stage stage) 
    { 
    Scene scene = new Scene(new Group()); 
    stage.setTitle("Table View Sample"); 
    stage.setWidth(450); 
    stage.setHeight(550); 

    final Label label = new Label("Address Book"); 
    label.setFont(new Font("Arial", 20)); 

    table.setEditable(true); 
    table.setRowFactory(getRowFactory()); 

    TableColumn firstNameCol = new TableColumn("First Name"); 
    firstNameCol.setMinWidth(100); 
    firstNameCol.setCellValueFactory(
     new PropertyValueFactory< Person, String >("firstName")); 

    TableColumn lastNameCol = new TableColumn("Last Name"); 
    lastNameCol.setMinWidth(100); 
    lastNameCol.setCellValueFactory(
     new PropertyValueFactory< Person, String >("lastName")); 

    TableColumn emailCol = new TableColumn("Email"); 
    emailCol.setMinWidth(200); 
    emailCol.setCellValueFactory(
     new PropertyValueFactory< Person, String >("email")); 

    table.setItems(data); 
    table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 

    table.getSelectionModel().select(0); 

    table.getSelectionModel().getSelectedCells().addListener(new ListChangeListener<TablePosition>() 
    { 
     @Override 
     public void onChanged(final ListChangeListener.Change< ? extends TablePosition > c) 
     { 
     if (!c.getList().isEmpty()) 
     { 
      for (TablePosition pos : c.getList()) 
      { 
      System.out.println("Row " + String.valueOf(pos.getRow()) + " selected"); 
      } 
     } 
     else 
     { 
      System.out.println("Row unselected"); 
     } 
     } 
    }); 

    final TextField addFirstName = new TextField(); 
    addFirstName.setPromptText("First Name"); 
    addFirstName.setMaxWidth(firstNameCol.getPrefWidth()); 
    final TextField addLastName = new TextField(); 
    addLastName.setMaxWidth(lastNameCol.getPrefWidth()); 
    addLastName.setPromptText("Last Name"); 
    final TextField addEmail = new TextField(); 
    addEmail.setMaxWidth(emailCol.getPrefWidth()); 
    addEmail.setPromptText("Email"); 

    final Button addButton = new Button("Add"); 
    addButton.setOnAction(new EventHandler<ActionEvent>() 
    { 
     @Override 
     public void handle(ActionEvent e) 
     { 
     data.add(0, new Person(
      addFirstName.getText(), 
      addLastName.getText(), 
      addEmail.getText())); 
     addFirstName.clear(); 
     addLastName.clear(); 
     addEmail.clear(); 
     } 
    }); 

    hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton); 
    hb.setSpacing(3); 

    final VBox vbox = new VBox(); 
    vbox.setSpacing(5); 
    vbox.setPadding(new Insets(10, 0, 0, 10)); 
    vbox.getChildren().addAll(label, table, hb); 

    ((Group) scene.getRoot()).getChildren().addAll(vbox); 

    stage.setScene(scene); 
    stage.show(); 
    } 

    private Callback< TableView<Person>, TableRow<Person>> getRowFactory() 
    { 
    return new Callback< TableView<Person>, TableRow<Person>>() 
    { 
     @Override 
     public TableRow<Person> call(final TableView<Person> arg0) 
     { 

     return new DataTableRow(); 
     } 
    }; 
    } 

    public class DataTableRow extends TableRow<Person> 
    { 

    private final ChangeListener<Boolean> focusListener = new ChangeListener<Boolean>() 
    { 
     @Override 
     public void changed(final ObservableValue< ? extends Boolean > unused, final Boolean arg1, 
      final Boolean focused) 
     { 
     System.out.println("Row " + getIndex() + " Focus: " + focused); 
     } 
    }; 

    public DataTableRow() 
    { 
     focusedProperty().addListener(this.focusListener); 
    } 
    } 

    public static class Person 
    { 

    private final SimpleStringProperty firstName; 
    private final SimpleStringProperty lastName; 
    private final SimpleStringProperty email; 

    private Person(String fName, String lName, String email) 
    { 
     this.firstName = new SimpleStringProperty(fName); 
     this.lastName = new SimpleStringProperty(lName); 
     this.email = new SimpleStringProperty(email); 
    } 

    public String getFirstName() 
    { 
     return firstName.get(); 
    } 

    public void setFirstName(String fName) 
    { 
     firstName.set(fName); 
    } 

    public String getLastName() 
    { 
     return lastName.get(); 
    } 

    public void setLastName(String fName) 
    { 
     lastName.set(fName); 
    } 

    public String getEmail() 
    { 
     return email.get(); 
    } 

    public void setEmail(String fName) 
    { 
     email.set(fName); 
    } 
    } 
} 

我從運行這一點,並加入了單行得到的輸出是:

Row unselected 
Row 1 selected 
Row 0 Focus: false 
Row 1 Focus: true 
Row 1 Focus: false 
Row 2 Focus: true 
Row unselected 
Row unselected 
Row 2 selected 
Row 2 Focus: false 
Row 3 Focus: true 
Row 3 Focus: true 

誰能幫助我明白是怎麼回事,這是正確的行爲?

+0

這是一個錯誤。我在[Java 8u20發行版](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)上試了一下,在插入之後,焦點行與選定的行。在JavaFX問題跟蹤器中記錄錯誤:https://javafx-jira.kenai.com。 – jewelsea 2014-08-28 22:52:48

+0

謝謝。我很確定是這樣。我已經記錄了這個錯誤https://javafx-jira.kenai.com/browse/RT-38477。第一次記錄,所以我可能已經排除了信息。我想我有一個解決方法,保存selectedIndex,清除選擇,添加新行,然後選擇我想要的索引。 – kithril 2014-08-28 23:12:04

+0

我錯了。上述解決方法不起作用。 clearSelection()將焦點更改爲false,這觸發了我試圖避免的相同錯誤。我需要另一種解決方案,否則我將不得不重寫整個驗證策略。對於最後幾周的項目來說,這並不理想。 – kithril 2014-08-29 01:22:27

回答

0

你在用什麼IDE?你在IntelliJ上試過了嗎?當我在IntelliJ中運行你的Class時,我沒有報告過的焦點問題。我正在使用jdk 8u20。當我進入一個新行時,前一行變得不重要,新行變得焦點。見下:

Row 0 Focus: true 
Row 0 Focus: false 
Row 1 Focus: true 
Row 1 selected 
Row 1 Focus: false 
Row 2 Focus: true 
Row 2 selected 
Row unselected 
Row 3 selected 
Row 2 Focus: false 
Row 3 Focus: true 
Row 3 Focus: false 
Row 4 Focus: true 
Row 1 Focus: true 
Row 4 Focus: false 
Row 1 selected 
Row 1 Focus: false 
Row 5 Focus: true 
Row 5 selected 
Row 3 Focus: true 
Row 5 Focus: false 
Row 3 selected 
Row 0 Focus: true 
Row 3 Focus: false 
Row 0 selected 
Row 0 Focus: false 
Row 1 Focus: true 
Row 1 selected 
Row 1 Focus: false 
Row 2 Focus: true 
Row 2 selected 
Row 2 Focus: false 
Row 3 Focus: true 
Row 3 selected 
Row 0 Focus: true 
Row 3 Focus: false 
Row 0 selected