2016-05-27 2 views
0

Я новичок в javafx, так голый со мной.Показать информацию о продажах в TreeTableView

То, что я хочу достичь, более или менее имеет объект Sale, который при расширении отображает объекты SaleTransaction под этим объектом Sale. Аналогично будет отображен на экране в этом образе от Code Project

enter image description here

, где я могу также выполнять другие функции CRUD кроме только чтения (т.е. создания, обновления и удаления).

Я попытался его реализацию с помощью табличного дерева, как так: не отображается

List<CreditSale> lstData = new ArrayList<CreditSale>(creditsaleservice.findAllCreditSales()); 

    TreeItem root = new TreeItem<>(); 
    for (CreditSaleTransaction cst : lstData.get(0).getCreditSaleTransaction()) { 
     root.getChildren().addAll(new TreeItem<>(cst)); 
    } 


    TreeTableColumn<CreditSaleTransaction, Product> productColumn = new TreeTableColumn<>("Product Name"); 

    productColumn.setPrefWidth(150); 
    productColumn.setEditable(true); 

    productColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<CreditSaleTransaction, Product> p) 
      -> new ReadOnlyObjectWrapper<>(p.getValue().getValue().getProduct())); 


    TreeTableColumn<CreditSaleTransaction, Float> quantityColumn = new TreeTableColumn<>("Quantity"); 
    quantityColumn.setPrefWidth(150); 
    quantityColumn.setEditable(true); 
    quantityColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<CreditSaleTransaction,Float> p) 
      -> new ReadOnlyObjectWrapper<>(p.getValue().getValue().getAmount())); 

    TreeTableColumn<CreditSaleTransaction, Float> unitPColumn = new TreeTableColumn<>("Unit Price"); 
    unitPColumn.setPrefWidth(150); 
    unitPColumn.setEditable(true); 
    unitPColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<CreditSaleTransaction,Float> p) 
      -> new ReadOnlyObjectWrapper<>(p.getValue().getValue().getUnitPrice())); 

    TreeTableView<CreditSaleTransaction> treeTableView = new TreeTableView<>(); 
    treeTableView.setRoot(root); 

    treeTableView.getColumns().addAll(productColumn,quantityColumn,unitPColumn); 
    treeviewanchorpane.getChildren().add(treeTableView); 

но ничего. Любое содействие желаемому результату высоко ценится.

+1

Ваша ссылка «Код проекта» нарушается, когда я нажимаю на него. Также ваш вопрос нечеткий и открытый, с чем именно вы хотите помочь? В качестве примечания, если вы новичок в JavaFX, я бы предложил начать с разработки более простых пользовательских интерфейсов, а не TreeTableView, что, вероятно, является самым сложным элементом управления в стандартном API JavaFX. – jewelsea

+0

Я только что установил ссылку. Я хочу, чтобы я мог отображать информацию о продаже, как когда она была сделана, общая сумма также отображает каждую информацию о транзакциях продажи, как сейчас, какой продукт был продан, цена за единицу, количество в раскрывающемся списке –

+0

Возможно, вы захотите добавить свой TreeTableView в другой макет. AnchorPane почти никогда не является хорошим выбором. Попробуйте BorderPane или StackPane. И вы добавляете эту панель в сцену и передаете эту сцену на основной этап, верно? – VGR

ответ

1

Это можно достичь такой же производительности с TreeTableView условии, что вы не возражаете потерять эти внутренние заголовки:

Inner headers

Jewelsea имеет хороший пример того, как подойти к этому здесь:


Предлагаемый подход для пользовательской реализации

Если заголовки важны, вы можете создать собственный элемент управления, чтобы получить желаемый макет. Мое предложение было бы кратным TitledPane в контейнере, таком как VBox, с внешним элементом в качестве заголовка и внутренними элементами в качестве содержимого в пределах TableView. TitledPane ожидает String как название, но с комбинацией и setContentDisplay, это может быть изменен на Node позволяет поддерживать последовательную компоновки

Такой подход позволил бы несколько элементов (как внутренних и внешних), чтобы быть видимый одновременно.

