2013-05-03 36 views
6

Tôi có một dự án xoay sử dụng nhiều JTables để hiển thị tất cả mọi thứ từ văn bản đến bảng điều khiển cho đến khi kết hợp các nút và hộp kiểm. Tôi đã có thể thực hiện điều này bằng cách ghi đè lên trình kết xuất ô của bảng để trả về các JComponents chung. Câu hỏi của tôi là một bảng tương tự có thể được thực hiện bằng cách sử dụng JavaFx?Bảng JavaFX - cách thêm thành phần?

Tôi muốn cập nhật tất cả các bảng trong dự án để sử dụng JavaFx để hỗ trợ hầu hết các cử chỉ. Có vẻ như TableView là thành phần JavaFx để sử dụng và tôi đã thử thêm các nút vào nó nhưng khi được hiển thị nó sẽ hiển thị giá trị chuỗi của nút, chứ không phải chính nút đó. Có vẻ như tôi phải ghi đè lên nhà máy sản xuất hàng hoặc nhà máy di động để làm những gì tôi muốn nhưng không có nhiều ví dụ. Đây là mã tôi sử dụng làm ví dụ hiển thị nút dưới dạng chuỗi.

import javax.swing.JButton; 

import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.geometry.Insets; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.TextField; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.layout.VBox; 
import javafx.scene.text.Font; 
import javafx.stage.Stage; 

public class GestureEvents extends Application { 

    private TableView<Person> table = new TableView<Person>(); 
    private final ObservableList<Person> data = 
     FXCollections.observableArrayList(
      new Person("Jacob", "Smith", "[email protected]","The Button"), 
      new Person("Isabella", "Johnson", "[email protected]","The Button"), 
      new Person("Ethan", "Williams", "[email protected]","The Button"), 
      new Person("Emma", "Jones", "[email protected]","The Button"), 
      new Person("Michael", "Brown", "[email protected]","The Button") 

     ); 

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

    @Override 
    public void start(Stage stage) { 
     Scene scene = new Scene(new Group()); 
     stage.setTitle("Table View Sample"); 
     stage.setWidth(450); 
     stage.setHeight(500); 

     final Label label = new Label("Address Book"); 
     label.setFont(new Font("Arial", 20)); 

     table.setEditable(true); 

     TableColumn firstNameCol = new TableColumn("First Name"); 
     firstNameCol.setMinWidth(100); 
     firstNameCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("firstName")); 

     TableColumn lastNameCol = new TableColumn("Last Name"); 
     lastNameCol.setMinWidth(100); 
     lastNameCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("lastName")); 

     TableColumn emailCol = new TableColumn("Email"); 
     emailCol.setMinWidth(200); 
     emailCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("email")); 

     TableColumn btnCol = new TableColumn("Buttons"); 
     btnCol.setMinWidth(100); 
     btnCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("btn")); 

     table.setItems(data); 
     table.getColumns().addAll(firstNameCol, lastNameCol, emailCol, btnCol); 

     final VBox vbox = new VBox(); 
     vbox.setSpacing(5); 
     vbox.setPadding(new Insets(10, 0, 0, 10)); 
     vbox.getChildren().addAll(label, table); 

     ((Group) scene.getRoot()).getChildren().addAll(vbox); 

     stage.setScene(scene); 
     stage.show(); 
    } 

    public static class Person { 

     private final SimpleStringProperty firstName; 
     private final SimpleStringProperty lastName; 
     private final SimpleStringProperty email; 
     private final JButton btn; 

     private Person(String fName, String lName, String email, String btn) { 
      this.firstName = new SimpleStringProperty(fName); 
      this.lastName = new SimpleStringProperty(lName); 
      this.email = new SimpleStringProperty(email); 
      this.btn = new JButton(btn); 
     } 

     public String getFirstName() { 
      return firstName.get(); 
     } 

     public void setFirstName(String fName) { 
      firstName.set(fName); 
     } 

     public String getLastName() { 
      return lastName.get(); 
     } 

     public void setLastName(String fName) { 
      lastName.set(fName); 
     } 

     public String getEmail() { 
      return email.get(); 
     } 

     public void setEmail(String fName) { 
      email.set(fName); 
     } 

     public JButton getBtn(){ 
      return btn; 
     } 

     public void setBtn(String btn){ 

     } 
    } 

    public static class ButtonPerson{ 
     private final JButton btn; 
     private ButtonPerson(){ 
      btn = new JButton("The Button"); 
     } 
     public JButton getButton(){ 
      return btn; 
     } 
    } 
} 

