JavaFX与TableView监听器有关

时间:2017-04-04 22:44:32

标签: javafx tableview listener fxml

所以我对JavaFX很陌生,并且一直在努力让听众在我的TableView上正常工作。我发现了几个不同的例子,但似乎没有一个像我期望的那样工作,或者我的代码中的其他地方存在一个阻止它工作的问题。

以下是我的initialize方法中侦听器代码的片段:

bookList.addListener((Change<? extends LibraryBook> c) -> {
           while (c.next()) {
               if (c.wasAdded()) {
                   MainController.getInstance().setFieldChange(true);
               }
               if (c.wasRemoved()) {
                   MainController.getInstance().setFieldChange(true);
               }
               if (c.wasUpdated()) {
                   MainController.getInstance().setFieldChange(true);
               }
           }
    });

    tvLibraryTable.setItems(bookList);
    bookName.setCellValueFactory(new PropertyValueFactory<>("book"));
    quantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));

我的observableList目前在我的构造函数中初始化(但我也将它移动到其他几个地方:

if(library.getBooks() != null) {
        this.newList = new ArrayList<LibraryBook>(library.getBooks());
        this.bookList = FXCollections.observableArrayList(library.getBooks());

因此,在我的控制器视图的其余部分,我有按钮可以从列表中添加和删除书籍,如果您双击列表中的项目,则可以更新数量。我正在为所有这些选项使用自定义模式对话框。当我从对话框返回结果时,我更新了我的bookList,我认为这就是我的问题所在。这是控制器类的完整代码。而且我很确定代码非常粗糙,但它目前正在运行...减去tableview监听器。

package app;

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfWriter;

import javafx.beans.Observable;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextInputDialog;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.util.Pair;
import javafx.util.converter.NumberStringConverter;
import javafx.scene.control.Alert.AlertType;
import models.Book;
import models.Library;
import models.LibraryBook;
import models.ValidationException;
import view.ViewType;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Dialog;
public class LibraryDetailViewController implements Initializable {

    private static Logger logger = LogManager.getLogger();
    private Library library;
    private Library origLibrary;
    private List<LibraryBook> newList;
    private ObservableList<LibraryBook> bookList;

    @FXML private TextField tfLibrary;
    @FXML private TableView<LibraryBook> tvLibraryTable;
    @FXML private TableColumn<LibraryBook, Book> bookName;
    @FXML private TableColumn<LibraryBook, Integer> quantity;
    @FXML private ComboBox<Book> cbBook;
    @FXML private Button saveButton, auditTrail, inventoryReport, addBook, deleteBook;
    @FXML private Label saveLabel;

    public LibraryDetailViewController(Library library) {
        this.library = library;
        this.origLibrary = new Library(library);
        if(library.getBooks() != null) {
            this.newList = new ArrayList<LibraryBook>(library.getBooks());
            this.bookList = FXCollections.observableArrayList(library.getBooks());
        } else {
            this.newList =  new ArrayList<LibraryBook>();
            this.bookList = FXCollections.observableArrayList();
        }
    }

    //event handler for buttons
    @FXML private void handleButtonAction(ActionEvent event) {
        Object source = event.getSource();

        if (source == saveButton) {
            try {
                saveLibraryFields();
                saveLabel.setText(library.saveLibrary(origLibrary));
                origLibrary = library;
            } catch (SQLException e) {
                logger.error(e);
                Alert alert = new Alert(AlertType.ERROR);
                alert.setHeaderText("Save Error");
                alert.setContentText("Error saving data. Please check fields and try again.");
                alert.showAndWait();
                //revert to original model data on error
                library = origLibrary;
            } catch (ValidationException e) {
                Alert alert = new Alert(AlertType.ERROR);
                alert.setHeaderText(e.getMessage());
                alert.showAndWait();
            }
        } else if(source == auditTrail) {
            if(library.getId() == 0) {
                Alert alert = new Alert(AlertType.WARNING);
                alert.setHeaderText("Audit Trail Error");
                alert.setContentText("No audit trail exists! Please save the library first.");
                alert.showAndWait();
            } else {
                MainController.getInstance().changeView(ViewType.LIBRARY_AUDITTRAIL, library);
            }
        } else if(source == inventoryReport) {
            try {
                createPdf("Inventory Report.pdf");
                Alert alert = new Alert(AlertType.INFORMATION);
                alert.setTitle("Success");
                alert.setHeaderText(null);
                alert.setContentText("The report has been created!");
                alert.showAndWait();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (DocumentException e) {
                e.printStackTrace();
            }
        } else if(source == addBook) {

            // create modal dialogue box
            List<Book> books = new ArrayList<Book>(MainController.getInstance().getBookGateway().getBooks());
            Dialog<Pair<Book, String>> dialog = new Dialog<>();
            dialog.setTitle("Book List");
            dialog.setHeaderText("Add a book to the library");

            dialog.setGraphic(new ImageView(this.getClass().getResource("/view/book-stack.png").toString()));

            ButtonType okButtonType = new ButtonType("Ok", ButtonData.OK_DONE);
            dialog.getDialogPane().getButtonTypes().addAll(okButtonType, ButtonType.CANCEL);


            GridPane grid = new GridPane();
            grid.setHgap(10);
            grid.setVgap(10);
            grid.setPadding(new Insets(20, 150, 10, 10));

            ObservableList<Book> bookListOptions = FXCollections.observableArrayList(books);
            ChoiceBox<Book> cbBooks = new ChoiceBox<Book>(bookListOptions);
            TextField tfQuantity = new TextField();
            tfQuantity.setTextFormatter(new TextFormatter<>(new NumberStringConverter()));
            tfQuantity.setPromptText("Quantity");

            grid.add(new Label("Please select a book"), 0, 0);
            grid.add(cbBooks, 1, 0);
            grid.add(new Label("Please enter a quantity"), 0, 1);
            grid.add(tfQuantity, 1, 1);

            dialog.getDialogPane().setContent(grid);

            // convert results that were selected
            dialog.setResultConverter(dialogButton -> {
                if (dialogButton == okButtonType) {
                    return new Pair<>(cbBooks.getSelectionModel().getSelectedItem(), tfQuantity.getText());
                }
                return null;
            });

            // return results of dialogue box to main view and reinitialize tableView list
            Optional<Pair<Book, String>> result = dialog.showAndWait();
            result.ifPresent(book -> {
                    newList.add(new LibraryBook(book.getKey(), Integer.parseInt(book.getValue()), true));
                    library.setBooks(newList);
                    bookList = FXCollections.observableArrayList(library.getBooks());
                    bookName.setCellValueFactory(new PropertyValueFactory<>("book"));
                    quantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
                    tvLibraryTable.setItems(bookList);
            });
        } else if(source == deleteBook) {
            newList.remove(tvLibraryTable.getSelectionModel().getSelectedItem());
            library.setBooks(newList);
            bookList = FXCollections.observableArrayList(library.getBooks());
            bookName.setCellValueFactory(new PropertyValueFactory<>("book"));
            quantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
            tvLibraryTable.setItems(bookList);
        }
    }

    /**
     * event handler for double clicking a book from the ListView
     *
     * @param event
     */
    @FXML private void handleMouseClick(MouseEvent event) {
        if(event.getButton().equals(MouseButton.PRIMARY)){
            if(event.getClickCount() == 2){
                if (tvLibraryTable.getSelectionModel().isEmpty()) {
                    Alert alert = new Alert(AlertType.WARNING);
                    alert.setHeaderText("Update Quantity Error");
                    alert.setContentText("No book was selected!");
                    alert.showAndWait();
                } else {
                    LibraryBook lb = tvLibraryTable.getSelectionModel().getSelectedItem();
                    TextInputDialog dialog = new TextInputDialog();
                    dialog.setTitle("Edit Book");
                    dialog.setHeaderText("Please enter the new quantity.");
                    dialog.setContentText("Quantity:");

                    Optional<String> result = dialog.showAndWait();
                    result.ifPresent(quantity -> {
                        lb.setQuantity(Integer.parseInt(quantity));
                        tvLibraryTable.refresh();
                    });
                }
            }
        }
    }

    public void saveLibraryDetail() {
        try {
            saveLibraryFields();
            library.saveLibrary(origLibrary);
            origLibrary = library;
        } catch (SQLException e) {
            logger.error(e);
            library = origLibrary;
        } catch (ValidationException e) {
            Alert alert = new Alert(AlertType.ERROR);
            alert.setHeaderText(e.getMessage());
            alert.showAndWait();
        }
    }

    public void saveLibraryFields() {
        library.setLibraryName(tfLibrary.getText());
        library.setBooks(tvLibraryTable.getItems());
    }

    private class MyFooter extends PdfPageEventHelper {
        Font ffont = new Font(Font.FontFamily.UNDEFINED, 18, Font.ITALIC);

        public void onEndPage(PdfWriter writer, Document document) {
            PdfContentByte cb = writer.getDirectContent();
            Phrase header = new Phrase(library.getLibraryName(), ffont);
            ColumnText.showTextAligned(cb, Element.ALIGN_CENTER,
                    header,
                    (document.right() - document.left()) / 2 + document.leftMargin(),
                    document.top() + 10, 0);
        }
    }

    public void createPdf(String filename) throws IOException, DocumentException {
        Document document = new Document();

        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
        MyFooter event = new MyFooter();
        writer.setPageEvent(event);

        document.open();

        //create table with 4 evenly-spaced columns
        PdfPTable table = new PdfPTable(4);
        table.addCell("Title:");
        table.addCell("Author:");
        table.addCell("Publisher:");
        table.addCell("Quantity:");
        table.setHeaderRows(1);
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
        for(int aw = 0; aw < library.getBooks().size(); aw++){
            table.addCell(library.getBooks().get(aw).getBook().getTitle());
            table.addCell(library.getBooks().get(aw).getBook().getAuthor().getFullName());
            table.addCell(library.getBooks().get(aw).getBook().getPublisher());
            table.addCell(String.valueOf(library.getBooks().get(aw).getQuantity()));
            table.completeRow();
        }
        document.add(table);

        document.close();
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        //init field values
        tfLibrary.setText(library.getLibraryName());

        /*if(library.getBooks() != null) {
            ObservableList<LibraryBook> booksList = FXCollections.observableArrayList(library.getBooks());
            bookName.setCellValueFactory(new PropertyValueFactory<>("book"));
            quantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
            tvLibraryTable.setItems(booksList);
        }*/

        //event listeners for field changes
        if(library.getId() == 0) {
            MainController.getInstance().setFieldChange(true);
        }

        tfLibrary.textProperty().addListener(new ChangeListener<String>() {
            public void changed(ObservableValue<? extends String> observable,
                            String oldValue, String newValue) {
                MainController.getInstance().setFieldChange(true);
            }
        });

        /**
         *  Unable to get listener for tableview to work properly :(
         *
        ObservableList<LibraryBook> bookList = FXCollections.observableArrayList(book ->
            new Observable[] {
                (Observable) book.getBook(),
                book.getObsQuantity()
            });
        */
        bookList.addListener((Change<? extends LibraryBook> c) -> {
               while (c.next()) {
                   if (c.wasAdded()) {
                       MainController.getInstance().setFieldChange(true);
                   }
                   if (c.wasRemoved()) {
                       MainController.getInstance().setFieldChange(true);
                   }
                   if (c.wasUpdated()) {
                       MainController.getInstance().setFieldChange(true);
                   }
               }
        });

        tvLibraryTable.setItems(bookList);
        bookName.setCellValueFactory(new PropertyValueFactory<>("book"));
        quantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
    }
}

这是我的fxml代码:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane id="pane-bg" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Label layoutX="106.0" layoutY="63.0" text="Library Name:">
         <font>
            <Font name="Serif Regular" size="18.0" />
         </font>
      </Label>
      <Button fx:id="saveButton" layoutX="465.0" layoutY="126.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Save">
         <font>
            <Font name="Serif Regular" size="14.0" />
         </font>
      </Button>
      <TextField fx:id="tfLibrary" layoutX="224.0" layoutY="61.0" />
      <Label fx:id="saveLabel" layoutX="431.0" layoutY="277.0" textFill="#f20909">
         <font>
            <Font name="Serif Regular" size="18.0" />
         </font>
      </Label>
      <Button fx:id="auditTrail" layoutX="440.0" layoutY="170.0" mnemonicParsing="false" onAction="#handleButtonAction" text="View Audit Trail" />
      <TableView fx:id="tvLibraryTable" editable="true" layoutX="174.0" layoutY="104.0" onMouseClicked="#handleMouseClick" prefHeight="215.0" prefWidth="248.0">
        <columns>
          <TableColumn fx:id="bookName" prefWidth="169.0" text="Book Name" />
            <TableColumn fx:id="quantity" prefWidth="77.0" text="Quantity" />
        </columns>
      </TableView>
      <Button fx:id="inventoryReport" layoutX="437.0" layoutY="215.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Inventory Report" />
      <Button fx:id="addBook" layoutX="174.0" layoutY="325.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Add Book">
         <font>
            <Font name="Serif Regular" size="14.0" />
         </font>
      </Button>
      <Button fx:id="deleteBook" layoutX="331.0" layoutY="325.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Delete Book">
         <font>
            <Font name="Serif Regular" size="14.0" />
         </font>
      </Button>
      <!-- <Button fx:id="backToListButton" layoutX="309.0" layoutY="286.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Back to Author List" /> -->
   </children>
</AnchorPane>

0 个答案:

没有答案