В случае, если вы только хотите, чтобы быть в состоянии видеть внутреннюю по одному, Accordian будет подходящей альтернативой VBox, поскольку это позволяет только один TitledPane быть расширен в любой момент времени

Оба TitledPane и Accordian покрыты в этом руководстве Oracle:

(Я вкл uded пример того, как можно было бы реализовать этот подход и изображение, отображающее выход в конце этого ответа)


Мониторинг изменения

JavaFX предлагает ObservableList, который уведомляет слушателей каких-либо изменений. Эффективное использование этого позволит пользовательскому интерфейсу автоматически отражать любые изменения.

Например, ListChangeListener для определения того, когда элементы были добавлены/удалены, что покрыто here.

Примечание: Если дочерний элемент в ObservableList изменяется (например, цена в пределах вложенного пункта продаж), не может быть событие обновления. В этой ситуации экстрактор должен быть добавлен в список, который определяет дополнительные значения должны быть соблюдены, обжиг обновления событий, если какие-либо из этих значений изменить

Есть также целый ряд свойств/переплетов доступен, которые покрыты в следующих частях документации:

(пример содержит примеры того, как использовать приведенное выше)


Предложения по реализации функциональности CR на TableView-х:

  • Созданием Button бара: Вы можете поместить это под каждый TableView или nestedView, с использованием выбранных ячеек определить, когда для того, чтобы кнопки и какие объекты для изменения
  • Разместить EventHandler на TableView: См setOnEditCommint()
  • Добавление пользовательских ячеек в TableView: Существует несколько примеров создания пользовательских TableCell, которые удаляют строку при нажатии.

    Например: Delete Rows using row buttons in Javafx TableView
  • Использование ContextMenu «s

Пример:

Я добавил комментарии кода, где это возможно, но если есть какие-либо вопросы или предлагаемые улучшения пожалуйста, оставьте комментарий

NestedTableView:

public class NestedTableView extends VBox { 
    private ObservableList<Node> titledPanes = FXCollections.observableArrayList(); 
    private Region parent; 

    public NestedTableView(Region parent, ObservableList<ProductBundle> bundlesToDisplay){ 
     this.parent = parent; 
     VBox nestedView = new VBox(); 
     Bindings.bindContentBidirectional(nestedView.getChildren(), titledPanes); 
     titledPanes.addAll(bundlesToDisplay.stream() 
       .map(TablePane::new).collect(Collectors.toList())); 
     getChildren().setAll(createHeader(), nestedView); 
     getStylesheets().add("CSS/nestedTableViewStyles.css"); 
    } 

    private HBox createHeader(){ 
     //Set up widths to align with the content headers beneath the header 
     Label symbol = new Label("#"); 
     symbol.setPrefWidth(25); //Sum of the values used by the "arrow" region 

     Label productId = new Label("Product Id"); 
     productId.prefWidthProperty().bind(parent.widthProperty().multiply(0.15)); 

     Label productName = new Label("Product Name"); 
     productName.prefWidthProperty().bind(parent.widthProperty().multiply(0.35)); //Give name extra space 

     Label amount = new Label("Amount"); 
     amount.prefWidthProperty().bind(parent.widthProperty().multiply(0.15)); 

     Label date = new Label("Order Date"); 
     date.prefWidthProperty().bind(parent.widthProperty().multiply(0.15)); 

     Label quantityAvailable = new Label("#Available"); 
     quantityAvailable.prefWidthProperty().bind(parent.widthProperty().multiply(0.15)); 

     HBox header = new HBox(symbol, productId, productName, amount, date, quantityAvailable); 
     header.getStyleClass().add("header"); 
     return header; 
    } 

    private class TablePane extends TitledPane { 
     private ProductBundle productBundle; 

     private HBox header; 
     private TableView contentTableView; 
     private MenuItem addToBundle, deleteBundle; 

