FXMisc/Flowless

Can't Get Clicked Item in List

newtingz opened this issue · 27 comments

I Have A Virtual ScrollPane
Displays All I want, except I cant Click Any Items.
Ima Currently Using Gridpane as the node in virtual flow,is that the way to Go ?
Screenshot (1505)

Jugen commented

If you want to know which item/row was clicked in the list you can try:

flow.setOnMouseClicked( ME ->
{
    VirtualFlowHit<Cell<AudioParser,?>> hit = flow.hit( ME.getX(), ME.getY() );
    int row = hit.getCellIndex();
} );

If you want to know which item/row was clicked in the list you can try:

flow.setOnMouseClicked( ME ->
{
    VirtualFlowHit<Cell<AudioParser,?>> hit = flow.hit( ME.getX(), ME.getY() );
    int row = hit.getCellIndex();
} );

Thanks, Btw
Solved The Problem, expect More
Lol

If you want to know which item/row was clicked in the list you can try:

flow.setOnMouseClicked( ME ->
{
    VirtualFlowHit<Cell<AudioParser,?>> hit = flow.hit( ME.getX(), ME.getY() );
    int row = hit.getCellIndex();
} );

Hey, didn't want to open a new issue
however,I'm trying to access Data from a From a cell so i Put the Data into a Node(as I
cant access the cell and its class like a listview,Idk how to do it in virtual listview), since I'm failing to reproduce the listview effect of getselecteditem.(custom class function e.g getter or setter)
Screenshot (1514)

How do I achieve that effect ?

Jugen commented

You could use the row value to access the list of items passed to the VirtualFlow, like:

AudioParser ap = list.get( row );

You could use the row value to access the list of items passed to the VirtualFlow, like:

AudioParser ap = list.get( row );

Thanks that worked too, I found a way,
I'm Getting Through Via the Cells' contents through Node, ->getCell(row).getNode(),
However Now I'm trying to get rid of the Horizontal Scroll Bar, I tried checking out the Previous Issues.
And also Having the List start from the Top when Displaying content, in My case it takes me to the bottom of the ListView
Thank You

Jugen commented

If you are using org.fxmisc.flowless.VirtualizedScrollPane then:

VirtualizedScrollPane vsp = new VirtualizedScrollPane<>( flow );
vsp.setHbarPolicy( ScrollBarPolicy.NEVER );
Jugen commented

You can also get the node directly from VirtualFlowHit:

flow.setOnMouseClicked( ME ->
{
    VirtualFlowHit<Cell<AudioParser,?>> hit = flow.hit( ME.getX(), ME.getY() );
    Node n = hit.getCell().getNode();
} );

Awesome, it all works, when I click on A cell I Access a Hidden Node with Data I need not the User To see.
Now I wanted To tryout, reUsable cell to see If performance is matched, better Or not, how do I Do That ?

Jugen commented

Instead of using return Cell.wrapNode( grid ); you need to create your own subclass of org.fxmisc.flowless.Cell and implement:

Node getNode()
boolean isReusable()
void updateItem( T item )
void reset()
void dispose()

See an example here in RichTextFX.

Jugen commented

If you do this you can also add another method to your Cell class to get the item passed to it back again later, instead of having to embed it in a Node as you are doing now. So add:

T getItem()

then you should be able to do:

AudioParser ap = hit.getCell().getItem();  // might need to cast hit.getCell() first ?

Screenshot (1529)
Screenshot (1528)

Hey, I've Been trying To implement a SubClass Did some Digging,
I would Like to Confirm If this is the Way,I have an error, There, Been trying to fix it so far no avail

Jugen commented

Nah, you've just copied the code from the Cell interface.
Whereas you need to do a full implementation of it, something like in the RichTextFX example.

You also asked (but removed from the post) "How Would I Be Able To stop Loading any Cell once they are out of the viewport".
The answer is that you would do that in the reset() method of your Cell class.

The VirtualFlow program logic goes something like this:

  1. If a cell is NOT available for reuse "VirtualFlow" will call the Cell factory that you passed to it when creating it. For example if you did: VirtualFlow.createVertical( list, this::myCellFactory ); then "VirtualFlow" will use myCellFactory to get a new Cell.
  2. If a cell is already available then "VirtualFlow" will call updateItem( T item ) on it. (This is where you update your nodes to show data from a new item, in your case AudioParser.)
  3. When a cell goes out of view "VirtualFlow" will call reset() on it.

