Таблица JavaFX-как добавить компоненты?

У меня есть проект swing, который использует много JTables для отображения всех видов вещей от текста до панелей до сочетания кнопок и флажков. Я смог сделать это, перезаписав визуализатор ячеек таблицы для возврата общих JComponents. Мой вопрос в том, можно ли сделать подобную таблицу с помощью JavaFx?

Я хочу обновить все мои таблицы в проекте, чтобы использовать JavaFx для поддержки жестов в основном. Кажется, что TableView является компонентом JavaFx для использования, и я попытался добавить к нему кнопки, но когда на дисплее отображается строковое значение кнопки, а не сама кнопка. Похоже, мне нужно перезаписать фабрику строк или фабрику ячеек, чтобы сделать то, что я хочу, но примеров не так много. Вот код, который я использовал в качестве примера, который отображает кнопку в виде строки.

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", "jacob.smith@example.com","The Button"),
            new Person("Isabella", "Johnson", "isabella.johnson@example.com","The Button"),
            new Person("Ethan", "Williams", "ethan.williams@example.com","The Button"),
            new Person("Emma", "Jones", "emma.jones@example.com","The Button"),
            new Person("Michael", "Brown", "michael.brown@example.com","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;
        }
    }
}

Edit: после дальнейшего исследования я нашел примеры, которые переопределяют графику ячеек, используя предопределенные типы ячеек, такие как текст и проверки. Неясно, может ли какой-либо общий компонент jfx быть помещен в ячейку как JFXPanel. Это не похоже на JTable, так как с помощью JTable я могу разместить все, что наследуется от JComponent, если я правильно настроил класс визуализации. Если кто-то знает, как (или если это даже возможно) поместить JFXPanel в ячейку или другой общий компонент JFx, такой как кнопка, это было бы очень полезно.

1 ответов


проблемы с реализацией

вы можете встроить компоненты JavaFX в приложения Swing (разместив компонент JavaFX в JFXPanel). Но вы не можете встроить компонент Swing в JavaFX (если вы не используете JavaFX 8+).

JavaFX имеет свою собственную реализацию кнопки в любом случае, поэтому нет причин вставлять javax.swing.JButton на сцене JavaFX, даже если вы используете Java8, и это будет работать.

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

вы ставите кнопки вместо javax.swing.JButton.

  • обеспечьте фабрику перевода клетки для вашей кнопки.
  • создать кнопку в ячейке таблицы, а не в человеке.
  • чтобы установить кнопку (или любой произвольный узел JavaFX) в ячейке таблицы, используйте setGraphic метод.
  • Правильный Пример Кода

    этот код включает в себя предлагаемые исправления и несколько улучшения.

    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", "jacob.smith@example.com","Coffee"),
                new Person("Isabella", "Johnson", "isabella.johnson@example.com","Fruit"),
                new Person("Ethan", "Williams", "ethan.williams@example.com","Fruit"),
                new Person("Emma", "Jones", "emma.jones@example.com","Coffee"),
                new Person("Michael", "Brown", "michael.brown@example.com","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"
        );
    }
    

    при использовании компонентов Swing в JavaFX

    после дальнейшего исследования я нашел примеры, которые переопределяют графику ячеек, используя предопределенные типы ячеек, такие как текст и проверки. Неясно, может ли какой-либо общий компонент jfx быть помещен в ячейку, такую как JFXPanel.

    A JFXPanel для встраивания компонента JavaFX в Swing не компонент Swing в JavaFX, следовательно, было бы абсолютно бессмысленно пытаться разместить JFXPanel в JavaFX TableView. Вот почему вы не находите примеров, когда кто-то пытался сделать это.

    это не похоже на JTable, так как с помощью JTable я могу разместить все, что наследуется от JComponent, если я правильно настроил класс визуализации.

    С Поддержкой JavaFX TableView похоже на качели JTable в этой связи. Вместо JComponent, a узел основной строительный блок для JavaFX-они аналогичны, хотя и отличаются. Вы можете сделать любой Node в JavaFX TableView покуда вы поставляете соотвествующую фабрику клетки для ее.

    на Java 8, есть SwingNode, который может содержать качели JComponent. А SwingNode позволяет отображать любой компонент Swing внутри JavaFX TableView.

    код для использования SwingNode очень просто:

    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); }
    }
    

    альтернатива Реализация

    в основном то, что я пытаюсь сделать, это добавить поддержку прокрутки жестов в мой проект java, чтобы пользователь мог "щелкнуть" по таблицам и вкладкам

    хотя Java 8 должен позволить вам достичь именно того, что вы хотите, если вы предпочитаете использовать более старую версию Java, вы можете использовать Swing based мультитач для Java (MT4J) система для этого вместо JavaFX.