     public TablePane(ProductBundle productBundle){ 
      this.productBundle = productBundle; 
      setupMenuItems(); 
      setupContentHeader(); 
      setGraphic(header); 
      setContentDisplay(ContentDisplay.GRAPHIC_ONLY); 
      if(!productBundle.getBundleItems().isEmpty()){ 
       createTableView(); 
       setContent(contentTableView); 
      } 

      //Only display the expandable "arrow" if there is content to display 
      collapsibleProperty().bind(contentProperty().isNotNull()); 
      //If the "arrow" isn't displayed, pad the area to mimic the arrow being present to align headers 
      header.paddingProperty().bind(
        Bindings.when(collapsibleProperty()).then(Insets.EMPTY).otherwise(new Insets(0,0,0,15))); 
      /* For testing purposes. With more rows this will clutter the UI 
       ToDo: add logic to determine how many panes to expand before the viewport has been filled 
      */ 
      setExpanded(true); 
     } 

     private void setupMenuItems(){ 
      addToBundle = new MenuItem("Add to bundle"); 
      addToBundle.setOnAction(event -> { 
       //ToDo: Add CRUD create logic here 
       System.out.println("Add to bundle: " + productBundle.idProperty()); 
      }); 
      deleteBundle = new MenuItem("Delete bundle"); 
      deleteBundle.setOnAction(event -> { 
       //ToDo: Add CRUD delete logic here 
       System.out.println("Delete bundle: " + productBundle.idProperty()); 
      }); 
     } 

     private void setupContentHeader(){ 
      header = new HBox(); 
      //Bind the content header to the root so that it aligned with the initial header 
      header.prefWidthProperty().bind(parent.widthProperty()); 
      header.maxWidthProperty().bind(parent.widthProperty()); 

      /* Set up each TextField with widths to align with the TableView 
       Each TextField is editable with the exception of id as it would be the primary key 
       and amount as it's value is calculated from the sub items */ 
      TextField id = new TextField(); 
      id.setEditable(false); 
      modifyTextFieldContextMenu(id); 
      id.textProperty().bind(productBundle.idProperty()); 
      id.prefWidthProperty().bind(header.widthProperty().multiply(0.15)); 

      TextField name = new TextField(); 
      modifyTextFieldForCRUDFunctionality(name); 
      name.textProperty().bindBidirectional(productBundle.nameProperty()); 
      name.prefWidthProperty().bind(header.widthProperty().multiply(0.35)); //Give name extra space 

      TextField amount = new TextField(); 
      amount.setEditable(false); 
      Bindings.bindBidirectional(amount.textProperty(), productBundle.amountProperty(), 
        new NumberStringConverter(NumberFormat.getCurrencyInstance(Locale.US))); 
      amount.prefWidthProperty().bind(header.widthProperty().multiply(0.15)); 

      TextField date = new TextField(); 
      modifyTextFieldForCRUDFunctionality(date); 
      date.textProperty().bind(productBundle.orderDateProperty()); 
      date.prefWidthProperty().bind(header.widthProperty().multiply(0.15)); 

      TextField quantityRemaining = new TextField(); 
      modifyTextFieldForCRUDFunctionality(quantityRemaining); 
      //Only display a quantity if it's a valid value (to match example screen shot) 
      quantityRemaining.textProperty().bind(
        Bindings.when(productBundle.quantityAvailableProperty().greaterThan(0)) 
          .then(productBundle.quantityAvailableProperty().asString()).otherwise("N/A")); 
      quantityRemaining.prefWidthProperty().bind(header.widthProperty().multiply(0.15)); 

      header.getChildren().setAll(id, name, amount, date, quantityRemaining); 
      header.getStyleClass().add("content-header"); 
     } 

     private void modifyTextFieldContextMenu(TextField textField){ 
      TextFieldSkin skin = new TextFieldSkin(textField){ 
       @Override 
       public void populateContextMenu(ContextMenu contextMenu) { 
        super.populateContextMenu(contextMenu); 
        contextMenu.getItems().add(0, addToBundle); 
        contextMenu.getItems().add(1, deleteBundle); 
        contextMenu.getItems().add(2, new SeparatorMenuItem()); 
       } 
      }; 
      textField.setSkin(skin); 
     } 

     private void modifyTextFieldForCRUDFunctionality(TextField textField){ 
      textField.setEditable(true); 
      textField.focusedProperty().addListener(new ChangeListener<Boolean>() { 
       private String previousText; 
       @Override 
       public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { 
        String currentText = textField.getText(); 
        if(newValue){ 
         previousText = currentText; 
        } 
        //ToDo: Add CRUD update logic here 
        else if(!previousText.equals(currentText)){ 
         System.out.println("Value has been changed from: " + previousText + " to: " + currentText); 
        } 
       } 
      }); 
     } 

