oupoup
oupoup

Reputation: 75

javafx cannot access button in custom listcell

The core of the problem is that I cannot refresh or change the content of a node of a scene (here TablesMain) from another class (here NamePriceCell).

I am building and application with a main StackPane (TableMainController extends StackPane) that contains other nodes, some of which are ListViews. In a specific ListView (say 'readitemslistview') I have created a custom ListCell (public class NamePriceCell extends ListCell) and this NamePriceCell listcell contains a button (plusbtn). When a user clicks on the plusbtn, an arraylist (say 'chosenitemslist') gets filled up with the item displayed in the particular cell and at the same time another listview in the stackpane (say 'ordereditemslist') should be triggered to display the content of the 'chosenitemslist' arraylist.

I haven't found a way to reference the plusbtn of the NamePriceCell from the main controller. Moreover this post Get ListCell via ListView

Unfortunately right now there is no API to get List Cell by index or to get All children's(listcells) for ListView.

has turned me away from such an attempt (I haven't been able to understand if the solution provided there is suitable for my needs, as I don't want a refresh of the same listview but from another in the same scene).

So the only way I have found to get a mouse click action from the plusbtn is with an EventHandler in the same class (NamePriceCell). And even though I can get an arraylist filled according to the clicks on the NamePriceCell buttons (the NamePriceCell calls a static method in another class with a static arraylist in it) and I can get the result in my orderedlistview by letting the user click on another button node of the TableMain StackPane, I cannot find a way to do that when the user clicks on the NamePriceCell button. Among the things I tried is setting a static method in the TablesMainController that I can access it from the NamePriceCell EventHandler (but then I have to make the holder node of the ordereditemslist static, and even so, it hasn't worked), writing a separate fxml for the VBox containing the ordereditemslist with a corresponding separate controller so that I can have a method there to create the ordereditemslist and set the cellFactory (but even though the fxml file displays correctly and calling the method from the EventHandler of NamePriceCell works - a System.out gets displayed - it won't affect anything on the screen not the ordereditemslist, not even a label I tested.

I am relatively a java newbie and even so more when it comes to javafx. Your help is greatly needed and appreciated.

The code of my last approach is below:

VboxList.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.VBox?>
<VBox>
    <Label text="Label" id="label1"/>
    <Label text="Label" id="label2"/>
    <Label text="sdfsdf" id="label3"/>
    <ListView nodeOrientation="LEFT_TO_RIGHT" id="orderedlist" prefHeight="200.0" prefWidth="200.0"  />
</VBox>

VboxListController.java

public class VboxListController extends VBox{
    FXMLLoader fxmlLoader;
    @FXML
    private Label label1;

    @FXML
    private Label label2;

    @FXML
    private ListView<OrderItem> orderedlist;

    public VboxListController() {
        fxmlLoader = new FXMLLoader(getClass().getResource("fxml/VboxList.fxml"));
        //fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    public void getorderedlist(ArrayList<OrderItem> chosenitems){
        ObservableList<OrderItem> myObservableList = FXCollections.observableList(chosenitems);

        this.getChildren().remove(orderedlist);

        orderedlist = new ListView<>();
        orderedlist.setItems(myObservableList);
        orderedlist.setCellFactory(new Callback<ListView<OrderItem>, ListCell<OrderItem>>() {

            @Override
            public ListCell<OrderItem> call(ListView<OrderItem> p) {

                ListCell<OrderItem> cell = new ListCell<OrderItem>() {

                    @Override
                    protected void updateItem(OrderItem dataobj, boolean bln) {
                        super.updateItem(dataobj, bln);
                        if (dataobj != null) {
                            setText(dataobj.read_item_name);
                        }
                    }

                };
                return cell;
            }
        });
        this.getChildren().add(orderedlist);
        orderedlist.setItems(null);
        orderedlist.setItems(myObservableList);
        label1 = null;
        this.getChildren().remove(label1);
        label1 = new Label();
label1.setText("oooops!");
        System.out.println("sdf");
        this.getChildren().add(label1);


    }


}

NamePriceCell.java

public class NamePriceCell extends ListCell<ReadItemChoiceObj> {
    int count=0;
    @FXML
    Label namelbl;

    @FXML
    Label pricelbl;

    @FXML
    Button plusbtn;

    @FXML
    Region spacer;

    @FXML
    HBox cellHbox;

    FXMLLoader mLLoader;

    ReadItemChoiceObj readitem;
    ArrayList<ReadItemChoiceObj> chosenreaditems;
    @Override
    protected void updateItem(ReadItemChoiceObj readitem, boolean empty) {
        super.updateItem(readitem, empty);
        chosenreaditems = new ArrayList<>();

        if(empty || readitem == null) {

            setText(null);
            setGraphic(null);

        } else {

            this.readitem = readitem;
            if (mLLoader == null) {
                mLLoader = new FXMLLoader(getClass().getResource("fxml/NamePriceCell.fxml"));
                mLLoader.setController(this);
                try {
                    mLLoader.load();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }


            namelbl.setText(readitem.getname());
            namelbl.setMaxWidth(500);
            pricelbl.setText(String.format("%.2f", readitem.getprice()));
            pricelbl.setStyle("-fx-font: 8pt  \"Arial\";");
            pricelbl.setMaxWidth(40);
            spacer.setMaxWidth(10);
            spacer.setMinWidth(10);
            plusbtn.setMaxWidth(20);
            cellHbox.setHgrow(namelbl, Priority.ALWAYS);

            cellHbox.setAlignment(Pos.BASELINE_LEFT);

            setText(null);
            setGraphic(cellHbox);

            plusbtn.setOnMouseClicked(whattodohandler);
        }

    }



    EventHandler<MouseEvent> whattodohandler = new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            ChosenItemsStat.getplusbtnclicked(readitem);
            ChosenItemsStat chos = new ChosenItemsStat();

            count+=1;
            plusbtn.setText(String.valueOf(count));
            new VboxListController().getorderedlist(chos.sendchosenlist());
        }
    };

}

