Панель обновления 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 комментировать