Панель обновления JavaFX после изменения списка

Таким образом, после моего первого в истории работы с JavaFX мне был назначен проект, который я бы посчитал масштабным, потому что я только второй раз с JavaFX. Мне пришлось создать фотоальбом с основными функциями: добавлять изображения, удалять изображения, сортировать по названию / описанию / местоположению, возможность редактировать заголовок, дату съемки, описание и местоположение. Хорошие новости: я получил все, кроме одной из этих вещей.

Удаление фотографии или, вернее, удаление ее с экрана после удаления из imageData Массив оказался сложным. Я уверен, что это связано с тем, как я это организовал. Я попытался сделать свой собственный "changeProperty" для Album класс и наблюдая за этим из источника, но, видимо, я как-то облажался, или это не работает так, как я думал.

private BooleanProperty changed = new SimpleBooleanProperty();
public final boolean getChanged(){return changed.get();}
public final void setChanged(boolean value){changed.set(value);}
public BooleanProperty changedProperty(){return changed;}

Так что это был провал. Я также попробовал ObservableList но потому что это было создано в источнике, я не мог obsList.remove() изнутри моего Album учебный класс. Опять же, возможно, я только что реализовал это неправильно.

Так что, чтобы повторить - я могу удалить изображения из ArrayList imageData но они остаются в галерее FlowPane,

Source.java

import javafx.application.Application;
import javafx.geometry.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.*;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.io.File;


/**
 * Created by Alyssa on 9/27/2015.
 */
public class Source extends Application  {

    protected Stage mainWin;
    protected FlowPane gallery;
    private static boolean delete;

    public static void main(String[] args){
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        Album album = new Album();

        Scene mainScene;

        for(int i = 0; i < 52;i++) {
            album.getImageData().add(new ImageData(("cards/" + String.valueOf(i + 1) + ".png"), "cardtitle" + i, "carddesc", "cardloc"));
        }

        album.getObsList().addListener(new ListChangeListener(){ 
        @Override 
        public void onChanged(ListChangeListener.Change change){ 
            refreshGallery(); } 
        });

        //FILE MENU
        Menu fileMenu = new Menu("_File");
        MenuItem addImg = new MenuItem("_Add Photo...");
        addImg.setOnAction(e -> {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Open Resource File");
            File file = fileChooser.showOpenDialog(mainWin);
            String absPath = "file:" + file.getAbsolutePath();
            absPath = absPath.replace('\\', '/');
            album.addImage(absPath, "","","");
            refreshGallery();
        });

        MenuItem exit = new MenuItem("_Exit");
        exit.setOnAction(e -> mainWin.close());
        fileMenu.getItems().addAll(addImg, new SeparatorMenuItem(), exit);

        //SORT MENU
        Menu sortMenu = new Menu("_Sort");
        MenuItem sortTitle = new MenuItem("_Title");
        sortTitle.setOnAction(e -> {
            album.sortAlbumTitle(album);
            refreshGallery();
        });
        MenuItem sortDate = new MenuItem("_Date Taken");
        sortDate.setOnAction(e -> {
            album.sortAlbumDate(album);
            refreshGallery();
        });
        MenuItem sortLoc = new MenuItem("_Location");
        sortLoc.setOnAction(e -> {
            album.sortAlbumLoc(album);
            refreshGallery();
        });

        sortMenu.getItems().addAll(sortTitle, sortDate,sortLoc);

        //HELP MENU
        Menu helpMenu = new Menu("_Help");
        MenuItem helpAbout = new MenuItem("_About");
        helpAbout.setOnAction(e -> Help.displayAbout());
        MenuItem helpHelp = new MenuItem("_Help");
        helpHelp.setOnAction(e -> Help.displayHelp());
        helpMenu.getItems().addAll(helpAbout, helpHelp);

        //MENU BAR
        MenuBar menuBar = new MenuBar();
        menuBar.getMenus().addAll(fileMenu, sortMenu, helpMenu);
        menuBar.setStyle("-fx-background-color: #383838;");

        mainWin = primaryStage;
        mainWin.setTitle("Photo Album");

        ScrollPane center = new ScrollPane();
        //center.setMinWidth(800);
        center.setFitToWidth(true);

        gallery = new FlowPane();
        gallery.setPadding(new Insets(5, 5, 5, 5));
        gallery.setAlignment(Pos.CENTER);
        gallery.setColumnHalignment(HPos.CENTER);
        gallery.setRowValignment(VPos.CENTER);
        gallery.setHgap(10);
        gallery.setVgap(10);
        gallery.setPrefWrapLength(785);

        for (int i =0 ; i < album.getImageData().size(); i++){
            gallery.getChildren().add(album.getImageData().get(i).getImageBtn());
        }

        center.setContent(gallery);

        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(center);
        borderPane.setTop(menuBar);

        mainScene = new Scene(borderPane, 800,600);
        mainScene.getStylesheets().add("styles.css");
        mainWin.setScene(mainScene);
        mainWin.setResizable(false);
        mainWin.show();
    }

