<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>It's a bit hard to say if this is a bug or not.</p>
    <p>I think this happens any time when children are added during
      layout. Most controls will avoid doing this, but when Cells are
      involved, there is another layer of indirection. I think the View
      classes manage their cells during layout, and since Cells can be
      newly created or the Cells are modified in ways that would trigger
      a child to be added/removed, then this effectively is changing the
      children list during layout.</p>
    <p>For example, Labels, when you add a graphic, immediately update
      their children list to include the graphic. Normally, calling
      `setGraphic` is not done by you during layout but in an event
      listener or during creation of the control.  However, when it is
      called in `Cell#updateItem` then layout is running, and the Label
      will change its children list when it notices the graphic
      changed.  This new child won't have CSS applied yet.</p>
    <p>I couldn't find documentation that says you shouldn't add/remove
      children during layout, but I'm pretty sure this is standard
      practice.</p>
    <p>The View controls may or may not be creating cells during layout,
      but they are almost certain to call `updateItem` on cells during
      layout. I'm not certain if this could be avoided in a similar
      fashion as I've done for my own ListView skin (using the pulse
      listener); if it can be, then this could be a bug fix.  If it
      can't, then I think `Cell#updateItem` should mention that the call
      should not modify the children list directly or indirectly.</p>
    <p>As I pointed out in my other reply, you may be able to set a
      dummy graphic on all cells, and just hide it when it is not
      needed.<br>
    </p>
    <p>--John<br>
    </p>
    On 22/02/2023 02:26, Scott Palmer wrote:<br>
    <blockquote type="cite"
