5 Replies Latest reply: Mar 25, 2013 11:42 PM by Retheesh RSS

    JFX fxml: custom cellfactory for CheckBoxTableCell throwing exception

    Retheesh
      Hi,

      I am trying to create a custom cell factory for inserting a CheckBoxTableCell in a TableView through fxml. But its giving me an exception as shown below.
      The cell factory class i have created and the fxml is also put below

      Can somebody help?

      SEVERE: javafx.scene.control.Control impl_processCSS The -fx-skin property has not been defined in CSS for TableRow[id=null, styleClass=cell indexed-cell table-row-cell]
      SEVERE: javafx.scene.control.Control loadSkinClass Failed to load skin 'StringProperty [bean: TableRow[id=null, styleClass=cell indexed-cell table-row-cell], name: skinClassName, value: com.sun.javafx.scene.control.skin.TableRowSkin]' for control TableRow[id=null, styleClass=cell indexed-cell table-row-cell]
      java.lang.ClassCastException: javafx.scene.control.cell.CheckBoxTableCell$1 cannot be cast to javafx.scene.control.TableCell
           at com.sun.javafx.scene.control.skin.TableRowSkin.recreateCells(TableRowSkin.java:224)
           at com.sun.javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:87)
           at sun.reflect.GeneratedConstructorAccessor1.newInstance(Unknown Source)
           at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
           at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
           at javafx.scene.control.Control.loadSkinClass(Control.java:992)
           at javafx.scene.control.Control.access$500(Control.java:71)
           at javafx.scene.control.Control$12.invalidated(Control.java:920)
           at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:127)
           at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)
           at com.sun.javafx.css.StyleableStringProperty.set(StyleableStringProperty.java:71)
           at javafx.scene.control.Control$12.set(Control.java:912)
           at com.sun.javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:59)
           at com.sun.javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:31)
           at com.sun.javafx.css.StyleableProperty.set(StyleableProperty.java:70)
           at com.sun.javafx.css.StyleHelper.transitionToState(StyleHelper.java:902)
           at javafx.scene.Node.impl_processCSS(Node.java:7415)
           at javafx.scene.Parent.impl_processCSS(Parent.java:1146)
           at javafx.scene.control.Control.impl_processCSS(Control.java:1102)
           at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1598)
           at com.sun.javafx.scene.control.skin.VirtualFlow.addTrailingCells(VirtualFlow.java:1114)
           at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1007)
           at javafx.scene.Parent.layout(Parent.java:1018)
           at javafx.scene.Parent.layout(Parent.java:1028)
           at javafx.scene.Parent.layout(Parent.java:1028)
           at javafx.scene.Parent.layout(Parent.java:1028)
           at javafx.scene.Scene.layoutDirtyRoots(Scene.java:513)
           at javafx.scene.Scene.doLayoutPass(Scene.java:484)
           at javafx.scene.Scene.preferredSize(Scene.java:1485)
           at javafx.scene.Scene.impl_preferredSize(Scene.java:1512)
           at javafx.stage.Window$10.invalidated(Window.java:719)
           at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:127)
           at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:161)
           at javafx.stage.Window.setShowing(Window.java:782)
           at javafx.stage.Window.show(Window.java:797)
           at javafx.stage.Stage.show(Stage.java:229)
           at fxmltableview.FXMLTableView.start(FXMLTableView.java:49)
           at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319)
           at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:206)
           at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:173)
           at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
           at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
           at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
           at java.lang.Thread.run(Thread.java:722)

      Cell factory

      /**
      *
      */
      package view.components;

      import javafx.scene.control.TableCell;
      import javafx.scene.control.TableColumn;
      import javafx.scene.control.cell.CheckBoxTableCell;
      import javafx.util.Callback;

      public class CheckBoxCellFactory<S, T>
      implements Callback<TableColumn<S, Boolean>, Callback<TableColumn<S, Boolean>, TableCell<S, Boolean>>> {

           public Callback<TableColumn<S, Boolean>, TableCell<S, Boolean>> call(TableColumn<S, Boolean> paramAnonymousTableColumn) {
                return CheckBoxTableCell.forTableColumn(paramAnonymousTableColumn);
           }


      }



      FXML


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

      <?import java.lang.*?>
      <?import java.net.*?>
      <?import java.util.*?>
      <?import javafx.util.*?>
      <?import javafx.collections.*?>
      <?import javafx.geometry.*?>
      <?import javafx.scene.control.*?>
      <?import javafx.scene.control.cell.*?>
      <?import javafx.scene.layout.*?>
      <?import javafx.scene.paint.*?>
      <?import javafx.scene.text.*?>
      <?import model.*?>
      <?import model.DummyTableValues?>
      <?scenebuilder-classpath-element ../bin?>
      <?import view.components.CheckBoxCellFactory?>

      <ScrollPane id="scrollPane" fx:id="scrollPane" minHeight="275.0" minWidth="771.0" prefHeight="275.0" prefWidth="771.0" xmlns:fx="http://javafx.com/fxml">
      <content>
      <TableView id="configTable" fx:id="configTable" minHeight="1000.0" minWidth="1000.0" prefHeight="1000.0" prefWidth="1000.0">
      <columns>
                <TableColumn id ="col1" fx:id="col1" prefWidth="75.0" text="Delete/Edit">
                     <cellValueFactory>
           <PropertyValueFactory property="value3" />
           </cellValueFactory>
                     <cellFactory>
                          <CheckBoxCellFactory></CheckBoxCellFactory>
                     </cellFactory>
                </TableColumn>
      <TableColumn prefWidth="75.0" text="Article Num">
      <cellValueFactory>
      <PropertyValueFactory property="value1" />
      </cellValueFactory>
      </TableColumn>
      <TableColumn prefWidth="75.0" text="Article Desc">
      <cellValueFactory>
      <PropertyValueFactory property="value2" />
      </cellValueFactory>
      </TableColumn>
      </columns>
      <items>
      <FXCollections fx:factory="observableArrayList">
      <DummyTableValues value1="Jacob1" value2="Smith1" />
      <DummyTableValues value1="Jacob2" value2="Smith2" />
      <DummyTableValues value1="Jacob3" value2="Smith3" />
      </FXCollections>
      </items>
      </TableView>
      </content>
      </ScrollPane>



      package model;

      import javafx.beans.property.SimpleBooleanProperty;
      import javafx.beans.property.SimpleStringProperty;


      public class DummyTableValues {
           private SimpleStringProperty value1 = new SimpleStringProperty("initial1");
           private SimpleStringProperty value2 = new SimpleStringProperty("initial2");
           private SimpleBooleanProperty value3 = new SimpleBooleanProperty(false);
           public void setValue1(String value1) {
                this.value1.set(value1);
           }
           
           public void setValue2(String value2) {
                this.value2.set(value2);
           }
           
           public String getValue1() {
                return value1.get();
           }
           
           public String getValue2() {
                return value2.get();
           }

           public boolean isValue3() {
                return value3.getValue();
           }

           public void setValue3(boolean value3) {
                this.value3.setValue(value3);
           }
           
      }
        • 1. Re: JFX fxml: custom cellfactory for CheckBoxTableCell throwing exception
          James_D
          The factory method CheckBoxTableCell.forTableColumn(...) returns a cell factory (i.e. a Callback<TableColumn, TableCell>), not a TableCell. So you want to set the cellFactory of your column to the result of CheckBoxTableCell.forTableColumn(...), not to a callback that returns one.

          I've not tried to do that directly in FXML, and it might be a bit tricky. Try:
          <TableColumn id ="col1" fx:id="col1" prefWidth="75.0" text="Delete/Edit">
           <cellValueFactory>
            <PropertyValueFactory property="value3" />
           </cellValueFactory>
           <cellFactory>
            <CheckBoxTableCell fx:factory="forTableColumn">
             <fx:reference source="col1"/>
            </CheckBoxTableCell>
           </cellFactory>
          </TableColumn>
          but you may have to do this in the controller.
          • 2. Re: JFX fxml: custom cellfactory for CheckBoxTableCell throwing exception
            James_D
            My previous code won't work: the fx:factory can only be used to provide a no-arg factory method.

            The only way I can see to make this work is to do something like
            package view.components;
            
            import javafx.scene.control.TableCell;
            import javafx.scene.control.TableColumn;
            import javafx.scene.control.cell.CheckBoxTableCell;
            import javafx.util.Callback;
            
            public class CheckBoxCellFactory<S, T> 
            implements Callback<TableColumn<S, Boolean>, Callback<TableColumn<S, Boolean>, TableCell<S, Boolean>>> {
            
              public Callback<TableColumn<S, Boolean>, TableCell<S, Boolean>> call(TableColumn<S, Boolean> paramAnonymousTableColumn) {
                return CheckBoxTableCell.forTableColumn(paramAnonymousTableColumn).call(paramAnonymousTableColumn);
              }
            }
            This calls CheckBoxTableCell.forTableColumn(...) every time it needs a new table cell. If you were doing this in Java, rather than FXML, you'd do
            col1.setCellFactory(CheckBoxTableCell.forTableColumn(col1));
            which creates the cell factory only once. I don't think this is a problem, but if it is you could do something more sophisticated in your CheckBoxCellFactory. (Maybe define a "column" property, which you can set from the FXML, and then define a private Callback which is bound to the column property, assigning it the result of CheckBoxTableCell.forTableColumn(...) when the column property changes.)
            • 3. Re: JFX fxml: custom cellfactory for CheckBoxTableCell throwing exception
              Retheesh
              Hi James,

              Thank you for the answer. I checked your last solution and is working.

              Edited by: 995890 on Mar 25, 2013 9:32 PM
              • 4. Re: JFX fxml: custom cellfactory for CheckBoxTableCell throwing exception
                James_D
                I thought the Callback implementation we provide will be executed somewhere in the FXLoader part to load the TableCell returned from the call method.
                No, the FXML loader instantiates objects. With a few exceptions, it doesn't invoke any methods.
                • 5. Re: JFX fxml: custom cellfactory for CheckBoxTableCell throwing exception
                  Retheesh
                  But to render the Table cell the call method of the CheckBoxCellFactory should get executed somewhere right.
                  The cellFactory may be using the Callback and calling the call method to render.

                  Actually my earlier doubt was not correct. I got my mistake.
                  I was setting a Callback to cellFactory as CheckBoxCellfactory and then again I was returning a Callback from the call method of CheckBoxCellFactory which was the problem.

                  Thank you,
                  Retheesh