    private void refreshGallery(){

        gallery.getChildren().clear();

        for (int i =0 ; i < Album.getImageData().size(); i++){
            gallery.getChildren().add(Album.getImageData().get(i).getImageBtn());
        }
    }
}

Album.java

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.image.ImageView;
import java.util.*;

/**
 * Created by Alyssa on 9/27/2015.
 */
public class Album extends Observable{
    private static List<ImageData> imageData = new ArrayList<>();

    ObservableList<ImageData> observableList = FXCollections.observableList(imageData);
    public ObservableList<ImageData> getObsList(){return observableList;}

    private BooleanProperty changed = new SimpleBooleanProperty();
    public final boolean getChanged(){return changed.get();}
    public final void setChanged(boolean value){changed.set(value);}
    public BooleanProperty changedProperty(){return changed;}

    public Album(){}

    public static List<ImageData> getImageData(){ return imageData; }

    public void addImage(String image, String title, String desc, String loc) {
        imageData.add(0, new ImageData(image, title, desc, loc));
    }

    public void removeImage(ImageView img){

        List<ImageData> toRemove = new ArrayList<>();
        for(ImageData a: imageData){
            if(a.getImageView() == img){
                toRemove.add(a);
                //observableList.remove(a);
                break;
            }
        }

        imageData.removeAll(toRemove);
        if (this.getChanged() == true)
            this.setChanged(false);
        else
            this.setChanged(true);
    }

    public void sortAlbumTitle(Album album) {
        System.out.println("Sort by Title");
        Collections.sort(album.getImageData(), new Comparator<ImageData>() {
            public int compare(ImageData img1, ImageData img2) {
                return img1.getTitle().compareToIgnoreCase(img2.getTitle());
            }
        });
    }

    public void sortAlbumDate(Album album) {
        System.out.println("Sort by Date");
        Collections.sort(album.getImageData(), new Comparator<ImageData>() {
            public int compare(ImageData img1, ImageData img2) {
                return img1.getDate().compareTo(img2.getDate());
            }
        });
    }

    public void sortAlbumLoc(Album album) {
        System.out.println("Sort by description");
        Collections.sort(album.getImageData(), new Comparator<ImageData>() {
            public int compare(ImageData img1, ImageData img2) {
                return img1.getLocation().compareToIgnoreCase(img2.getLocation());
            }
        });
    }
}

ImageData.java

import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;


/**
 * Created by Alyssa on 9/27/2015.
 */
