JavaFX表-如何添加组件?

标签 javafx tableview

我有一个swing项目,该项目使用许多JTables来显示各种各样的内容,从文本到面板,再到混合按钮和复选框。通过覆盖表单元格渲染器以返回通用JComponent,我能够做到这一点。我的问题是可以使用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;
        }
    }
}

编辑:进一步研究之后,我发现了一些示例,这些示例使用预定义的单元格类型(如文本和检查)覆盖了单元格图形。尚不清楚是否可以在JFXPanel之类的单元中放置任何通用jfx组件。这与JTable不同,因为使用JTable可以放置任何从JComponent继承的东西,只要我正确设置了render类。如果有人知道如何(或什至有可能)将JFXPanel放置在单元格或其他通用JFx组件(如Button)中,这将非常有帮助。

最佳答案

实现方面的问题

您可以将JavaFX组件嵌入到Swing应用程序中(通过将JavaFX组件放置在JFXPanel中)。但是您不能在JavaFX中嵌入Swing组件(除非您使用的是JavaFX 8+)。

无论如何,JavaFX都有其自己的按钮实现,因此即使您使用的是Java8,也没有理由在JavaFX场景中嵌入javax.swing.JButton

但这并不能解决您的所有问题。您正在为按钮列提供单元格值工厂以提供按钮,但未提供自定义单元格渲染工厂。默认的表格单元格渲染工厂在相应的单元格值上渲染toString输出,这就是为什么您只在表实现中看到按钮的to字符串表示形式的原因。

您正在将按钮放在Person对象中。不要那样做-他们不属于那里。而是在单元格渲染工厂中动态生成一个按钮。这使您可以利用表的虚拟流技术,该技术仅为您在屏幕上看到的内容创建可视节点,而不是为表的后备数据存储区中的每个元素创建可视节点。例如,如果屏幕上有10行可见,表中有10000个元素,则仅创建10个按钮,而不是10000个。

如何修复

  • 使用JavaFX的Button代替javax.swing.JButton
  • 为您的按钮提供一个单元格渲染工厂。
  • 在表格单元中而不是在Person中生成一个按钮。
  • 要在表格单元格中设置按钮(或任意JavaFX节点),请使用单元格的setGraphic方法。

  • 正确的示例代码

    此代码合并了建议的修复程序和一些改进。
    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"
        );
    }
    

    关于在JavaFX中使用Swing组件

    After investigating further I've found examples that override cell graphics using predefined cell types like text and checks. It is not clear if any generic jfx component can be placed in a cell like a JFXPanel.



    JFXPanel用于在Swing中嵌入JavaFX组件,而不是JavaFX中的Swing组件,因此尝试将JFXPanel放置在JavaFX TableView中绝对没有任何意义。这就是为什么您找不到任何尝试这种事情的例子的原因。

    This is unlike JTable, since using a JTable I can place anything that inherits from JComponent as long as I setup the render class correctly.



    在这方面,JavaFX TableView与Swing JTable相似。 Node代替了JComponent,是JavaFX的基本构建块-它们是相似的,尽管有所不同。只要提供适当的单元格工厂,就可以在JavaFX Node中呈现任何TableView

    Java 8中,有一个SwingNode可以包含Swing JComponentSwingNode允许您在JavaFX TableView中呈现任何Swing组件。

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

    替代实现

    Basically what I'm trying to do is add gesture scrolling support to my java project so the user can 'flick' through the tables and tabs



    尽管Java 8应该允许您完全实现所需的功能,但是如果您希望使用较旧的Java版本,则可以为此使用基于Swing的Multitouch for Java (MT4J)系统而不是JavaFX。

    关于JavaFX表-如何添加组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16360323/

    相关文章:

    java - 如何在 JavaFX 中更改 TextArea 的行距

    javascript - 在 JavaFX 中访问 Javascript 的返回值

    java - 右键单击 javaFX 中的 Pane 或 ImageView 时如何显示上下文菜单

    快速反转表格 View 单元格的顺序

    ios - 如何在表格 View 中添加更多原型(prototype)单元格?

    ios - 如何在 Swift 中固定到 TableView 的顶部?

    css - 面积图中的颜色变化

    从 FXML 获取对象时 JavaFX 返回 null

    java - TableView.setItems 在 java 中抛出 null 异常

    swift - iOS 11 中的 TableView 标题 View 问题