     private void createTableView(){ 
      TableColumn<BundleItem, String> idColumn = new TableColumn<>("#ID"); 
      idColumn.setCellValueFactory(param -> param.getValue().getItem().itemIdProperty()); 

      TableColumn<BundleItem, String> nameColumn = new TableColumn<>("Item"); 
      nameColumn.setCellValueFactory(param -> param.getValue().getItem().itemNameProperty()); 

      TableColumn<BundleItem, String> amountColumn = new TableColumn<>("Amount"); 
      amountColumn.setCellValueFactory(param -> param.getValue().getItem().amountProperty().asString("$%.2f")); 

      TableColumn<BundleItem, Number> quantityColumn = new TableColumn<>("Qty"); 
      quantityColumn.setCellValueFactory(param -> param.getValue().quantityProperty()); 

      TableView<BundleItem> tableView = new TableView<>(productBundle.getBundleItems()); 
      tableView.setPadding(new Insets(10)); 
      //Equal column widths 
      tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); 
      tableView.getColumns().setAll(idColumn, nameColumn, amountColumn, quantityColumn); 
      //Only show visible shows 
      tableView.setFixedCellSize(30); 
      tableView.prefHeightProperty().bind(Bindings.size(productBundle.getBundleItems()) 
        .multiply(tableView.getFixedCellSize()).add(tableView.getFixedCellSize()*1.5)); 
      contentTableView = tableView; 
     } 
    } 
} 

продаж объектов, связанных с:

public class ProductBundle { 
    private ObservableList<BundleItem> bundleItems = FXCollections.observableArrayList(); 
    private SimpleStringProperty productId, productName, orderDate; 
    private SimpleDoubleProperty amount = new SimpleDoubleProperty(); 
    private SimpleIntegerProperty quantityAvailable; 

    private ProductBundle(String productId, String productName, String orderDate, int quantityAvailable){ 
     this.productId = new SimpleStringProperty(productId); 
     this.productName = new SimpleStringProperty(productName); 
     this.orderDate = new SimpleStringProperty(orderDate); 
     this.quantityAvailable = new SimpleIntegerProperty(quantityAvailable); 
    } 

    public ProductBundle(String productId, String productName, String orderDate, 
         int quantityAvailable, ObservableList<BundleItem> bundleItems){ 
     this(productId, productName, orderDate, quantityAvailable); 
     //Setup an extractor to "Observe" changes on the amount/quantity of any items in the bundle 
     this.bundleItems = FXCollections.observableArrayList(new Callback<BundleItem, Observable[]>() { 
      @Override 
      public Observable[] call(BundleItem param) { 
       return new Observable[]{param.amountProperty(), param.quantityProperty()}; 
      } 
     }); 
     this.bundleItems.addAll(bundleItems); 
     //Calculate the total worth of this bundle 
     amount.bind(Bindings.createDoubleBinding(()-> 
       bundleItems.stream().collect(Collectors.summingDouble(BundleItem::getAmount)), this.bundleItems) 
       .multiply(quantityAvailable)); 
    } 

    public ProductBundle(String productId, String productName, String orderDate, 
         int quantityAvailable, double amount){ 
     this(productId, productName, orderDate, quantityAvailable); 
     this.amount.set(amount); 
    } 

    public ObservableList<BundleItem> getBundleItems(){ 
     return bundleItems; 
    } 

    public SimpleStringProperty idProperty(){ 
     return productId; 
    } 

    public SimpleStringProperty nameProperty(){ 
     return productName; 
    } 

    public SimpleIntegerProperty quantityAvailableProperty(){ 
     return quantityAvailable; 
    } 

    public SimpleStringProperty orderDateProperty(){ 
     return orderDate; 
    } 

    public SimpleDoubleProperty amountProperty(){ 
     return amount; 
    } 

    public double getAmount(){ 
     return amount.get(); 
    } 
} 