public class ImageData extends Album implements EventHandler<MouseEvent>{

private Image image;
private ImageView smImgView;
private ImageView imgView;
private String title = null;
private String desc = null;
private Date dateAdded = null;
private Date date = null;
private String location = null;
private Button btn;



public ImageData(){};
public ImageData(String img, String nTitle, String nDesc, String loc){

    image = new Image(img);
    smImgView = new ImageView(image);   //thumbnail
    getSmImageView().setFitWidth(80);
    smImgView.setPreserveRatio(true);
    imgView = new ImageView(image); //fullsize

    //image info
    title = nTitle;
    desc=nDesc;
    location = loc;
    dateAdded = new java.util.Date();
    date = new java.util.Date();


    btn = new Button();
    btn.setGraphic(smImgView);
    btn.setOnMouseClicked(this);

}

//getters/setters
public String getTitle(){ return title; }

public void setTitle(String nTitle){ this.title = nTitle; }

public String getDesc() { return desc; }

public void setDesc(String nDesc) { this.desc = nDesc; }

public java.util.Date getDateAdded() { return dateAdded; }

public Date getDate() { return date; }

public void setDate(Date nDate) { this.date = nDate; }

public String getLocation() { return location; }

public void setLocation(String nLocation) { this.location = nLocation; }

public ImageView getSmImageView(){ return this.smImgView; }

public ImageView getImageView(){ return this.imgView; }

public String getImage(){return this.image.toString(); }

public Button getImageBtn(){return this.btn; }

@Override
public void handle(MouseEvent event) {
    ArrayList arr = DisplayEditDetail.display(imgView, title, dateAdded, date, desc, location);
    title = arr.get(0).toString();

    desc = arr.get(2).toString();
    location = arr.get(3).toString();
    if (arr.get(1) != null) {
        try {
            SimpleDateFormat dateformat = new SimpleDateFormat("MM/dd/yyyy");
            Date nDate = dateformat.parse(arr.get(1).toString());
            date = nDate;
        }
        catch (ParseException ex) {

        }

    }
    if (arr.get(4) == "True") {
        super.removeImage(imgView);
    }
}
}

DisplayEditDetail.java

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import java.util.ArrayList;

/**
 * Created by Alyssa on 9/27/2015.
 */
public class DisplayEditDetail extends Album{

private Boolean delete = false;

public static ArrayList<String> display(ImageView img, String title, Date dateAdded, Date date, String desc, String loc){

    String cdate = null, olddate = null;
    if (date != null){
        cdate = date.toString();
        DateFormat df = new SimpleDateFormat("MM/dd/YYYY");
        olddate = df.format(date);
    }

    ArrayList<String> changes = new ArrayList<>();
    changes.add(title);
    changes.add(cdate);
    changes.add(desc);
    changes.add(loc);
    changes.add("False");

    Stage window = new Stage();

    window.initModality(Modality.APPLICATION_MODAL);
    window.setTitle(title);
    window.setWidth(img.getFitWidth());

    Label dateALbl = new Label("Date Added: " + dateAdded.toString());

    Label titleLbl = new Label("Title");
    TextField titleTf = new TextField(title);
    int TITLE_MAX = 100;
    titleTf.textProperty().addListener(new ChangeListener<String>(){
        @Override
        public void changed(ObservableValue<? extends String> observable,
                            String oldValue, String newValue) {

            if(titleTf.getText().length() > TITLE_MAX ) {
                titleTf.setText(titleTf.getText().substring(0, TITLE_MAX ));
            }
        }
    });


    Label dateTLbl = new Label("Date Taken");

    TextField dateTf = new TextField(olddate);

    Label descLbl = new Label("Description");
    TextArea descTf = new TextArea(desc);
    descTf.setWrapText(true);
    descTf.setMaxWidth(250);
    descTf.setMaxHeight(100);
    int DESC_MAX = 300;
    descTf.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable,
                            String oldValue, String newValue) {

            if(descTf.getText().length() > DESC_MAX){
                descTf.setText(descTf.getText().substring(0, DESC_MAX));
            }
        }
    });

    Label locLbl = new Label("Location");
    TextField locTf = new TextField(loc);
    //Create two buttons

    Button confirmBtn = new Button("Save");
    Button cancelBtn = new Button("Cancel");
    Button deleteBtn = new Button("Delete");

    confirmBtn.setOnAction(e-> {
        try {
            changes.set(0, titleTf.getText());
            changes.set(1, dateTf.getText());
            if (dateTf.getText() != null) {    //throws parse exception
                SimpleDateFormat dateformat = new SimpleDateFormat("MM/dd/yyyy");
                Date nDate = dateformat.parse(dateTf.getText());
            }
            changes.set(2, descTf.getText());
            changes.set(3, locTf.getText());
            window.close();
        }
        catch(ParseException ex) {
            AlertBox.display("Invalid Date", "Error: Invalid Date Format.\n Use format MM/DD/YYYY");
            window.fireEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));
        }
    });

    cancelBtn.setOnAction(e-> {
        window.close();
    });

    deleteBtn.setOnAction(e ->{
        changes.set(4, "True");
        window.close();
    });

    window.setOnCloseRequest(e-> {
        boolean confirm = ConfirmBox.display("Exit?", "Are you sure you want to exit without saving?");
        e.consume();
        if (confirm)
            window.close();

    });

    HBox buttons = new HBox(10);
    buttons.getChildren().addAll(confirmBtn, cancelBtn, deleteBtn);
    buttons.setAlignment(Pos.CENTER);
    buttons.setPadding(new Insets(5,5,5,5));

    VBox details = new VBox(5);
    details.getChildren().addAll(dateALbl, titleLbl, titleTf, dateTLbl, dateTf, descLbl, descTf, locLbl, locTf, buttons);
    details.setAlignment(Pos.CENTER);
    details.setPadding(new Insets(5,5,5,5));

    HBox layout = new HBox(10);
    layout.getChildren().addAll(img, details);
    layout.setAlignment(Pos.CENTER);
    layout.setPadding(new Insets(10,5,10,10));
    layout.setStyle("-fx-background-color: #1d1d1d");

    Scene scene = new Scene(layout);
    scene.getStylesheets().add("styles.css");
    window.setScene(scene);
    window.showAndWait(); //must be closed before anything else

    return changes;

}

}

