2016-09-29 3 views
1

Когда я просматриваю вверх и вниз в TableView JavaFX8, все больше и больше ячеек становятся неправомерно раскрашенными. Это означает, что css-псевдо-класс «заполняется» запускается, хотя ячейка должна быть пустой. Я не могу понять, связана ли связанная с ними cellValueFactory, или если где-то есть ошибка.JavaFX TableView триггеры css ": filled" -Pseudo-class onScrolling

this is how it looks after scrolling a while

.css

error-cell:filled { 
    -fx-background-color: #ff3333; 
    -fx-text-fill: white; 
    -fx-opacity: 1; 
} 

.fxml

<BorderPane fx:id="projectList" stylesheets="@../css/projectList.css,@../css/tables.css" xmlns="http://javafx.com/javafx/8.0.45" xmlns:fx="http://javafx.com/fxml/1" fx:controller="my.package.ProjectListController"> 
    <center> 
     <TableView fx:id="projectListTableView"> 
      <columnResizePolicy> 
       <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> 
      </columnResizePolicy> 
      <columns> 

       <TableColumn fx:id="errorCol" styleClass="error-cell" text="Error"> 
        <cellValueFactory> 
         <PropertyValueFactory property="error" /> 
        </cellValueFactory> 
       </TableColumn> 

      </columns> 
     </TableView> 
    </center> 
</BorderPane> 

.java

public class ProjectListController 
{ 
    @FXML 
    private TableView<ProjectWrapper> projectListTableView; 

    @FXML 
    private TableColumn<ProjectWrapper, String> errorCol; 

    private ObservableList<ProjectWrapper> projectTable = FXCollections.observableArrayList(); 

    // dummy-method that fills projectTable, normally it's a db-query 
    public void fillErrorColumn() 
    { 
     ProjectWrapper pw = new ProjectWrapper(); 
     pw.setError("1/0/0"); 
     this.projectTable.add(pw); 
    } 


    public void populateTable() 
    { 
     try 
     { 
      projectListTableView.setItems(this.projectTable); 
     } 
     catch (Exception e) 
     { 
      logger.error("", e); 
     } 
    } 

} 

Может кто-нибудь из вас думать о причине, что вызывает такое поведение? Или способ гарантировать, что ячейки остаются пустыми во время прокрутки?


Btw, я предпочел бы не установить дополнительную cellValueFactory, потому что есть слишком много подобных показателей. Я также пробовал это напрасно - что означает тот же результат.

private void setCellFactoryErrorCol() 
{ 
    errorCol.setCellFactory(column -> 
    { 
     return new TableCell<ProjectWrapper, String>() 
     { 
      @Override 
      protected void updateItem(String item, boolean empty) 
      { 
       super.updateItem(item, empty); 

       if (item != null && item.length() > 2) 
       { 
        setText(item); // ohne setText() bleibt das Feld 
            // leer - wird nicht automatisch von 
            // super gesetzt 
        getStyleClass().add("error-cell"); 
        setTooltip(new Tooltip("All/In work/Fixed")); 
       } 
       else 
       { 
        setText(null); 
        setStyle(""); 
       } 
      } 
     }; 
    }); 
} 

спасибо!


Edit 1 Я мог бы решить мою проблему с помощью кода от ответа "James_D" S'. Хотя я бы скорее использовал CSS.


Edit 2 Чтобы минимизировать LOC и повысить общую ремонтопригодность, я создал utilityClass, что я называю во время инициализации контроллеров.

public class CellFactoryUtil 
{ 

    public <E> void setCellFactoryStringErrorCol(TableColumn<E, String> errorCol) 
    { 
     PseudoClass errorPC = PseudoClass.getPseudoClass("error-pc"); 

     errorCol.setCellFactory(column -> new TableCell<E, String>() 
      { 
       @Override 
       protected void updateItem(String item, boolean empty) 
       { 
        super.updateItem(item, empty); 

        if (item != null && item.length() > 2) 
        { 
         setText(item); 
         pseudoClassStateChanged(errorPC, true); 
         setTooltip(new Tooltip("All/In work/Fixed")); 
        } 
        else 
        { 
         setText(null); 
         pseudoClassStateChanged(errorPC, false); 
        } 
       } 
      } 
     ); 
    } 
} 

Я использую generics, потому что программа имеет несколько таблиц с различными обертками. Все еще много кода, но все работает отлично!

+0

Ну, вы все еще используете CSS с моим решением, нет? И у вас есть дополнительные функции на фабрике ячеек, которые невозможно реализовать без фабрики ячеек (подсказка, а не отображение значений длиной <= 2), поэтому вам уже нужна фабрика ячеек. Не совсем уверен, что бы вы предпочли сделать. –

ответ

0

Для CSS вы применяете класс стиля к TableColumn: на самом деле не совсем ясно, как это будет работать. В документе JavaFX CSS guide отсутствует документация для TableColumn. Способ сделать это с фабрикой ячеек.

Обратите внимание, что :filled pseudoclass просто противоположность :empty: т.е. это верно для всех ячеек, кроме пустых «пространства наполнителя» клеток, которые находятся в таблице, но под строки, которые на самом деле есть данные. :filled должен быть true для всех ячеек, которые имеют данные в строках, даже если данные ячейки null (и, конечно, если данные ячейки являются пустой строкой).

В реализации фабрики вашей ячейки вы никогда не удаляете класс стиля "error-cell" из списка классов стилей. Более того, при прокрутке вы, вероятно, добавите несколько копий строки "error-cell" в список классов стилей (потенциально вызывающих утечку памяти).

Вам нужно что-то вроде

errorCol.setCellFactory(column -> 
{ 
    return new TableCell<ProjectWrapper, String>() 
    { 
     @Override 
     protected void updateItem(String item, boolean empty) 
     { 
      super.updateItem(item, empty); 

      if (item != null && item.length() > 2) 
      { 
       setText(item); // ohne setText() bleibt das Feld 
           // leer - wird nicht automatisch von 
           // super gesetzt 
       if (! getStyleClass().contains("error-cell")) { 
        getStyleClass().add("error-cell"); 
       } 
       setTooltip(new Tooltip("All/In work/Fixed")); 
      } 
      else 
      { 
       setText(null); 
       setStyle(""); // not sure this line does anything: you never set the style anyway... 
       getStyleClass().remove("error-cell"); 
      } 
     } 
    }; 
}); 

Обратите внимание, что это может быть чище, чтобы создать свой собственный pseudoclass для этого, вместо того, чтобы манипулировать класс стиля:

PseudoClass errorPC = PseudoClass.getPseudoClass("error"); 

errorCol.setCellFactory(column -> new TableCell<ProjectWrapper, String>() { 

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

     if (item != null && item.length() > 2) 
     { 
      setText(item); // ohne setText() bleibt das Feld 
          // leer - wird nicht automatisch von 
          // super gesetzt 
      pseudoClassStateChanged(errorPC, true); 
      setTooltip(new Tooltip("All/In work/Fixed")); 
     } 
     else 
     { 
      setText(null); 
      pseudoClassStateChanged(errorPC, false); 
     } 
    } 

}); 

и затем CSS выглядит

.table-cell:error { 
    -fx-background-color: #ff3333; 
    -fx-text-fill: white; 
    -fx-opacity: 1; 
} 
+0

Спасибо за ваш ответ. Он мне очень помог! –

+0

См. Обновление для немного более чистого подхода. –

+0

Ваше обновление отлично работает! Еще раз спасибо за быстрый и глубокий ответ. –