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