public class BundleItem { 
    private Item item; 
    private SimpleIntegerProperty quantity; 
    private SimpleDoubleProperty amount = new SimpleDoubleProperty(); 

    public BundleItem(Item item, int quantity){ 
     this.item = item; 
     this.quantity = new SimpleIntegerProperty(quantity); 
     amount.bind(item.amountProperty().multiply(quantity)); 
    } 

    public Item getItem(){ 
     return item; 
    } 

    public SimpleIntegerProperty quantityProperty(){ 
     return quantity; 
    } 

    public SimpleDoubleProperty amountProperty(){ 
     return amount; 
    } 

    public double getAmount(){ 
     return amount.get(); 
    } 
} 

public class Item { 
    private SimpleStringProperty itemId, itemName; 
    private SimpleDoubleProperty amount; 

    public Item(String itemId, String itemName, double amount){ 
     this.itemId = new SimpleStringProperty(itemId); 
     this.itemName = new SimpleStringProperty(itemName); 
     this.amount = new SimpleDoubleProperty(amount); 
    } 

    public SimpleStringProperty itemIdProperty(){ 
     return itemId; 
    } 

    public SimpleStringProperty itemNameProperty(){ 
     return itemName; 
    } 

    public SimpleDoubleProperty amountProperty(){ 
     return amount; 
    } 

    public double getAmount(){ 
     return amount.get(); 
    } 

    public void setAmount(double newValue){ 
     amount.set(newValue); 
    } 
} 

nestedTableViewStyles.css:

.header { 
    -fx-background-color: darkorange; 
    -fx-pref-height: 30; 
    -fx-padding: 5 0 0 0; 
} 

.header > .label { 
    -fx-text-fill: white; 
} 

.header > .label, .content-header > .text-field { 
    -fx-alignment: center; 
    -fx-text-alignment: center; 
} 

.content-header > .text-field, .content-header > .text-field:focused { 
    /* Make the TextField's display similar to a Label */ 
    -fx-background-color: transparent; 
} 

.content-header, .titled-pane > .title, .table-view { 
    -fx-background-color: white; 
} 

.titled-pane > .title { 
    -fx-border-color: lightgray; 
    -fx-border-width: 0 0 1 0; 
} 

.table-view { 
    -fx-table-cell-border-color: transparent; 
} 

.table-view .column-header-background { 
    -fx-border-radius: 5 5 0 0; 
    -fx-background-radius: 5 5 0 0; 
} 

.table-view .column-header-background, .table-row-cell { 
    -fx-background-color: lightgray; 
    -fx-border-color: gray; 
    -fx-border-width: 0 0 1 0; 
} 

.table-view .column-header-background .label { 
    -fx-background-color: lightgray; 
    -fx-text-fill: black; 
    -fx-font-weight: bold; 
} 

.table-view .column-header { 
    -fx-background-color: transparent; 
} 

.table-column { 
    -fx-alignment: center; 
} 

Использование:

public class NestedTableViewExample extends Application { 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     ObservableList<ProductBundle> bundles = 
       FXCollections.observableArrayList(
         new ProductBundle("1001456", "Spring Season Gift", "02/14/2015", 1, 
           FXCollections.observableArrayList(
             new BundleItem(new Item("17890", "PS 3", 150.00), 1), 
             new BundleItem(new Item("17891", "Heart shape ring", 100.00), 1) 
           )), 
         new ProductBundle("1001457", "Christmas Season Gift", "04/14/2015", 1, 
           FXCollections.observableArrayList(
             new BundleItem(new Item("17900", "Chocolate Giftbox", 150.00), 1), 
             new BundleItem(new Item("17901", "Xbox 360", 199.00), 1) 
           )), 
         new ProductBundle("1001458", "Birthday Gift", "", 1, 200) 
       ); 

     VBox root = new VBox(); 
     root.getChildren().setAll(new NestedTableView(root, bundles)); 
     Scene scene = new Scene(root, 500, 500); 
     primaryStage.setScene(scene); 
     primaryStage.setTitle("Nested TableView example"); 
     primaryStage.show(); 
    } 
} 


Выход:

Nested TableView Example

+1

Фантастический ... Амазинец ... Удивительный –

Смежные вопросы