ListView with ImageViews for cells very bugged?

Kevin Rushforth kevin.rushforth at oracle.com
Wed Jul 12 14:57:10 UTC 2023


The updateItem docs [1] already say this. I had missed that the test 
program didn't do this, so thanks to Ajit for pointing it out.

And yes, https://bugs.openjdk.org/browse/JDK-8090254 should be closed as 
not an issue with a reference to the doc bug that clarified this.

-- Kevin

[1] 
https://download.java.net/java/early_access/javafx21/docs/api/javafx.controls/javafx/scene/control/Cell.html#updateItem(T,boolean)

On 7/12/2023 7:50 AM, Andy Goryachev wrote:
>
> Ajit is right - perhaps javadoc for updateItem() should explicitly 
> mention this?
>
> Also, perhaps https://bugs.openjdk.org/browse/JDK-8090254 should be 
> closed - we recently updated javadoc to read
>
>
>       Warning: Nodes should not be inserted directly into the items list
>
> (this is a different issue altogether)
>
> -andy
>
> *From: *Ajit Ghaisas <ajit.ghaisas at oracle.com>
> *Date: *Wednesday, July 12, 2023 at 02:26
> *To: *John Hendrikx <john.hendrikx at gmail.com>
> *Cc: *openjfx-dev at openjdk.org <openjfx-dev at openjdk.org>, Andy 
> Goryachev <andy.goryachev at oracle.com>
> *Subject: *Re: ListView with ImageViews for cells very bugged?
>
> Hi John,
>
>  This looks like a user code issue and not a JavaFX bug.
>
>  Most of the vertical scrollbar issues that you have mentioned get 
> fixed by adding a call to "super.updateItem(image, empty);" as a first 
> call in the cell factory method "protected void updateItem(Image 
> image, boolean empty)”
>
> I am seeing an exception when I scroll fully down and then scroll up 
> by clicking empty area on the vertical scrollbar. This looks like a 
> separate issue though.
>
> Regards,
>
> Ajit
>
>
>
>     On 12-Jul-2023, at 5:18 AM, Andy Goryachev
>     <andy.goryachev at oracle.com> wrote:
>
>     Thank you for the code sample, John!
>
>     Had to replace loading from https:// to a local file://, but I do
>     see some of the issues you've mentioned (on macOS):
>
>     2), 5), and 6).
>
>     There is also a new issue:
>
>     7) when the top of the cell is outside of the view area, the image
>     is not shown at all (but the cell is sized correctly).
>
>     All this is indeed weird. Looks like the time is right to create a
>     bug, unless it's this one:
>
>     JDK-8090254 <https://bugs.openjdk.org/browse/JDK-8090254>
>
>     	
>
>     [ListView] page up/down navigation doesn't work, when items are
>     large (again!) <https://bugs.openjdk.org/browse/JDK-8090254>
>
>     -andy
>
>     *From:*openjfx-dev <openjfx-dev-retn at openjdk.org> on behalf of
>     John Hendrikx <john.hendrikx at gmail.com>
>     *Date:*Tuesday, July 11, 2023 at 16:34
>     *To:*openjfx-dev at openjdk.org <openjfx-dev at openjdk.org>
>     *Subject:*Re: ListView with ImageViews for cells very bugged?
>
>     I said I'd do it tomorrow, but here is a full example anyway with
>     pre-loaded images, and without external dependencies:
>
>     package org.int4.sdui.ui;
>
>     import javafx.application.Application;
>     import javafx.scene.Scene;
>     import javafx.scene.control.Button;
>     import javafx.scene.control.ListCell;
>     import javafx.scene.control.ListView;
>     import javafx.scene.control.TextArea;
>     import javafx.scene.image.Image;
>     import javafx.scene.image.ImageView;
>     import javafx.scene.layout.HBox;
>     import javafx.scene.layout.Priority;
>     import javafx.scene.layout.VBox;
>     import javafx.stage.Stage;
>
>     public class Main2 {
>
>       public static void main(String[] args) {
>         Application.launch(UI.class, args);
>       }
>
>       public static class UI extends Application {
>
>         @Override
>         public void start(Stage primaryStage) throws
>     InterruptedException {
>           Image image1 = new Image("https://picsum.photos/512/512"
>     <https://picsum.photos/512/512>);
>           Image image2 = new Image("https://picsum.photos/512/512"
>     <https://picsum.photos/512/512>);
>
>           TextArea prompt = new TextArea("a flower on Mars");
>           Button button = new Button("Submit");
>           ListView<Image> listView = new ListView<>();
>
>           while(image1.isBackgroundLoading() ||
>     image2.isBackgroundLoading()) {
>             Thread.sleep(100);
>           }
>
>           listView.getItems().addAll(image1, image2);
>           listView.setCellFactory(lv -> {
>             final ImageView imageView = new ImageView();
>
>             return new ListCell<>() {
>               protected void updateItem(Image image, boolean empty) {
>                 if(empty) {
>                   setGraphic(null);
>                 }
>                 else {
>                   imageView.setImage(image);
>                   setGraphic(imageView);
>                 }
>               }
>             };
>           });
>
>           HBox hbox = new HBox() {{
>             getChildren().addAll(
>               new VBox() {{
>                 getChildren().addAll(prompt, button);
>               }},
>               listView
>             );
>           }};
>
>           HBox.setHgrow(listView, Priority.ALWAYS);
>
>           Scene scene = new Scene(hbox);
>
>           primaryStage.setScene(scene);
>           primaryStage.show();
>         }
>       }
>     }
>
>
>
>
>
>     --John
>
>     On 12/07/2023 01:17, Andy Goryachev wrote:
>
>         I'll need to replicate this scenario to be able to say
>         anything definitive.
>
>         Just by looking at the cell factory code though, I suspect
>         there might be some async processing around
>
>         new ImageView(new Image(new
>         > ByteArrayInputStream(imageHandle.getImageData()))));
>
>         which might cause the issue.
>
>         Could you try pre-loading images?
>
>         -andy
>
>         *From:*openjfx-dev<openjfx-dev-retn at openjdk.org>
>         <mailto:openjfx-dev-retn at openjdk.org>on behalf of Kevin
>         Rushforth<kevin.rushforth at oracle.com>
>         <mailto:kevin.rushforth at oracle.com>
>         *Date:*Tuesday, July 11, 2023 at 15:58
>         *To:*openjfx-dev at openjdk.org<openjfx-dev at openjdk.org>
>         <mailto:openjfx-dev at openjdk.org>
>         *Subject:*Re: ListView with ImageViews for cells very bugged?
>
>         What you have should work, but will create redundant images and
>         ImageView ojbects. The recommendation is to create the nodes
>         (ImageView
>         in this case) in the constructor of the cell factory and call
>         setGraphic
>         with either null or that factory's node.
>
>         Having said that, I doubt that this is related to the visual
>         problems
>         you are seeing. Maybe Ajit or Andy have some ideas.
>
>         -- Kevin
>
>
>         On 7/11/2023 3:50 PM, John Hendrikx wrote:
>         > I tend to avoid ListView, because for some reason it seems
>         to just
>         > never do what I want unless used for its mundane rows of
>         text use
>         > case. I so far always just implemented my own skin for
>         ListView that
>         > deals with displays that have many images that need to scroll
>         > smoothly, but...
>         >
>         > Recently, I've again attempted to use ListView, this time
>         for showing
>         > (so far) fixed size ImageViews with images exactly 512x512
>         pixels in
>         > size:
>         >
>         > The cell factory looks like this, which I think is a correct
>         > implementation:
>         >
>         > listView.setCellFactory(lv -> {
>         >         return new ListCell<>() {
>         >           protected void updateItem(ImageHandle imageHandle,
>         boolean
>         > empty) {
>         >             if(empty) {
>         >               setGraphic(null);
>         >             }
>         >             else {
>         >               try {
>         >                 setGraphic(new ImageView(new Image(new
>         > ByteArrayInputStream(imageHandle.getImageData()))));
>         >               }
>         >               catch(IOException e) {
>         > e.printStackTrace();
>         >               }
>         >             }
>         >           }
>         >         };
>         >       });
>         >
>         > Now, this is with JavaFX 21-ea-24 (but also happens on 19).
>         I spotted
>         > the following IMHO bugs:
>         >
>         > 1) When the ImageView is so large that a single row is only
>         partially
>         > visible, the scrollbar is incorrect (it shows a full bar,
>         even if half
>         > of a row is displayed).
>         >
>         > 2) The vertical scrollbar doesn't respond to a click in the
>         non-thumb
>         > area at all (you'd expect to make it scroll a page up or
>         down that way)
>         >
>         > 3) When jerkily resizing the window, I can sometimes have a
>         vertical +
>         > horizontal scrollbar when there's a full row visible +
>         anywhere from 0
>         > to 10 extra empty pixels (probably the potential height of a
>         > horizontal scrollbar) with the vertical scroll bar still
>         visible. The
>         > algorithm to hide the scrollbar apparently is not
>         deterministic and
>         > depends on mouse movement speed.
>         >
>         > 4) When a row is less than half visible, scrolling the
>         window down to
>         > another ImageView will jump the view and hide the first cell
>         that
>         > should still be visible for the bottom 0-49% of its height.
>         >
>         > 5) It's possible to get the vertical scroll bar in such a
>         state that
>         > it doesn't respond to the mouse any more at all, even by
>         dragging the
>         > thumb.  Some keyboard action and mouse scrolling sometimes
>         restores it
>         > to relatively normal functioning.
>         >
>         > 6) Mouse wheel scrolling acts weird.  With one large cell
>         visible and
>         > two rows available, scrolling only **down** on the mouse
>         wheel will
>         > scroll down, then jump back up, and scroll down again... it's
>         > impossible to scroll all the way down to get to a point
>         where it stops
>         > scrolling as it keeps jumping back.
>         >
>         > This is with ImageView's.  I suppose they're known to have
>         problems...
>         > but then I switched to a Region, which contain an ImageView with
>         > proper min/pref/max implementations.  This improved the
>         situation
>         > somewhat.  The scrollbar was much more reliable, but I still saw
>         > almost all of the above issues, but somewhat more reliable than
>         > before.  Still rows would disappear when (for the most part)
>         > invisible, those and the jumps of the view are just totally
>         unacceptable.
>         >
>         > I'm not quite sure what to make of this, it seems the
>         control is not
>         > meant for arbitrary graphics.
>         >
>         > --John
>         >
>         >
>         >
>         > package org.int4.sdui.ui;
>         >
>         > import hs.mediasystem.util.image.ImageHandle;
>         > import hs.mediasystem.util.javafx.control.Containers;
>         >
>         > import java.io.ByteArrayInputStream;
>         > import java.io.IOException;
>         > import java.util.Base64;
>         > import java.util.List;
>         >
>         > import javafx.application.Application;
>         > import javafx.scene.Scene;
>         > import javafx.scene.control.Button;
>         > import javafx.scene.control.ListCell;
>         > import javafx.scene.control.ListView;
>         > import javafx.scene.control.TextArea;
>         > import javafx.scene.image.Image;
>         > import javafx.scene.image.ImageView;
>         > import javafx.scene.layout.HBox;
>         > import javafx.scene.layout.Priority;
>         > import javafx.stage.Stage;
>         >
>         > import kong.unirest.core.Unirest;
>         >
>         > public class Main {
>         >
>         >   public static void main(String[] args) {
>         > Application.launch(UI.class, args);
>         >   }
>         >
>         >   public static class UI extends Application {
>         >
>         >     @Override
>         >     public void start(Stage primaryStage) {
>         >       TextArea prompt = new TextArea("a flower on Mars");
>         >       Button button = new Button("Submit");
>         > ListView<ImageHandle> listView = new ListView<>();
>         >
>         > listView.setCellFactory(lv -> {
>         >         return new ListCell<>() {
>         >           protected void updateItem(ImageHandle imageHandle,
>         boolean
>         > empty) {
>         >             if(empty) {
>         >               setGraphic(null);
>         >             }
>         >             else {
>         >               try {
>         >                 setGraphic(new ImageView(new Image(new
>         > ByteArrayInputStream(imageHandle.getImageData()))));
>         >               }
>         >               catch(IOException e) {
>         > e.printStackTrace();
>         >               }
>         >             }
>         >           }
>         >         };
>         >       });
>         >
>         >       button.setOnAction(e -> {
>         >         Txt2ImgResponse response =
>         textToImage(prompt.getText());
>         >
>         >         for(String image : response.images) {
>         > listView.getItems().add(new
>         > InMemoryImageHandle(Base64.getDecoder().decode(image)));
>         >         }
>         >       });
>         >
>         >       HBox hbox = Containers.hbox(Containers.vbox(prompt,
>         button),
>         > listView);
>         >
>         >       HBox.setHgrow(listView, Priority.ALWAYS);
>         >
>         >       Scene scene = new Scene(hbox);
>         >
>         > primaryStage.setScene(scene);
>         >       primaryStage.show();
>         >     }
>         >
>         >     private Txt2ImgResponse textToImage(String prompt) {
>         >       return
>         Unirest.post("http://127.0.0.1:7860/sdapi/v1/txt2img")
>         >         .body(new Txt2Img(prompt, 5))
>         > .contentType("application/json")
>         > .asObject(Txt2ImgResponse.class)
>         >         .getBody();
>         >     }
>         >   }
>         >
>         >   static class InMemoryImageHandle implements ImageHandle {
>         >     private final byte[] data;
>         >
>         >     public InMemoryImageHandle(byte[] data) {
>         >       this.data = data;
>         >     }
>         >
>         >     @Override
>         >     public byte[] getImageData() {
>         >       return data;
>         >     }
>         >
>         >     @Override
>         >     public String getKey() {
>         >       return null;
>         >     }
>         >
>         >     @Override
>         >     public boolean isFastSource() {
>         >       return true;
>         >     }
>         >   }
>         >
>         >   record Txt2Img(String prompt, int steps) {}
>         >   record Txt2ImgResponse(List<String> images) {}
>         > }
>         >
>         >
>         >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20230712/5e78b7c1/attachment-0001.htm>


More information about the openjfx-dev mailing list