JavaFX TableView TableRow焦点行为奇怪

时间:2014-08-28 22:30:51

标签: focus javafx-2 tableview

如果重要的话,我正在使用JDK 1.7.0_51。我有以下改编的示例代码来演示我所看到的异常行为。

我以编程方式选择了表中的第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", "jacob.smith@example.com" ),
          new Person( "Isabella", "Johnson", "isabella.johnson@example.com" ),
          new Person( "Ethan", "Williams", "ethan.williams@example.com" ),
          new Person( "Emma", "Jones", "emma.jones@example.com" ),
          new Person( "Michael", "Brown", "michael.brown@example.com" ) );
  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

任何人都可以帮助我了解这里发生了什么以及这是否是正确的行为?

1 个答案:

答案 0 :(得分:0)

您使用的是什么IDE?你在IntelliJ上试过吗?当我在IntelliJ中运行您的类时,我没有报告您的焦点问题。我使用的是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