1 ответ

Когда вы удаляете изображение. Вы удаляете из списка, вы должны удалить форму ObservableList, тогда только она вызывает changeListListner. Вот мой рабочий код. Измените этот класс, он будет работать для вас. Любой комментарий

Album.java

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.image.ImageView;

import java.util.*;


public class Album extends Observable{
private static ObservableList<ImageData> imageData = FXCollections.observableArrayList();

private BooleanProperty changed = new SimpleBooleanProperty();
public final boolean getChanged(){return changed.get();}
public final void setChanged(boolean value){changed.set(value);}
public BooleanProperty changedProperty(){return changed;}

public Album(){}

public static ObservableList<ImageData> getImageData(){ return imageData; }

public void addImage(String image, String title, String desc, String loc) {
    imageData.add(0, new ImageData(image, title, desc, loc));
}

public void removeImage(ImageView img){

    List<ImageData> toRemove = new ArrayList<>();
    for(ImageData a: imageData){
        if(a.getImageView() == img){
            toRemove.add(a);
            //observableList.remove(a);
            break;
        }
    }

    imageData.removeAll(toRemove);
    if (this.getChanged() == true)
        this.setChanged(false);
    else
        this.setChanged(true);
}

public void sortAlbumTitle(Album album) {
    System.out.println("Sort by Title");
    Collections.sort(album.getImageData(), new Comparator<ImageData>() {
        public int compare(ImageData img1, ImageData img2) {
            return img1.getTitle().compareToIgnoreCase(img2.getTitle());
        }
    });
}

public void sortAlbumDate(Album album) {
    System.out.println("Sort by Date");
    Collections.sort(album.getImageData(), new Comparator<ImageData>() {
        public int compare(ImageData img1, ImageData img2) {
            return img1.getDate().compareTo(img2.getDate());
        }
    });
}

public void sortAlbumLoc(Album album) {
    System.out.println("Sort by description");
    Collections.sort(album.getImageData(), new Comparator<ImageData>() {
        public int compare(ImageData img1, ImageData img2) {
            return img1.getLocation().compareToIgnoreCase(img2.getLocation());
        }
    });
}
}

Source.java

import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.File;


