ListView with ImageViews for cells very bugged?
John Hendrikx
john.hendrikx at gmail.com
Tue Jul 11 23:22:15 UTC 2023
It's not the most efficient code for sure, as so far its bare bones
seeing if the app works at all. I already updated it a bit, adding the
ImageView as a field of the cell factory, but it made little
difference. I'll work up a full example tomorrow with pre-loaded images
and everything (and without my util helpers) so others can try.
--John
On 12/07/2023 00:58, Kevin Rushforth wrote:
> 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) {}
>> }
>>
>>
>>
>
More information about the openjfx-dev
mailing list