2015-08-08 5 views
1

В моем TableView есть столбец с ToggleButton. Все кнопки принадлежат одной группе, вы можете выбрать только одну кнопку (одну строку). Но у моего TableView много строк, и ToggleGroup, похоже, работает. Это до тех пор, пока я не прокручу. Когда я выбираю один ToggleButton и прокручиваю вниз, ни одна другая кнопка не должна быть выбрана, но всегда есть один, который выбран для каждого вида. Это исправление?
Edit: Вот SSCCE:JavaFX: TableView ToogleButton Column

MainApp.java:

package p1; 
import java.io.IOException; 
import javafx.application.Application; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Scene; 
import javafx.scene.layout.AnchorPane; 
import javafx.stage.Stage; 

public class MainApp extends Application { 

private Stage primaryStage; 
private AnchorPane rootLayout; 
private ObservableList<Person> personData = FXCollections.observableArrayList(); 

public MainApp(){  
    for(int i=0;i<40;i++){ 
     personData.add(new Person("person " +i)); 
    } 
} 
public ObservableList<Person> getPersonData(){ 
    return personData; 
} 
@Override 
public void start(Stage primaryStage) throws Exception {  
    this.primaryStage = primaryStage; 
    try{ 
     FXMLLoader loader =new FXMLLoader(); 
     loader.setLocation(MainApp.class.getResource("People.fxml"));     
     rootLayout = (AnchorPane)loader.load(); 
     Scene scene = new Scene(rootLayout); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
     PeopleController controller = loader.getController(); 
     controller.setMainApp(this);    
    } catch(IOException e){ 
     e.printStackTrace(); 
    }   
} 
public Stage getPrimaryStage(){ 
    return primaryStage; 
} 
public static void main(String[] args){ 
    launch(args); 
}} 

People.fxml:

<?xml version="1.0" encoding="UTF-8"?> 
<?import java.lang.*?> 
<?import java.util.*?> 
<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="p1.PeopleController"> 
<children> 
<TableView fx:id="personTable" layoutX="160.0" layoutY="49.0" prefHeight="351.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="49.0"> 
<columns> 
     <TableColumn fx:id="nameColumn" prefWidth="75.0" text="Name" /> 
     <TableColumn fx:id="previewColumn" prefWidth="75.0" text="Preview"/> 
    </columns> 
    </TableView> 
    </children> 
    </AnchorPane> 

PeopleController.java:

package p1; 
import com.sun.prism.impl.Disposer; 
import javafx.fxml.FXML; 
import javafx.geometry.Pos; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.ToggleButton; 
import javafx.scene.control.ToggleGroup; 
import javafx.util.Callback; 

public class PeopleController{ 

@FXML private TableView<Person> personTable; 
@FXML private TableColumn<Person, String> nameColumn; 
@FXML private TableColumn previewColumn; 
private MainApp mainApp; 
final ToggleGroup group = new ToggleGroup(); 

@FXML 
public void initialize() { 
    nameColumn.setCellValueFactory(cellData -> cellData.getValue().NameProperty()); 
    previewColumn.setCellFactory(
      new Callback<TableColumn<Disposer.Record, Boolean>, TableCell<Disposer.Record, Boolean>>() { 

     @Override 
     public TableCell<Disposer.Record, Boolean> call(TableColumn<Disposer.Record, Boolean> p) { 
      ButtonCell cell = new ButtonCell(group); 
      cell.setAlignment(Pos.CENTER); 
      return cell; 
     } 
    }); 
} 
public void setMainApp(MainApp mainApp){ 
    this.mainApp = mainApp; 
    personTable.setItems(mainApp.getPersonData()); 
} 
public class ButtonCell extends TableCell<Disposer.Record, Boolean> { 

    final ToggleButton cellButton = new ToggleButton("click"); 

    public ButtonCell(ToggleGroup group){ 
     cellButton.setToggleGroup(group); 
    } 
    @Override 
    protected void updateItem(Boolean t, boolean empty) { 
     super.updateItem(t, empty); 
     if(!empty){ 
      setGraphic(cellButton); 
     } 
    }}} 

Person. java:

package p1; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 

public class Person { 
private final StringProperty name; 
public Person(){ 
    this(null); 
} 
public Person(String name){ 
this.name = new SimpleStringProperty(name); 
}  
public String getName(){ 
    return name.get(); 
} 
public void setName(String name){ 
    this.name.set(name); 
} 
public StringProperty NameProperty(){ 
    return name; 
} } 
+0