An example of what a myCellFactory method may look like for your case:

private Cell audioParserCellFactory( AudioParser item )
{
    Cell newCell = new AudioParserCell();
    newCell.updateItem( item );
    return newCell;
}

Of course this can be condensed into VirtualFlow.createVertical( list, audioparser -> new AudioParserCell( audioparser ) );
but then your AudioParserCell constructor should call updateItem( audioparser ) once it has finished building the node that'll be returned by getNode().

Hope this helps.

Hey, Man Your Helping Tonnes,
I'm trying to get this one done with, however, The scroll pane shows One Item, then all of out Of heap errors,
If You Mind,where am I going Wrong, been struggling
thanks too for the other post I edited
here's is how I set it up, I chose the AudioParserCell Route am not sure if its best,(as Later on I would Implennt the getItem)
I suspect my error is all on the Update call and getNode I'm confused on how to set them up, Then I went to the richTextFlow again,(understand it better now) but, which item am I supposed to be getting with getNode()?, is it Supposed to Be Cell then,I wrap it then return it and Which Item am I updating?
Screenshot (1533)
Screenshot (1534)
Screenshot (1535)

Jugen commented
  1. getNode() returning grid is right, but it should just be:
public Node getNode() { return grid; }

You build the grid only once in the constructor.

  1. updateItem() returns void and not Cell. The method should look something like:
public void updateItem( AudioParser parser )
{
    SonfName.setText( parser.nameGet() +"\n"+ parser.albumGet() );
    executor.submit( () -> icon.setImage( new Image( parser.imageGet(), true ) ) );
}
  1. I didn't see it, so I'm just making sure you also have:
boolean isReusable() { return true; }

Oh Ok,
How about this this is what i fixed out
Screenshot (1543)
Screenshot (1544)
VirtualFlow<AudioParser, Cell<AudioParser, ?>> flows = VirtualFlow.createVertical(list, audioparser ->new AudioParserCell(audioparser));
that is how ive Implemented it,but its still empty

Jugen commented
  1. The grid and EVERYTHING inside it should ONLY be built and configured in the constructor. So no controls should be created inside updateItem.
  2. In updateItem only change whatever needs to be changed for each AudioParser, like SonfName text and icon image.
  3. You forgot to assign parser to audiop in updateItem before using audiop.
  4. Remove the getNode() call in your constructor, it doesn't do anything ?
  5. The call to updateItem in the constructor should only happen after ALL the GUI controls have been created.

Hey it works partially,
it stops loading once I start scrolling, and stops.
im tryna sort it out rn
they're stacked on each other, the cells,
Screenshot (1551)
Screenshot (1552)

Ohh, great all this time it has been the Cell reusable, checked some comments it mentions its buggy on java 1.8 and up something like that,
Man thanks for your patience,let me try implement get item now.
also is that set up ,in the shots fine ?

Jugen commented

Yeah, it's fine. You can move the SonfName.setStyle() into the constructor as well, unless it's going to change.
Remember the reason you are doing this is for performance !!! So do as little as possible in updateItem, only stuff that changes.

For the "the cells are stacked on each other" problem, try sizing the grid with grid.setPrefSize( w, h ) and see if that helps.

I did that but, that still happens, getting an error saying Cell. unsupported.......
However I've set The grid height to be consistent throughout,
Ive been getting an Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException
So I think it's related to setting up the Image in the grid pane after serious scrolling, so I'm trying to implement a blocking queue that if a certain number of executors submitted it dumps the later ones and deals with Something Like the Latest 10,

Hey ,
How can i wrap a TilePane in the virtualized Scrolpane, or functionality of a TilePane within vscrollpane as currently, it takes much ram and performance, in normal scroll pane

Jugen commented

You would need to extend TilePane and implement the Virtualized interface.

Oh , I'll work on that
Meanwhile ,if I started using the Virtualized GridView From Controls Fx,
But The Update Item Is costly, its Creating New objects all the Time, it behaves like Normal Listview
How Can I Create An Update Item or modify it in a way that it doesn't create those items again but re-use them, and update those like Images,