Chỉnh sửa: Sau khi điều tra thêm, tôi đã tìm thấy các ví dụ ghi đè lên các loại ô được xác định trước như văn bản và séc. Nó không phải là rõ ràng nếu bất kỳ thành phần jfx chung có thể được đặt trong một tế bào giống như một JFXPanel. Điều này là không giống như JTable, kể từ khi sử dụng một JTable tôi có thể đặt bất cứ điều gì mà kế thừa từ JComponent miễn là tôi thiết lập các lớp render một cách chính xác. Nếu ai đó biết làm thế nào (hoặc nếu nó thậm chí có thể) để đặt một JFXPanel trong một tế bào hoặc một thành phần JFx chung khác như một nút đó sẽ rất hữu ích.

Trả lời

24

Các vấn đề với thực hiện của bạn

Bạn có thể nhúng các thành phần trong các ứng dụng JavaFX Swing (bằng cách đặt các thành phần JavaFX trong một JFXPanel). Nhưng bạn không thể nhúng một thành phần Swing trong JavaFX (trừ khi bạn đang sử dụng JavaFX 8+).

JavaFX có thực hiện nút riêng, vì vậy không có lý do gì để nhúng javax.swing.JButton trên cảnh JavaFX, ngay cả khi bạn đang sử dụng Java8 và nó sẽ hoạt động.

Nhưng điều đó sẽ không khắc phục được tất cả sự cố của bạn. Bạn đang cung cấp một nhà máy giá trị ô cho cột nút của bạn để cung cấp các nút, nhưng không cung cấp nhà máy hiển thị ô tùy chỉnh. Nhà sản xuất biểu đồ ô mặc định hiển thị đầu ra toString trên giá trị ô tương ứng, đó là lý do tại sao bạn chỉ thấy biểu diễn chuỗi ký tự của nút trong triển khai bảng.

Bạn đang đặt các nút trong đối tượng Person của mình. Đừng làm thế - họ không thuộc về đó. Thay vào đó, hãy tạo động một nút trong nhà máy kết xuất ô. Điều này cho phép bạn tận dụng lợi thế của công nghệ luồng ảo của một bảng, theo đó nó chỉ tạo ra các nút trực quan cho những gì bạn có thể thấy trên màn hình, không phải cho mọi phần tử trong kho lưu trữ dữ liệu sao lưu của bảng. Ví dụ, nếu có 10 dòng có thể nhìn thấy trên màn hình và 10000 yếu tố trong bảng, chỉ có 10 nút sẽ được tạo ra chứ không phải là 10000.

Làm thế nào để sửa chữa nó

  1. Sử dụng JavaFX Button thay vì thay vì của javax.swing.JButton.
  2. Cung cấp một nhà máy hiển thị ô cho nút của bạn.
  3. Tạo nút trong ô bảng thay vì trong Người.
  4. Để đặt nút (hoặc bất kỳ nút JavaFX tùy ý nào) trong ô bảng, hãy sử dụng phương thức setGraphic của ô.

Đúng Mẫu Mã

Mã này kết hợp các bản sửa lỗi đề nghị và một vài cải tiến.

gift registry

import javafx.application.Application; 
import javafx.beans.property.*; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.*; 
import javafx.event.*; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.*; 
import javafx.scene.control.TableColumn.CellDataFeatures; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.image.*; 
import javafx.scene.layout.*; 
import javafx.scene.text.Font; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

public class GestureEvents extends Application { 
    private TableView<Person> table = new TableView<Person>(); 
    private final ObservableList<Person> data = 
     FXCollections.observableArrayList(
      new Person("Jacob", "Smith", "[email protected]","Coffee"), 
      new Person("Isabella", "Johnson", "[email protected]","Fruit"), 
      new Person("Ethan", "Williams", "[email protected]","Fruit"), 
      new Person("Emma", "Jones", "[email protected]","Coffee"), 
      new Person("Michael", "Brown", "[email protected]","Fruit") 

     ); 

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