, пожалуйста, покажите SSCCE, который демонстрирует проблему – kleopatra

+0

Я добавил SSCCE, это хорошо? @kleopatra – whites

+0

да, спасибо - теперь посмотрите, что вы имеете в виду :-) Вы не можете управлять состоянием в представлении (aka: ToggleGroup), потому что ячейки повторно используются, а затем больше не соответствуют начальной строке , Вместо этого сохраните состояние в некоторой модели данных и обновите по мере необходимости. Несвязанный: лучше придерживаться соглашений об именах javafx, должен быть _nameProperty_ – kleopatra

ответ

0

Причина, по которой тумблер кажется, при прокрутке «прыгать» является повторным использованием клеток: выбранный государственным прилипает к кнопке, а не пункт. Следовательно, вы не можете использовать toggleGroup (за исключением не очень распространенного и не рекомендуемого случая, когда элементы в ваших данных реализуют Toggle), чтобы сохранить состояние переключения. Вам нужно реализовать тумблер самостоятельно.

Один из вариантов - это индивидуальный SingleSelectionModel и пользовательский ButtonCell, который говорит с моделью (как и все другие соавторы). К сожалению, у FX нет публично доступной конкретной реализации модели. Как часто, тяжелая атлетика - что в данном случае обновить себя на модификаций элементов - оставляется кода клиента (и не сделали в этом примере, а ;-)

Что-то вроде:

public class ToggleButtonTableExample extends Application { 

    public static class DataSelectionModel<S> extends SingleSelectionModel<S> { 

     private ListProperty<S> listProperty; 

     public DataSelectionModel(Property<ObservableList<S>> items) { 
      //listProperty = BugPropertyAdapters.listProperty(items); 
      listProperty = new SimpleListProperty<>(); 
      listProperty.bindBidirectional(items); 
      ListChangeListener<S> itemsContentObserver = c -> { 
       itemsChanged(c); 
      }; 
      listProperty.addListener(itemsContentObserver); 
     } 

     protected void itemsChanged(Change<? extends S> c) { 
      // TODO need to implement update on modificatins to the underlying list 
     } 

     @Override 
     protected S getModelItem(int index) { 
      if (index < 0 || index >= getItemCount()) return null; 
      return listProperty.get(index); 
     } 

     @Override 
     protected int getItemCount() { 
      return listProperty.getSize(); 
     } 

    } 

    public static class ButtonCellX<S, T> extends TableCell<S, T> { 

     private ToggleButton cellButton; 
     private SingleSelectionModel<S> model; 

     public ButtonCellX(SingleSelectionModel<S> group) { 
      this.model = group; 
      cellButton = new ToggleButton("click"); 
      cellButton.setOnAction(e -> updateToggle()); 
      updateToggle(); 
      setAlignment(Pos.CENTER); 
     } 

     protected void updateToggle() { 
      model.select(cellButton.isSelected()? getIndex() : -1); 
     } 

     @Override 
     protected void updateItem(T t, boolean empty) { 
      super.updateItem(t, empty); 
      if (empty) { 
       setGraphic(null); 
      } else { 
       cellButton.setSelected(model.isSelected(getIndex())); 
       setGraphic(cellButton); 
      } 
     } 
    } 

    private Parent getContent() { 
     TableView<Person> table = new TableView<>(); 
     table.setItems(Person.persons()); 
     TableColumn<Person, String> name = new TableColumn<>("Name"); 
     name.setCellValueFactory(new PropertyValueFactory<>("lastName")); 

     SingleSelectionModel<Person> model = new DataSelectionModel<>(table.itemsProperty()); 
     TableColumn<Person, Boolean> toggle = new TableColumn<>("Preview"); 
     toggle.setCellFactory(c -> new ButtonCellX<Person, Boolean>(model)); 

     toggle.setCellValueFactory(f -> { 
      Object value = f.getValue(); 
      return Bindings.equal(value, model.selectedItemProperty()); 
     }); 

     table.getColumns().addAll(name, toggle); 

     Button select = new Button("Select 0"); 
     select.setOnAction(e -> { 
      model.select(0); 
     }); 
     VBox content = new VBox(10, table, select); 
     return content; 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     primaryStage.setScene(new Scene(getContent())); 
     //primaryStage.setTitle(FXUtils.version()); 
     primaryStage.show(); 
    } 


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

    @SuppressWarnings("unused") 
    private static final Logger LOG = Logger 
      .getLogger(ChoiceBoxTableCellDynamic.class.getName()); 

}