public class Source extends Application {

protected Stage mainWin;
protected FlowPane gallery;
private static boolean delete;

public static void main(String[] args) {
    launch(args);
}

@Override
public void start(Stage primaryStage) throws Exception {
    Album album = new Album();

    Scene mainScene;

    for (int i = 1; i < 10; i++) {
        String s = "D:\\prabhu\\w\\1";
        album.getImageData().add(
                new ImageData((s + " (" + i + ").jpg"), "cardtitle" + i,
                        "carddesc", "cardloc"));
    }

    album.getImageData().addListener(new ListChangeListener() {
        @Override
        public void onChanged(ListChangeListener.Change change) {
            refreshGallery();
        }
    });

    // FILE MENU
    Menu fileMenu = new Menu("_File");
    MenuItem addImg = new MenuItem("_Add Photo...");
    addImg.setOnAction(e -> {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Open Resource File");
        File file = fileChooser.showOpenDialog(mainWin);
        String absPath = "file:" + file.getAbsolutePath();
        absPath = absPath.replace('\\', '/');
        album.addImage(absPath, "", "", "");
        refreshGallery();
    });

    MenuItem exit = new MenuItem("_Exit");
    exit.setOnAction(e -> mainWin.close());
    fileMenu.getItems().addAll(addImg, new SeparatorMenuItem(), exit);

    // SORT MENU
    Menu sortMenu = new Menu("_Sort");
    MenuItem sortTitle = new MenuItem("_Title");
    sortTitle.setOnAction(e -> {
        album.sortAlbumTitle(album);
        refreshGallery();
    });
    MenuItem sortDate = new MenuItem("_Date Taken");
    sortDate.setOnAction(e -> {
        album.sortAlbumDate(album);
        refreshGallery();
    });
    MenuItem sortLoc = new MenuItem("_Location");
    sortLoc.setOnAction(e -> {
        album.sortAlbumLoc(album);
        refreshGallery();
    });

    sortMenu.getItems().addAll(sortTitle, sortDate, sortLoc);

    // HELP MENU
    Menu helpMenu = new Menu("_Help");
    MenuItem helpAbout = new MenuItem("_About");
    helpAbout.setOnAction(e -> Help.displayAbout());
    MenuItem helpHelp = new MenuItem("_Help");
    helpHelp.setOnAction(e -> Help.displayHelp());
    helpMenu.getItems().addAll(helpAbout, helpHelp);

    // MENU BAR
    MenuBar menuBar = new MenuBar();
    menuBar.getMenus().addAll(fileMenu, sortMenu, helpMenu);
    menuBar.setStyle("-fx-background-color: #383838;");

    mainWin = primaryStage;
    mainWin.setTitle("Photo Album");

    ScrollPane center = new ScrollPane();
    // center.setMinWidth(800);
    center.setFitToWidth(true);

    gallery = new FlowPane();
    gallery.setPadding(new Insets(5, 5, 5, 5));
    gallery.setAlignment(Pos.CENTER);
    gallery.setColumnHalignment(HPos.CENTER);
    gallery.setRowValignment(VPos.CENTER);
    gallery.setHgap(10);
    gallery.setVgap(10);
    gallery.setPrefWrapLength(785);

    for (int i = 0; i < album.getImageData().size(); i++) {
        gallery.getChildren()
                .add(album.getImageData().get(i).getImageBtn());
    }

    center.setContent(gallery);

    BorderPane borderPane = new BorderPane();
    borderPane.setCenter(center);
    borderPane.setTop(menuBar);

    mainScene = new Scene(borderPane, 800, 600);
    mainScene.getStylesheets().add("styles.css");
    mainWin.setScene(mainScene);
    mainWin.setResizable(false);
    mainWin.show();
}

private void refreshGallery() {

    gallery.getChildren().clear();

    for (int i = 0; i < Album.getImageData().size(); i++) {
        gallery.getChildren()
                .add(Album.getImageData().get(i).getImageBtn());
    }
}
}

Я изменил всего 3 строки кода. Я надеюсь, что это поможет вам. и любой? S комментировать

Другие вопросы по тегам