JavaFX:TableView ToogleButton列

时间:2015-08-08 13:01:29

标签: javafx tableview javafx-8

我的TableView有一个带有ToggleButton的列。所有按钮属于一个组,您只能选择一个按钮(一行)。 但我的TableView有很多行,ToggleGroup似乎有效。 那是直到我滚动淹死。 当我选择一个ToggleButton并向下滚动时,不应选择其他按钮,但每个视图始终选择一个按钮。 这可以解决吗?
修改:这是SSCCE:

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;
} }   

1 个答案:

答案 0 :(得分: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());

}