简体   繁体   English

JavaFX - TableCell 中带有添加数据按钮的单选按钮

[英]JavaFX - RadioButtons in TableCell with Add Data Button

I'm currently working on an application where I use a TableView including RadioButton s in one TableCell .我目前正在开发一个应用程序,在该应用程序中我使用TableView其中一个TableCell包含RadioButton For that I created an own RadioButtonCell class.为此,我创建了一个自己的RadioButtonCell类。 I also have a "Add new Row"-Button to let the user add some additional rows.我还有一个“添加新行”按钮,让用户添加一些额外的行。 After clicking the "Add" button a third time, I get more RadioButtonCell s than rows.第三次单击“添加”按钮后,我得到的RadioButtonCell比行多。 I don't find the mistake in my code.我在我的代码中没有发现错误。

Here a screenshot after clicking the Button a third time:这是第三次单击Button后的屏幕截图:

表视图的一部分

RadioButtonCell:单选按钮单元:

import java.util.EnumSet;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TableCell;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;

public class RadioButtonCell<S,T extends Enum<T>> extends TableCell<S,T>{

    private EnumSet<T> enumeration;

    public RadioButtonCell(EnumSet<T> enumeration) {
        this.enumeration = enumeration;
    }

    @Override
    protected void updateItem(T item, boolean empty)
    {
        super.updateItem(item, empty);
        if (!empty) 
        {
            // GUI
            HBox hb = new HBox(7);
            hb.setAlignment(Pos.CENTER);
            final ToggleGroup group = new ToggleGroup();

            // create a radio button for each 'element' of the enumeration
            for (Enum<T> enumElement : enumeration) {
                RadioButton radioButton = new RadioButton(enumElement.toString());
                radioButton.setUserData(enumElement);
                radioButton.setToggleGroup(group);
                hb.getChildren().add(radioButton);
                if (enumElement.equals(item)) {
                    radioButton.setSelected(true);
                }
            }

            // issue events on change of the selected radio button
            group.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {

                @SuppressWarnings("unchecked")
                @Override
                public void changed(ObservableValue<? extends Toggle> observable,
                        Toggle oldValue, Toggle newValue) {
                    getTableView().edit(getIndex(), getTableColumn());
                    RadioButtonCell.this.commitEdit((T) newValue.getUserData());
                }
            });
            setGraphic(hb);
        } 
    }
}

Model:模型:

public class Points {

    private final SimpleObjectProperty<Participation> participation = new SimpleObjectProperty<Participation>(); // radio buttons


    public static enum Participation {
        NONE, HALO, BORDER;

        public String toString() {
            return super.toString().toLowerCase();
        };
    }

    /**
     * Constructor.
     * @param <Participation>
     */
    public Points(Participation p) {

        this.participation.setValue(p);

    public void setParticipation(Participation p){
        participation.set(p);
    }

    public Participation getParticipation(){
        return participation.get();
    }

    public SimpleObjectProperty<Participation> ParticipationProperty() {
        return participation;
    }
}

FXML:文件格式:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<VBox prefHeight="900.0" prefWidth="1250.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="address.view.DataOverviewController">
   <children>
      <SplitPane fx:id="splitPaneVertical" prefHeight="776.0" prefWidth="1200.0" VBox.vgrow="ALWAYS">
         <items>
            <TabPane fx:id="tabPane" stylesheets="@Theme.css">
               <tabs>
                  <Tab text="Points">
                     <content>
                        <SplitPane fx:id="splitPaneHorizontal" dividerPositions="0.949874686716792" orientation="VERTICAL" stylesheets="@Theme.css">
                          <items>
                              <TableView fx:id="pointsDataTable">
                                <columns>                                
                                  <TableColumn fx:id="pointsBackgroundColumn" prefWidth="200.0" resizable="false" text="Background" />                                 
                                </columns>                                            
                              </TableView>
                            <AnchorPane SplitPane.resizableWithParent="false">
                                 <children>
                                    <HBox fx:id="pointsHBoxButton" alignment="CENTER" prefHeight="35.0" prefWidth="1016.0" spacing="20.0" stylesheets="@Theme.css" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
                                       <children>
                                          <Button fx:id="pointsAddButton" mnemonicParsing="false" onAction="#handleAddPoints" text="Add" />                     
                                     </children>
                                </HBox>
                             </children>
                          </AnchorPane>
                       </items>
                    </SplitPane>
                 </content>
              </Tab>
           </tabs>
        </TabPane>
     </items>
  </SplitPane>

Controller:控制器:

    public class DataOverviewController {
        @FXML
        private TableView<Points> pointsDataTable;

        @FXML
        private TableColumn<Points, Participation> pointsBackgroundColumn;

        @FXML
        private Button pointsButtonAdd;

        public DataOverviewController() {
        }

        @FXML
        private void initialize() {
            // select multipe rows, make rows editable
            pointsDataTable.setEditable(true);
            pointsDataTable.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
            linesDataTable.setEditable(true);

             pointsBackgroundColumn.setCellFactory((param) -> new RadioButtonCell<Points, Participation>(EnumSet.allOf(Participation.class)));
             pointsBackgroundColumn.setCellValueFactory(new PropertyValueFactory<Points, Participation>("Participation"));
             pointsBackgroundColumn.setOnEditCommit(
                        new EventHandler<CellEditEvent<Points, Participation>>() {
                            @Override
                            public void handle(CellEditEvent<Points, Participation> t) {
                                ((Points) t.getTableView().getItems().get(
                                    t.getTablePosition().getRow())
                                    ).setParticipation(t.getNewValue());
                            }
                        }
                    );

        public void setMainConfig(MainConfig mainConfig) {
            // Add observable list data to the table
            pointsDataTable.setItems(mainConfig.getTableDataPoints());
        }

        @FXML
        private void handleAddPoints() {
            // create new record and add it to the tableview
            Points dataPoints = new Points(0, "Points", "TabFileName.tab",Participation.NONE, false, false, 18, "new");
            pointsDataTable.getItems().add(dataPoints);
        }
    }
}

I reduced my code to the important parts.我将代码简化为重要部分。 Maybe someone can help?也许有人可以帮忙? Thanks.谢谢。

Items can be added as well as removed from TableCell s.可以在TableCell添加和删​​除项目。 This means you need to handle the case where the TableCell becomes empty by undoing any changes done to the cell when a item was added.这意味着您需要通过撤消添加项目时对单元格所做的任何更改来处理TableCell变空的情况。 Otherwise there may be TableCell s that look as if they contain a item although they are actually empty.否则,可能会有TableCell看起来好像包含一个项目,尽管它们实际上是空的。

A updateItem method should look like this: updateItem方法应如下所示:

@Override
protected void updateItem(T item, boolean empty) {
    super.updateItem(item, empty);

    if (empty) {
        // modifications to restore the empty state
    } else {
        // customized way of displaying the item
    }
}

Furthermore I do not recommend recreating the Node s for displaying the item in the cell every time the item is changed, since this means you'll have a lot of unnecessary node creations which is the thing TableView is trying to avoid by reusing cells.此外,我不建议在每次更改项目时重新创建Node以在单元格中显示项目,因为这意味着您将有很多不必要的节点创建,而TableView试图通过重用单元来避免这种情况。 Store them in fields and keep them for later use instead.将它们存储在字段中并保留以备后用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM