ListView with ImageViews for cells very bugged?

John Hendrikx john.hendrikx at gmail.com
Tue Jul 11 23:33:33 UTC 2023


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");
       Image image2 = new Image("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> on behalf of Kevin 
> Rushforth <kevin.rushforth at oracle.com>
> *Date: *Tuesday, July 11, 2023 at 15:58
> *To: *openjfx-dev at openjdk.org <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/ded91026/attachment-0001.htm>


More information about the openjfx-dev mailing list