Jugen commented

Hey @newtingz, you'll have to show your current GridCell implementation for the GridView for me to be able to give any advice.

Jugen commented

Actually you should maybe post that on ControlsFX issues. (Put a link here though to your post, and I'll have a look.)

image

Cannot infer type arguments for GridView<>-the Error I get
Ok,
Listview Uses, Viewport, is it possible to have The GridView Use Our Own ViewPort

class GridCellr implements Cell{

			Albums audiop;

			GridPane grid4 = new GridPane();
        	Label l ;

        	ImageView icod =new ImageView();
        	Rectangle clip=new Rectangle();
			HBox iconAndName = new HBox(2);
			{

			//	HBox iconAndName = new HBox();
 	        	//GridPane grid4 = new GridPane();


 	        	//L l = new Label(item.albumGet());


				icod.setFitHeight(75);
			    icod.setFitWidth(75);
 		        grid4.getStyleClass().add("grid4");
 	    		grid4.setPadding(new Insets(0,0,5,0));
 	    		//grid4.setCache(true);
 	    		//grid4.setCacheHint(CacheHint.SPEED);
 	            //grid4.setHgap(10);
 	           // grid4.setVgap(5);

 	            grid4.setPrefSize(75, 75);
 	            grid4.maxHeight(75);
 	            grid4.maxWidth(75);
 	            iconAndName.getChildren().add(icod);
		        iconAndName.setAlignment(Pos.CENTER);
		        iconAndName.setPadding(new Insets(0,0,3,0));
 	            grid4.add(iconAndName, 0, 0);





 	            grid4.setOnMouseClicked(e -> {
 	            	albumOnClikc(grid4,l);
 		        });


			}


		public GridCellr(Albums audioparser ) {//,String artist,String album) {
			this.audiop=audioparser;
			//queue.add(0, new Image(new File(audioparser.ImageGet()).toURI().toString(),true));
		    updateItem(audioparser);




			}
		public void updateItem( Albums item )
		{
			    l= new Label(item.albumGet());
	        	l.setTextFill(Color.WHITE);
		        l.setPadding(new Insets(2,5,0,5));
 	               grid4.add(l, 0, 1);

 	            clip.setArcWidth(10);
 	            clip.setArcHeight(10);
 	            clip.widthProperty().bind(grid4.widthProperty());
 	            clip.heightProperty().bind(grid4.heightProperty());
 	            grid4.setClip(clip);
		        icod = new ImageView(new Image(new File(item.ImageGet()).toURI().toString(),true));



		}
		@Override
		public Node getNode() {return grid4; };

		@Override
		public boolean isReusable() { return false; }



	}`

The Update Item that I'm using

gridView2.setCellFactory(new Callback<GridView<Artists>, GridCell<Artists>>() {
        public GridCell<Artists> call(GridView<Artists> gridView) {



            return new GridCell<Artists>() {

            	 @Override
            	    protected void updateItem(Artists item, boolean empty) {
            	        // TODO Auto-generated method stub
            	        super.updateItem(item, empty);
            	        if (empty || item == null) {
            	            setText(null);
            	            setGraphic(null);
            	        } else {
            	        	 GridPane grid4 = new GridPane();
            	        	Label l = new Label(item.artistGet());
            		        HBox iconAndName = new HBox();
            		        l.setTextFill(Color.WHITE);
            		        l.setPadding(new Insets(2,5,0,5));
            		        ImageView icod = new ImageView(new Image(new File(item.ImageGet()).toURI().toString(),true));
            		        iconAndName.getChildren().add(icod);
            		        iconAndName.setAlignment(Pos.CENTER);
            		        iconAndName.setPadding(new Insets(0,0,3,0));
            		        icod.setFitHeight(75);
            		        icod.setFitWidth(75);
            		        setGraphic(grid4);
            		        });

            	           
            	        }
            	    }


            };
        }
    });

I Tried Making A Gridcell Implementation and an error saying the GridCell is not generic so cannot be parameterized

It is was like this class GridCellr extends GridCell
The Body is the same as GridCellr Cell previously mentioned, without getNode and reUsable