    @Override 
    public void start(Stage stage) { 
     stage.setTitle("Table View Sample"); 

     final Label label = new Label("Address Book"); 
     label.setFont(new Font("Arial", 20)); 

     final Label actionTaken = new Label(); 

     table.setEditable(true); 

     TableColumn firstNameCol = new TableColumn("First Name"); 
     firstNameCol.setMinWidth(100); 
     firstNameCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("firstName")); 

     TableColumn lastNameCol = new TableColumn("Last Name"); 
     lastNameCol.setMinWidth(100); 
     lastNameCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("lastName")); 

     TableColumn emailCol = new TableColumn("Email"); 
     emailCol.setMinWidth(200); 
     emailCol.setCellValueFactory(
       new PropertyValueFactory<Person, String>("email")); 

     TableColumn<Person, Person> btnCol = new TableColumn<>("Gifts"); 
     btnCol.setMinWidth(150); 
     btnCol.setCellValueFactory(new Callback<CellDataFeatures<Person, Person>, ObservableValue<Person>>() { 
      @Override public ObservableValue<Person> call(CellDataFeatures<Person, Person> features) { 
       return new ReadOnlyObjectWrapper(features.getValue()); 
      } 
     }); 
     btnCol.setComparator(new Comparator<Person>() { 
      @Override public int compare(Person p1, Person p2) { 
      return p1.getLikes().compareTo(p2.getLikes()); 
      } 
     }); 
     btnCol.setCellFactory(new Callback<TableColumn<Person, Person>, TableCell<Person, Person>>() { 
      @Override public TableCell<Person, Person> call(TableColumn<Person, Person> btnCol) { 
      return new TableCell<Person, Person>() { 
       final ImageView buttonGraphic = new ImageView(); 
       final Button button = new Button(); { 
       button.setGraphic(buttonGraphic); 
       button.setMinWidth(130); 
       } 
       @Override public void updateItem(final Person person, boolean empty) { 
       super.updateItem(person, empty); 
       if (person != null) { 
        switch (person.getLikes().toLowerCase()) { 
        case "fruit": 
         button.setText("Buy fruit"); 
         buttonGraphic.setImage(fruitImage); 
         break; 

        default: 
         button.setText("Buy coffee"); 
         buttonGraphic.setImage(coffeeImage); 
         break; 
        } 

        setGraphic(button); 
        button.setOnAction(new EventHandler<ActionEvent>() { 
        @Override public void handle(ActionEvent event) { 
         actionTaken.setText("Bought " + person.getLikes().toLowerCase() + " for: " + person.getFirstName() + " " + person.getLastName()); 
        } 
        }); 
       } else { 
        setGraphic(null); 
       } 
       } 
      }; 
      } 
     }); 

     table.setItems(data); 
     table.getColumns().addAll(firstNameCol, lastNameCol, emailCol, btnCol); 

     final VBox vbox = new VBox(); 
     vbox.setSpacing(5); 
     vbox.setPadding(new Insets(10, 10, 10, 10)); 
     vbox.getChildren().addAll(label, table, actionTaken); 
     VBox.setVgrow(table, Priority.ALWAYS); 

     stage.setScene(new Scene(vbox)); 
     stage.show(); 
    } 

    public static class Person { 

     private final SimpleStringProperty firstName; 
     private final SimpleStringProperty lastName; 
     private final SimpleStringProperty email; 
     private final SimpleStringProperty likes; 

     private Person(String fName, String lName, String email, String likes) { 
      this.firstName = new SimpleStringProperty(fName); 
      this.lastName = new SimpleStringProperty(lName); 
      this.email = new SimpleStringProperty(email); 
      this.likes = new SimpleStringProperty(likes); 
     } 

     public String getFirstName() { 
      return firstName.get(); 
     } 

     public void setFirstName(String fName) { 
      firstName.set(fName); 
     } 

     public String getLastName() { 
      return lastName.get(); 
     } 

     public void setLastName(String fName) { 
      lastName.set(fName); 
     } 

     public String getEmail() { 
      return email.get(); 
     } 

     public void setEmail(String fName) { 
      email.set(fName); 
     } 

     public String getLikes() { 
      return likes.get(); 
     } 

     public void setLikes(String likes) { 
      this.likes.set(likes); 
     } 
    } 

    // icons for non-commercial use with attribution from: http://www.iconarchive.com/show/veggies-icons-by-iconicon/bananas-icon.html and http://www.iconarchive.com/show/collection-icons-by-archigraphs.html 
    private final Image coffeeImage = new Image(
     "http://icons.iconarchive.com/icons/archigraphs/collection/48/Coffee-icon.png" 
    ); 
    private final Image fruitImage = new Image(
     "http://icons.iconarchive.com/icons/iconicon/veggies/48/bananas-icon.png" 
    ); 
} 