and a part of TablesMain.java

 @FXML
    Label label1;

    @FXML
    BorderPane borderpane;

    @FXML
    Pane tablepane;

    @FXML
    ListView<DataObj> tabcatlist;

    @FXML
     VBox VboxList;

    @FXML
     VboxListController vboxListController;

  /*  @FXML
    ListView<OrderItem> orderedlist;*/

    @FXML
    VBox leftVbox;

 public TablesMain(Order order) {
        this.order = order;
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("fxml/tablesmain.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);
        try {
            fxmlLoader.load();
        } catch (IOException exception) {

            throw new RuntimeException(exception);
        }

        ObservableList<DataObj> myObservableList = FXCollections.observableList(gettable_categories());
        tabcatlist.setItems(myObservableList);
        tabcatlist.setCellFactory(new Callback<ListView<DataObj>, ListCell<DataObj>>() {

            @Override
            public ListCell<DataObj> call(ListView<DataObj> p) {

                ListCell<DataObj> cell = new ListCell<DataObj>() {

                    @Override
                    protected void updateItem(DataObj dataobj, boolean bln) {
                        super.updateItem(dataobj, bln);
                        if (dataobj != null) {
                            setText(dataobj.getname());
                        }
                    }

                };
                return cell;
            }
        });
        if (table_categoryID == 0) table_categoryID = tablecategories.get(0).getid();
        gettables(table_categoryID);
    }

 private void make_readitemlist(int itemcategoryID) {
             readitems = new ArrayList<>();


            .... the readitems  arraylist gets filled up...


        ObservableList<ReadItemChoiceObj> myObservableList = FXCollections.observableList(readitems);
        readitemlist.setItems(myObservableList);

        readitemlist.setCellFactory(new Callback<ListView<ReadItemChoiceObj>,
                                            ListCell<ReadItemChoiceObj>>() {
                                        @Override
                                        public ListCell<ReadItemChoiceObj> call(ListView<ReadItemChoiceObj> list) {
                                            readitemlistcell = new NamePriceCell();

                                            return readitemlistcell;
                                        }

                                    }
        );

        readitemlist.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                ReadItemChoiceObj dataobj = (ReadItemChoiceObj) readitemlist.getSelectionModel().getSelectedItem();
                System.out.println(String.valueOf(dataobj.getid()));

               // showorderedlist(new ChosenItemsStat().sendchosenlist());
            }
        });
        System.out.println(readitemlist.cellFactoryProperty().getClass().toString());
    }

...
}

Upvotes: 1

Views: 540

Answers (1)

oupoup
oupoup

Reputation: 75

