2016-06-07 2 views
0

javafx를 처음 사용합니다. CheckBoxTableCell을 표시하려고하지만 항상 Datamodel을 무시하고 선택을 취소합니다.javafx CheckBoxTableCell은 항상 선택 취소되었습니다.

@SuppressWarnings("unchecked") 
private static <S, T> TableColumn<S, T> createTableColumn(Class<T> type, String fieldName, String index, String columnHeader) { 
    TableColumn<S, T> col = new TableColumn<S, T>(columnHeader); 
    col.setCellValueFactory(cellData -> { 
     try { 
      Object o = ReflectionUtils.getValue(fieldName, cellData.getValue()); 
      // Erzeuge eine Property, die das Attribut enthält 
      SimpleObjectProperty<T> property = new SimpleObjectProperty<T>((T) o); 
      return property; 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    }); 
    if (type.equals(Boolean.TYPE)) 
     ((TableColumn<S, Boolean>) col).setCellFactory(CheckBoxTableCell.forTableColumn((TableColumn<S, Boolean>) col)); 

    col.setId(index); 
    return col; 
} 

내가 CheckBoxTableCell에 보니

public static <S> Callback<TableColumn<S,Boolean>, TableCell<S,Boolean>> forTableColumn(
     final TableColumn<S, Boolean> column) { 
    return forTableColumn(null, null); 
} 

에 내가 변환을 사용하고있는 factoryFunction 그래서 난이 기능이 작동하지 않는 이유를 알고하지만 난 잘 모릅니다 것으로 나타났습니다 : 그건 내가 열을 생성하는 방법이다 어떤 방법으로 지금 사용하십시오. 도와 주시면 감사하겠습니다.

최소한의 실행 예 : 내 TableGenerator :

package company.viewfx.tables; 

import java.lang.reflect.Field; 
import java.util.ArrayList; 
import java.util.Comparator; 
import java.util.List; 

import org.apache.commons.beanutils.BeanUtilsBean; 

import company.viewfx.annotations.AsTableColumn; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.collections.ObservableList; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.cell.CheckBoxTableCell; 
import lombok.Setter; 
import lombok.extern.log4j.Log4j2; 

/** 
*   Wrapperklasse, die die Benutzung des JavaFX TableView erleichtern soll 
* @param <S> Die Klasse, die in der Tabelle dargestellt werden soll 
*/ 
@Log4j2 
public class GTableView<S> extends TableView<S> { 
    /** 
    * Enthält eine Listen von Attributen aus <S> die in der Tabelle dargestellt werden sollen (optional) 
    */ 
    @Setter 
    private String[] attributes = new String[0]; 
    /** 
    * Die Klasse die dargestellt werden soll 
    */ 
    private Class<S> clazz; 

    /** 
    * @param clazz Die Klasse die dargestellt werden soll 
    * @param items eine ObservableList<S> von Datenelementen 
    */ 
    public GTableView(Class<S> clazz, ObservableList<S> items) { 
     super(items); 
     this.clazz = clazz; 
     initialize(); 
    } 

    /** 
    * Fügt die Spalten + Überschrift und Inhalt zu der rohen Tabelle hinzu 
    */ 
    private void initialize() { 
     getColumns().addAll(process(attributes, "", "", this.clazz)); 
     // Spalten nach Id sortieren 
     getColumns().sort(new Comparator<TableColumn<S, ?>>() { 
      @Override 
      public int compare(TableColumn<S, ?> o1, TableColumn<S, ?> o2) { 
       return o1.getId().compareTo(o2.getId()); 
      } 
     }); 
    } 

    /** 
    * Process the model class. 
    * For the fields declared which have annotation AsTableColumn, create a TableColumn<T,S> 
    * instance for it with the detected field type. 
    * 
    * @param attrList Eine Liste mit Attributen die angezeigt werden sollen (kann auch null sein, dann standard) 
    * @param containerName Entscheidet in welchem Komplexen Attribut nach den Spalten gesucht wird 
    * @param containerIndex Der index des entsprechenden Wurzelobjektes 
    * @param clazz Die Klasse des Attributes, das in dieser Spalte dargestellt werden soll 
    * @return Eine Listen von TableColumns für die mit @AsColumn in this.clazz markierten Attribute 
    */ 
    public static <S> List<TableColumn<S, ? extends Object>> process(String[] attrList, String containerName, String containerIndex, 
      Class<?> clazz) { 
     // Der Rückgabenwert 
     List<TableColumn<S, ? extends Object>> columns = new ArrayList<>(); 
     // Wenn der Index nicht leer ist hänge einen Punkt an 
     containerIndex += !containerIndex.equals("") ? "." : ""; 
     // Wenn der ContainerName nicht leer ist hänge einen Punkt an 
     containerName += !containerName.equals("") ? "." : ""; 
     // Wenn die StandardSpalten verwendet werden sollen 
     if (attrList.length == 0) { 
      // gehe erst alle Felder durch 
      for (Field field : clazz.getDeclaredFields()) { 
       // Wenn das Attribut als Feld angezeigt werden soll 
       if (field.isAnnotationPresent(AsTableColumn.class)) { 
        AsTableColumn anno = field.getAnnotation(AsTableColumn.class); 
        columns.add(createTableColumn(field.getType(), containerName + field.getName(), containerIndex + anno.index(), 
          anno.text())); 
       } 
      } 
     } 
     return columns; 
    } 

    /** 
    * @param type Der Typ des Attributes, das in der Spalte stehen soll 
    * @param fieldName Das Attribut, das in dieser Spalte dargestellt werden soll 
    * @param columnHeader Die Spaltenüberschrift 
    * @param index Der index der Spalte (entscheidet über ihre Reihenfolge) 
    * @return TableColumn 
    */ 
    // Das ist hier erlaubt da immer eine Typprüfung mit type.equals durchgeführt wird 
    @SuppressWarnings("unchecked") 
    private static <S, T> TableColumn<S, T> createTableColumn(Class<T> type, String fieldName, String index, String columnHeader) { 
     TableColumn<S, T> col = new TableColumn<S, T>(columnHeader); 
     col.setCellValueFactory(cellData -> { 
      try { 
       Object o = null; 
       try { 
        o = BeanUtilsBean.getInstance().getPropertyUtils().getNestedProperty(o, fieldName); 
       } catch (Exception e) { 
        log.warn(String.format("Can not reach attribute %s in %s", fieldName, cellData.getValue()), e); 
       } 
       // Erzeuge eine Property, die das Attribut enthält 
       SimpleObjectProperty<T> property = new SimpleObjectProperty<T>((T) o); 
       return property; 
      } catch (Exception e) { 
       throw new RuntimeException(e); 
      } 
     }); 
     if (type.equals(Boolean.TYPE)) 
      ((TableColumn<S, Boolean>) col).setCellFactory(CheckBoxTableCell.forTableColumn((TableColumn<S, Boolean>) col)); 
     col.setId(index); 
     return col; 
    } 
} 

주석

package company.viewfx.annotations; 

import java.lang.annotation.Retention; 
import java.lang.annotation.Target; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.RetentionPolicy; 

    @Retention(RetentionPolicy.RUNTIME) 
    @Target({ElementType.FIELD,ElementType.METHOD}) 
    /** 
    * Mit dieser Annotation markierte Attribute werden in GTableView automatisch angezeigt, sofern keine anders lautenden 
    * Parameter übergeben werden. 
    * 
    */ 
    public @interface AsTableColumn { 
     /** 
     * @return Die Überschrift, die im Spaltenkopf angezeigt werden soll 
     */ 
     String text() default ""; 

     /** 
     * @return Die Stelle an der Die Spalte stehen soll 
     */ 
     int index() default Integer.MAX_VALUE; 
    } 

TestDataModel :

package company.viewfx.tables.demo; 

import company.viewfx.annotations.AsTableColumn; 
import lombok.AllArgsConstructor; 
import lombok.Getter; 
import lombok.Setter; 

@SuppressWarnings("javadoc") 
@AllArgsConstructor 
public class Person { 
@Getter 
@Setter 
@AsTableColumn(index=1,text="Alive") 
private boolean alive; 
} 

TestApplication :

package company.viewfx.tables.demo; 

import company.viewfx.tables.GTableView; 
import javafx.application.Application; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.scene.Scene; 
import javafx.stage.Stage; 

/** 
*   Dient der Vorführung dem Test von GTabelView 
*/ 
public class TableTest extends Application { 

    @Override 
    public void start(Stage stage) throws Exception { 
     // initialize Testdata 
     ObservableList<Person> data = FXCollections.observableArrayList(
       new Person(true), 
       new Person(false)); 
     stage.setScene(new Scene(new GTableView<Person>(Person.class, data))); 
     stage.show(); 
    } 

    @SuppressWarnings("javadoc") 
    public static void main(String[] args) { 
     launch(args); 
    } 
} 

build.gradle

apply plugin: 'java' 

// In this section you declare where to find the dependencies of your project 
repositories { 
    jcenter() 
} 

configurations { 
    provided { 
     dependencies.all { dep -> 
      configurations.default.exclude group: dep.group, module: dep.name 
     } 
    } 
    compile.extendsFrom provided 
} 

// In this section you declare the dependencies for your production and test code 
dependencies { 
    compile 'org.slf4j:slf4j-api:1.7.12' 
    provided 'org.projectlombok:lombok:1.12.6' 
    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.6' 
    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.6' 
    compile group: 'commons-beanutils', name: 'commons-beanutils', version: '1.8.3' 
    compile 'org.apache.commons:commons-lang3:3.4' 
    compile group: 'org.springframework', name: 'spring-core', version: '2.5.6' 
    compile group: 'org.eclipse.osgi', name: 'org.eclipse.osgi', version: '3.7.1' 
    testCompile 'junit:junit:4.12' 
} 
+0

셀 값 팩토리가 호출 될 때마다 새로운'ObjectProperty'가 생성됩니다. 데이터 모델의 값을 변경하면 해당 객체 속성 값이 변경되지 않습니다. 모델에 직접 정의 된'ObjectProperty'를 참조하려면 셀 값 팩토리가 필요합니다. –

+0

@James_D 데이터가 변경 될 때마다 나에게 아무런 문제가되지 않으며 DB에서 검색되어 완전히 대체되지만 변경되지 않습니다. 새 정의 된 ObjectProperty에 대해서도 확인란이 선택되어 표시되거나 누락되었습니다. –

+1

귀하의 질문에 [MCVE] –

답변

0

FXML 사용자는 체크 박스를 렌더링하기 위해 추가 열로 사용.

<TableColumn text="Married" fx:id="married"> 
<cellValueFactory> 
    <PropertyValueFactory property="married" /> 
</cellValueFactory> 
</TableColumn> 
<fx:script> 
var myCellValue = javafx.scene.control.cell.CheckBoxTableCell.forTableColumn(married); 
married.setCellFactory(myCellValue); 
</fx:script> 

//Your data model should be exposed as below. 
private final SimpleBooleanProperty married = new SimpleBooleanProperty(false); 
public SimpleBooleanProperty marriedProperty(){ 
    return married; 
} 
관련 문제