Ngày Sử dụng các thành phần Swing trong JavaFX

Sau khi điều tra ví dụ hơn nữa tôi đã tìm thấy rằng ghi đè đồ họa di động sử dụng các loại tế bào được xác định trước như văn bản và kiểm tra. Nó không phải là rõ ràng nếu bất kỳ thành phần jfx chung có thể được đặt trong một tế bào giống như một JFXPanel.

Một JFXPanel là cho nhúng một thành phần JavaFX trong Swing không phải là một thành phần Swing trong JavaFX, do đó nó sẽ làm cho hoàn toàn không có tinh thần để cố gắng đặt một JFXPanel trong một JavaFX TableView. Đây là lý do tại sao bạn không tìm thấy ví dụ về bất cứ ai cố gắng một điều như vậy.

Điều này không giống như JTable, vì sử dụng JTable tôi có thể đặt bất kỳ thứ gì kế thừa từ JComponent miễn là tôi thiết lập lớp hiển thị chính xác.

Một JavaFX TableView tương tự như Swing JTable về vấn đề này. Thay vì một JComponent, một Node là khối xây dựng cơ bản cho JavaFX - chúng tương tự nhau, mặc dù khác nhau. Bạn có thể hiển thị bất kỳ Node nào trong JavaFX TableView miễn là bạn cung cấp cho nhà máy sản xuất ô thích hợp cho nó.

Trong Java 8, có SwingNode có thể chứa Swing JComponent. Một SwingNode cho phép bạn hiển thị bất kỳ thành phần Swing nào bên trong một bảng JavaFX.

Các mã để sử dụng một SwingNode rất đơn giản:

import javafx.application.Application; 
import javafx.embed.swing.SwingNode; 
import javafx.scene.Scene; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

import javax.swing.*; 

public class SwingFx extends Application { 
    @Override public void start(Stage stage) { 
    SwingNode swingNode = new SwingNode(); 
    SwingUtilities.invokeLater(() -> swingNode.setContent(new JButton("Click me!"))); 

    stage.setScene(new Scene(new StackPane(swingNode), 100, 50)); 
    stage.show(); 
    } 

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

Alternative Thực hiện

Về cơ bản những gì tôi đang cố gắng làm là thêm cử chỉ hỗ trợ di chuyển cho dự án java của tôi vì vậy các người dùng có thể 'vuốt' qua các bảng và tab

Mặc dù Java 8 nên cho phép bạn đạt được chính xác những gì bạn muốn, nếu bạn thích sử dụng một phiên bản Java cũ hơn, bạn có thể sử dụng hệ thống Swing dựa trên Multitouch for Java (MT4J) cho điều này thay vì JavaFX.

+0

Cảm ơn bạn rất nhiều vì ví dụ. Nhưng như bạn nói tôi không thể nhúng các thành phần swing trong javafx. Vì vậy, tất cả các thành phần mà tôi hiện đang đặt trên jtables của tôi sẽ phải được viết lại. Âm thanh chính xác? Trong trường hợp đó tôi không nghĩ rằng javafx xem bảng sẽ làm việc cho tôi. Về cơ bản những gì tôi đang cố gắng làm là thêm hỗ trợ di chuyển cử chỉ vào dự án java của tôi để người dùng có thể 'vuốt' qua các bảng và tab và tôi nghĩ vì javafx có hỗ trợ đó nên là một ý tưởng hay để nâng cấp dự án đến javafx. Nhưng có vẻ như điều đó là không thể nếu không viết lại nhiều thành phần. – Mark

+1

Giả định của bạn không chính xác. Tôi đã cập nhật câu trả lời của mình để giúp làm rõ quan điểm của tôi về vấn đề này. – jewelsea

+0

Cảm ơn ... cho công thức nấu ăn của bạn –

Các vấn đề liên quan