Since it's been almost 5 months without another contribution, i would like to post my solution as an answer. It's not mine but inspired (or copied) by the post mentioned in my question (or another one, now I don't remember, please excuse my possible misplacement of credits). More precisely I created a static StringProperty in TableMain file (the main Controller class). Every time the plusbtn (NamePriceCell class that extends ListCell) is clicked a random number turned to string is forced in the static StringProperty of the TableMain controller class. Inside this class the StringProperty has a ChangeListener added which in its turn triggers (from inside of the main controller now - that was the clue) the refreshing of the orderedlist (the listview that had to be refreshed with the added items).

NamePriceCell.java

public class NamePriceCell extends ListCell<ReadItemChoiceObj> {
@FXML
Label namelbl;

@FXML
Label pricelbl;

@FXML
Button plusbtn;

@FXML
Region spacer;

@FXML
HBox cellHbox;

FXMLLoader mLLoader;

ReadItemChoiceObj readitem;

@Override
protected void updateItem(ReadItemChoiceObj readitem, boolean empty) {
    super.updateItem(readitem, empty);

    if(empty || readitem == null) {

        setText(null);
        setGraphic(null);

    } else {

        this.readitem = readitem;
        if (mLLoader == null) {
            mLLoader = new FXMLLoader(getClass().getResource("fxml/NamePriceCell.fxml"));
            mLLoader.setController(this);
            try {
                mLLoader.load();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


        namelbl.setText(readitem.getname());
        namelbl.setMaxWidth(500);
        pricelbl.setText(String.format("%.2f", readitem.getprice()));
        pricelbl.setStyle("-fx-font: 8pt  \"Arial\";");
        pricelbl.setMaxWidth(40);
        spacer.setMaxWidth(10);
        spacer.setMinWidth(10);
        plusbtn.setMaxWidth(20);
        cellHbox.setHgrow(namelbl, Priority.ALWAYS);

        cellHbox.setAlignment(Pos.BASELINE_LEFT);

        setText(null);
        setGraphic(cellHbox);

        plusbtn.setOnMouseClicked(whattodohandler);
    }

}



EventHandler<MouseEvent> whattodohandler = new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent event) {


        OrderItem orderitem = new OrderItem();
        orderitem.read_item_name = readitem.getname();
        orderitem.read_item_price=readitem.getprice();
        orderitem.read_itemID=readitem.getid();
        orderitem.choice_name_list = new ArrayList<String>();
        orderitem.choice_price_list = new ArrayList<Float>();
        orderitem.choice_id_list = new ArrayList<Integer>();

        ChosenItemsStat.getplusbtnclicked(orderitem);
        Random rand = new Random();
        TablesMain.stringProperty.setValue(String.valueOf(rand));
    }
};

}

ChosenItemsStat.java (a static class receiving the additions to the list)

public class ChosenItemsStat {
static ArrayList<OrderItem> chosenorderitemsstat  = new ArrayList<>();
static void getplusbtnclicked(OrderItem orderitem){
    chosenorderitemsstat.add(orderitem);
    }
}

I didn't use the VboxList.fxml or the VboxListController.java as I included this in the TablesMain.java (see below)

TablesMain.java (as in the question but with this addition)

stringProperty = new SimpleStringProperty();
    stringProperty.setValue("");
    tablelbl.setText(stringProperty.getValue());
    stringProperty.addListener(new ChangeListener(){
        @Override
        public void changed(ObservableValue observable, Object oldValue, Object newValue) {
            showselectedlist();
        }
    });

while the showselectedlist() that is being called by the change of the StringProperty value is the one below (in this method the cell is being contructed as in the removed class (VboxListController)

private void showselectedlist(){
    orderitems.addAll(ChosenItemsStat.chosenorderitemsstat);
    ChosenItemsStat.chosenorderitemsstat.clear();
    ListView<OrderItem> selectedlist = new ListView<>();
    ObservableList<OrderItem> myObservableList = FXCollections.observableList(orderitems);
    selectedlist.setItems(myObservableList);
    selectedlist.setMaxWidth(220);
    selectedlist.setCellFactory(new Callback<ListView<OrderItem>, ListCell<OrderItem>>() {

        @Override
        public ListCell<OrderItem> call(ListView<OrderItem> p) {
            ListCell<OrderItem> cell = new ListCell<OrderItem>(){
                OrderedCell ordcell= new OrderedCell();
                @Override
                protected void updateItem(OrderItem orderitem, boolean bln) {
                    super.updateItem(orderitem, bln);
                    if (orderitem != null) {
                        Float price = ordcell.getitemTempPrice(orderitem,orderitem.read_item_price);

                        HBox namepriceHbox = new HBox();
                        Label lblprice= new Label(String.format("%.2f",price));
                        Region betweenregion = new Region();
                        Label lblname = new Label();

                        lblname.setText(orderitem.read_item_name );
                        lblname.setStyle("-fx-font: 10pt  \"Arial\";-fx-font-weight:bold");

                        namepriceHbox.setHgrow(betweenregion, Priority.ALWAYS);
                        namepriceHbox.getChildren().addAll(lblname,betweenregion,lblprice);

                        VBox allVbox = new VBox();
                        Text lblchoices = new Text();

                        String choices = ordcell.choicestostring(orderitem);
                        lblchoices.setText(choices);
                        lblchoices.setWrappingWidth(listpane.getLayoutBounds().getWidth());

                        if (choices.equals("")) allVbox.getChildren().addAll(namepriceHbox);
                        else allVbox.getChildren().addAll(namepriceHbox, lblchoices);

                        double namepricewidth = listpane.getLayoutBounds().getWidth();
                        System.out.println("namepricewidth is "+String.valueOf(namepricewidth));

                        //allVbox.setPadding(new Insets(10,0,10,0));
                        setGraphic(allVbox);
                    }
                }

            };
            return cell;
        }
    });
    listpane.getChildren().add(selectedlist);
}

Upvotes: 1

Related Questions