cite="mid:CAL3e5iG2EzJOCZspGNQyWtS2uEz9bgpZw8Xr2JTuNz6N2cZ_4w@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="ltr">
        <div class="gmail_default" style="font-family:arial,sans-serif">Well
          I managed to work around it by placing the applyCss() call on
          the Cell itself, rather than the Shape node that I was
          styling.  I'm still not sure if I'm doing something wrong, if
          this is just how it's done and the applyCss() call is the
          correct thing to do for this case, or if this should be
          considered a bug.</div>
        <div class="gmail_default" style="font-family:arial,sans-serif"><br>
        </div>
        <div class="gmail_default" style="font-family:arial,sans-serif">Scott</div>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Tue, Feb 21, 2023 at 7:37
          PM Scott Palmer <<a href="mailto:swpalmer@gmail.com"
            moz-do-not-send="true" class="moz-txt-link-freetext">swpalmer@gmail.com</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
          <div dir="ltr">
            <div class="gmail_default"
              style="font-family:arial,sans-serif">I agree, this seems
              like it could be the same issue.  Could you give me a
              little more context as to how this code works? I'm not
              implementing my own skin (maybe I should, I've never tried
              that before).  Is this something I can trigger without a
              custom skin?</div>
            <div class="gmail_default"
              style="font-family:arial,sans-serif"><br>
            </div>
            <div class="gmail_default"
              style="font-family:arial,sans-serif">Regards,</div>
            <div class="gmail_default"
              style="font-family:arial,sans-serif"><br>
            </div>
            <div class="gmail_default"
              style="font-family:arial,sans-serif">Scott.</div>
          </div>
          <br>
          <div class="gmail_quote">
            <div dir="ltr" class="gmail_attr">On Tue, Feb 21, 2023 at
              12:01 PM John Hendrikx <<a
                href="mailto:john.hendrikx@gmail.com" target="_blank"
                moz-do-not-send="true" class="moz-txt-link-freetext">john.hendrikx@gmail.com</a>>
              wrote:<br>
            </div>
            <blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
              <div>
                <p>I've run into something similar, maybe even the same
                  issue.</p>
                <p>My issue was that modifying the list of cell children
                  (in a Skin for ListView) caused a 1 frame white
                  flicker (my application is black, so it was annoying)
                  because no CSS was applied yet to those newly added
                  children.  This occured when the ListView first only
                  had a few children and wasn't completely filled, and
                  then switching to a list which required more cells to
                  be created. I couldn't find a "correct" place to
                  modify the list of children that would avoid the
                  flicker (layoutChildren/computePrefWidth are places I
                  tried).</p>
                <p>In the end I did this, and added a comment to remind
                  me why the hack was there:</p>
                <p>    /*<br>
                       * A pre-layout pulse listener is added to the
                  current Scene to manage the<br>
                       * cells before the CSS pass occurs (this could
                  also be done with an AnimationTimer).<br>
                       *<br>
                       * If cells are not managed before the CSS pass,
                  new cells will be rendered for<br>
                       * one frame without CSS applied. This results in
                  a visual artifact (a white flash<br>
                       * for example if the background is supposed to be
                  dark, while white is the default<br>
                       * color without any CSS applied).<br>
                       */<br>
                      private final Runnable pulseListener = () -> {<br>
                        int lines = vertical ? visibleColumns.get() :
                  visibleRows.get();<br>
                        int firstIndex = (int)(scrollPosition.get()) *
                  lines;<br>
                    <br>
                        content.manageCells(firstIndex);<br>
                      };</p>
                <p>Now, the reason I think this may be same issue is
                  that you're also doing a modification of the children
                  list during layout: setting the graphic is sort of
                  equivalent to label.getChildren().add(graphic)<br>
                </p>
                <p>--John<br>
                </p>
                <div>On 20/02/2023 20:58, Scott Palmer wrote:<br>
                </div>
                <blockquote type="cite">
                  <div dir="ltr">
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif">I'm seeing an
                      odd issue with using CSS to colour a Shape when I
                      have it as a child of a TextFlow.</div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif"><br>
                    </div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif">My use case
                      is a "rich" text Cell in a tree or list.  I want
                      to have the text portion in multiple colours and
                      so instead of using the graphic and text parts of
                      a typical Cell, I'm using only the Graphic and
                      setting it to a TextFlow to get the text colours.
                      This means that I lose the ability to set a
                      graphic independen to the text, and so the
                      graphic is also added to the TextFlow.</div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif"><br>
                    </div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif">To style the
                      graphics, which are made of simple shapes, I'm
                      using CSS.  It makes it easy to adapt the colours
                      for when a cell is selected etc.  What I've
                      noticed is that as the cell selection moves around
                      the Shape component of the TextFlow flickers, as
                      if it is drawn first using default colours and
                      then the CSS is applied afterward.  I
                      tried working around this by explicitly calling
                      applyCss() on the Shape from the Cell's update
                      method, but it did not help.  If I explicitly set
                      the Stroke and Fill via the Shape API the
                      flickering does not occur.  If I use CSS, but set
                      the Shape as the Cell's graphic and resort to only
                      having plain text, there is no flickering.</div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif"><br>
                    </div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif">A test
                      program that demonstrates this is below.</div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif"><br>
                    </div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif">Bug or known
                      limitation?</div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif"><br>
                    </div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif">Scott</div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif">------------------------------------</div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif">package bugs;<br>
                      <br>
                      import javafx.application.Application;<br>
                      import javafx.geometry.Insets;<br>
                      import javafx.scene.Node;<br>
                      import javafx.scene.Scene;<br>
                      import javafx.scene.control.CheckBox;<br>
                      import javafx.scene.control.ContentDisplay;<br>
                      import javafx.scene.control.Label;<br>
                      import javafx.scene.control.ListCell;<br>
                      import javafx.scene.control.ListView;<br>
                      import javafx.scene.control.Tab;<br>
                      import javafx.scene.control.TabPane;<br>
                      import javafx.scene.layout.HBox;<br>
                      import javafx.scene.layout.VBox;<br>
                      import javafx.scene.paint.Color;<br>
                      import javafx.scene.shape.Circle;<br>
                      import javafx.scene.shape.Rectangle;<br>
                      import javafx.scene.shape.Shape;<br>
                      import javafx.scene.text.Text;<br>
                      import javafx.scene.text.TextFlow;<br>
                      import javafx.stage.Stage;<br>
                      <br>
                      <br>
                      public class CSSFlickerInTextFlow extends
                      Application {<br>
                      <br>
                          public static void main(String[] args) {<br>
                              launch(args);<br>
                          }<br>
                      <br>
                          private CheckBox onlyCssCB;<br>
                      <br>
                          @Override<br>
                          public void start(Stage stage) throws
                      Exception {<br>
                              ListView<String> list1 = new
                      ListView<>();<br>
                              ListView<String> list2 = new
                      ListView<>();<br>
                              var items1 = list1.getItems();<br>
                              var items2 = list2.getItems();<br>
                              for (int i = 1; i < 23; i++) {<br>
                                  var x = "Item #"+i;<br>
                                  items1.add(x);<br>
                                  items2.add(x);<br>
                              }<br>
                              list1.setCellFactory(t -> new
                      MyCell1());<br>
                              list2.setCellFactory(t -> new
                      MyCell2());<br>
                      <br>
                              onlyCssCB = new CheckBox("Use only CSS
                      (shapes will flicker in TextFlow)");<br>
                              HBox buttons = new HBox(8, onlyCssCB);<br>
                              buttons.setPadding(new Insets(4));<br>
                      <br>
                              Tab custom = new Tab("Everything in
                      Graphic", list1);<br>
                              Tab withoutColoredText = new Tab("Graphic
                      + Text", list2);<br>
                              TabPane tabs = new TabPane(custom,
                      withoutColoredText);<br>
                      <br>
                              VBox root = new VBox(<br>
                                      new Label("""<br>
                                                Focus in list, cursor up
                      and down, pay attention to the circle.<br>
                                                Try the same with the
                      box checked - circle flickers.<br>
                                                Doesn't happen when not
                      using the TextFlow.<br>
                                                """),<br>
                                      buttons, tabs);<br>
                              root.setPadding(new Insets(4));<br>
                              var scene = new Scene(root);<br>
                              stage.setScene(scene);<br>
                              stage.setTitle("Flickering with CSS in
                      TextFlow");<br>
                              stage.show();<br>
                          }<br>
                      <br>
                          private Shape makeGraphic() {<br>
                              Shape graphic = new Circle(6);<br>
                              if (!onlyCssCB.isSelected()) {<br>
                                  graphic.setFill(Color.SALMON); // CSS
                      overrides these but causes flickering if not the
                      same<br>
                                  graphic.setStroke(Color.BLACK);<br>
                              }<br>
                              graphic.setStyle("-fx-fill: salmon;
                      -fx-stroke: black;");<br>
                              return graphic;<br>
                          }<br>
                      <br>
                          class MyCell1 extends ListCell<String> {<br>
                      <br>
                              @Override<br>
                              protected void updateItem(String item,
                      boolean empty) {<br>
                                  super.updateItem(item, empty);<br>
                                 
                      setContentDisplay(ContentDisplay.GRAPHIC_ONLY);<br>
                                  setText(null);<br>
                                  if (!empty && item != null) {<br>
                                      TextFlow flow = new TextFlow();<br>
                                      Shape graphic = makeGraphic();<br>
                                      graphic.setTranslateY(2);<br>
                                      var nodeList = flow.getChildren();<br>
                                      Text name = new Text(item + " :
                      ");<br>
                                      name.setStyle("-fx-fill:
                      -fx-text-background-color;");<br>
                                      Text extra = new Text("with
                      Color");<br>
                                     
                      extra.setStyle("-fx-fill:ladder(-fx-background,
                      white 49%, salmon 50%);");<br>
                                      nodeList.add(graphic);<br>
                                      nodeList.add(new Rectangle(4,0));
                      // gap<br>
                                      nodeList.add(name);<br>
                                      nodeList.add(extra);<br>
                                      setGraphic(flow);<br>
                                  } else {<br>
                                      setGraphic(null);<br>
                                  }<br>
                              }<br>
                          }<br>
                      <br>
                          class MyCell2 extends ListCell<String> {<br>
                              @Override<br>
                              protected void updateItem(String item,
                      boolean empty) {<br>
                                  super.updateItem(item, empty);<br>
                                  if (!empty && item != null) {<br>
                                      setGraphic(makeGraphic());<br>
                                      setText(item);<br>
                                  } else {<br>
                                      setText(null);<br>
                                      setGraphic(null);<br>
                                  }<br>
                              }<br>
                          }<br>
                      }<br>
                    </div>
                    <div class="gmail_default"
                      style="font-family:arial,sans-serif"><br>
                    </div>
                  </div>
                </blockquote>
              </div>
            </blockquote>
          </div>
        </blockquote>
      </div>
    </blockquote>
  </body>
</html>