質問

Im trying to build a custom view with JavaFX that allows 2 buttons "Edit User" and "View User" to be placed in the cell.

I have my adapter built but I am having trouble assigning the index to the button when the cell is created, this is a problem as when I click a button within a cell I get a Null Pointer Excpetion.

EDIT 07/04/2014 : I have updated my program logic a little but I am still struggling to find a solution to my problem - the index assigned is sometimes correct, but is mostly incorrect ( I set up a log to give me the current index and it fluctuates drastically, which leads me to conclude my cell constructor is unreliable)

I now use the following code : populateListView():

public void populateListView() {

    // Zero the index each time the list view is repopulated to 
    // bind to the correct button
    index = 0;

    // Refresh the lists contents to null
    lstNotes.setItems(null);

    // Observable list containing items to add
    ObservableList notes = populateObservable(thisTenant.getNotes());

    // Set the items returned by populateObservable(T);
    lstNotes.setItems(notes);
    lstNotes.setFixedCellSize(50);

    // Use a cell factory for custom styling
    lstNotes.setCellFactory(new Callback<ListView, ListCell>() {
        @Override
        public ListCell call(ListView listView) {
            NoteCell nCell = new NoteCell(index, controller);
            index++;
            nCell.getStyleClass().add("border-bottom");
            return nCell;
        }
    });
}

The comments are fairly self explanatory here - an observable list of items is populated via this method - populateObservable(NoteList n):

public ObservableList populateObservable(ArrayList<Note> notesArray) {

    ObservableList notes = FXCollections.observableArrayList();

    // Loop through the users Notes array and create a listview item
    for(int i = 0; i < notesArray.size(); i++) {
        Note thisNote = notesArray.get(i);
        notes.add(thisNote.getMessage());
    }

    return notes;
}

Finally the custom view is constructed in my cell factory (the styling is irrelevant to the question), what should be noted is a reference to my Controller is passed to it so I can access methods - within the NoteCell class I have a method to delete the row at the given index (this is what produces skewed results)

 cross.setOnMouseClicked(new EventHandler<MouseEvent>() {
      @Override
      public void handle(MouseEvent mouseEvent) {
          ScreensFramework.logGeneral.writeToFile("I am removing from index " + String.valueOf(thisIndex));
          if(thisTenant.removeNoteAt(thisIndex, true)){
              controller.populateListView();
          } else {
              controller.populateListView();
          }
      }
  });

the call to populateListView() is simply there to refresh the contents of the listview and rebuild it dependent on the Tenant's updated Note array.

The RemoveNoteAt() method sends a Delete query to my db and removes the note from the Tenants note array at the given index (but I do not always get the correct index as stated above, as I can't find an effective way to bind the button to that ListViews cell and my feeble attempt at passing an index does not seem to work).

I hope this update provides a clearer scope to my question, please request if you need any more information to get a clearer understanding of this.

EDIT: NoteCell code:

public class NoteCell extends ListCell<String> {
HBox hbox = new HBox();
HBox c = new HBox();
Pane b = new HBox();
Pane pane = new Pane();
Label msg = new Label();
Label date = new Label();
Button cross = new Button();
Tenant thisTenant;
int thisIndex;

String lastItem;


public NoteCell(int index, UserInfoController controller) {
    super();

    try{
        thisTenant = controller.getTenant();
        Note currNote = thisTenant.getNoteAt(index);
        date = new Label(currNote.getDate());
        System.out.println(thisTenant.getNotes());
        thisIndex = index;

        date.setStyle("-fx-text-fill: #fff !important; -fx-font-family: Helvetica; -fx-font-weight: bold; -fx-font-size: 12px; -fx-background-color: #f9246b; -fx-border-color: #FE246C; -fx-padding: 8 8 6 8; -fx-border-radius: 6; -fx-background-radius: 6");
        b.setStyle("-fx-padding: 10px 5px 10px 5px");
        msg.setStyle("-fx-text-fill: #fafafa; -fx-font-size: 14px; -fx-font-family: 'Open Sans Light'; -fx-label-padding: 10px");
        cross.getStyleClass().add("button_close");
        cross.setTranslateY(20);
        msg.setAlignment(Pos.CENTER_LEFT);

        pane.setTranslateY(20);
        b.getChildren().add(date);
        c.getChildren().add(cross);
        hbox.getChildren().addAll(b, msg, pane, cross);
        HBox.setHgrow(pane, Priority.ALWAYS);


        // Deletes the note
        cross.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                ScreensFramework.logGeneral.writeToFile("I am removing from index " + String.valueOf(thisIndex));
                if(thisTenant.removeNoteAt(thisIndex, true)){
                    controller.populateListView();
                } else {
                    controller.populateListView();
                }
            }
        });

    } catch (Exception e) {
        ScreensFramework.logError.writeToFile(e.getMessage());
    }
}



@Override
protected void updateItem(String item, boolean empty) {

    super.updateItem(item, empty);
    setText(null);  // No text in label of super class
    if (empty) {
        lastItem = null;
        setGraphic(null);
    } else {
        lastItem = item;
        msg.setText(item!=null ? item : "<null>");
        setGraphic(hbox);
    }
}

}

EDIT: Is there any way when creating the ListView cells I could pass the current index of that cell to the "CellFactory"?

Regards, Alex

役に立ちましたか?

解決

Every cell knows its index:

public class Demo extends Application {

    ListView<String> list = new ListView<String>();

    ObservableList<String> data = FXCollections.observableArrayList(
            "chocolate", "salmon", "gold", "coral", "darkorchid",
            "darkgoldenrod", "lightsalmon", "black", "rosybrown", "blue",
            "blueviolet", "brown");

    @Override
    public void start(Stage stage) {
        VBox box = new VBox();
        Scene scene = new Scene(box, 200, 200);
        stage.setScene(scene);
        box.getChildren().addAll(list);
        VBox.setVgrow(list, Priority.ALWAYS);

        list.setItems(data);

        list.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
            @Override
            public ListCell<String> call(ListView<String> list) {
                return new ButtonCell();
            }
        });
        stage.show();
    }

    static class ButtonCell extends ListCell<String> {
        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            if (item != null) {
                final Button btn = new Button(item + " with index " + getIndex());
                btn.setOnAction(new EventHandler<ActionEvent>() {
                    @Override
                    public void handle(ActionEvent event) {
                        System.out.println("I am a " + getItem() + " with index " + getIndex());
                    }
                });
                setGraphic(btn);
            } else {
                setGraphic(null);
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top