草庐IT

java - Node.snapshot(null, null) 改变场景的大小

coder 2024-03-08 原文

我有 Scene,它被设置为我的 primaryStage 的 Scene,在其他节点中,它包含一个 VBox 和一个 TableView 和一些按钮。当我使用 TableRow.snapshot(null, null) 在表中的一行拍摄快照时,Scene 的大小发生了变化。宽度改变了大约 10 像素,而高度改变了大约 40 - 有时超过 600 (!) - 像素。

发生这种情况是因为 Node.snapshot(null, null) 调用了 Scene.doCSSLayoutSyncForSnapshot(Node node) 这似乎获得了所有节点的首选大小使用它重新计算大小。这不知何故返回了错误的值,因为我的节点只指定了首选大小并且在调用此方法之前看起来很棒。有什么办法可以避免这种情况吗?

尺寸改变是个问题,但初级阶段不随其包含的Scene改变尺寸也是个问题。

我曾尝试创建一个 MCVE 来重现该问题,但在尝试这样做几天后,我仍然无法重现该问题。原始程序包含大约 2000 行代码,我不想在这里发布。

为什么 Scene.doCSSLayoutSyncForSnapshot(Node node) 会妥协我的布局,当它首先被正确布局时?我能否以某种方式确保布局在调用此方法之前已正确同步以确保它不会更改任何内容?

最佳答案

解决了这个问题。不得不复制我的整个项目,然后删除部分代码,直到问题消失。

无论如何。我的应用程序基本上包含三个组件。导航组件、表格组件和状态栏组件。它看起来像这样:

我遇到的问题是,每当我对表格中的一行进行快照时,状态栏的宽度以及表格组件的宽度和高度都会增加。

显然,这是由于状态栏组件的填充所致。它有 5 个像素的左右填充,一旦我移除填充,问题就消失了。

添加的 10 像素宽度使包含所有这些的 BorderPane 以相同数量的像素扩展,并且由于表格宽度绑定(bind)到 BorderPane 宽度,它增加了相同的数量。但我仍然不明白的是,为什么包含 BorderPaneStage 没有调整到新的宽度。

组件在 Scene.doCSSLayoutSyncForSnapshot(Node node) 被调用之前被正确填充,所以我不明白为什么要添加十个像素的额外宽度。

无论如何:从状态栏组件中删除填充,而不是填充状态栏内的组件解决了这个问题。如果有人对此有很好的解释,我会洗耳恭听。

这是一个 MCVE,您可以在其中通过在表格中拖动一行来重现问题:

import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class MCVE extends Application {

    private Stage primaryStage;
    private BorderPane rootLayout;
    private VBox detailsView;
    private StatusBar statusBar;

    public void start(Stage primaryStage) throws SQLException {

        this.primaryStage = primaryStage;
        this.primaryStage.setTitle("MCVE");

        initRootLayout();
        showStatusBar();
        showDetailsView();

        detailsView.prefWidthProperty().bind(rootLayout.widthProperty());
        detailsView.prefHeightProperty().bind(rootLayout.heightProperty());
    }

    @Override
    public void init() throws Exception {
        super.init();

    }

    public void initRootLayout() {
        rootLayout = new BorderPane();

        primaryStage.setWidth(1000);
        primaryStage.setHeight(600);

        Scene scene = new Scene(rootLayout);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public void showStatusBar() {
        statusBar = new StatusBar();
        rootLayout.setBottom(statusBar);
    }

    public void showDetailsView() {
        detailsView = new VBox();
        rootLayout.setCenter(detailsView);

        setDetailsView(new Table(this));

        detailsView.prefHeightProperty().bind(primaryStage.heightProperty());
        detailsView.setMaxHeight(Region.USE_PREF_SIZE);
    }

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

    public VBox getDetailsView() {
        return detailsView;
    }

    public void setDetailsView(Node content) {
        detailsView.getChildren().add(0, content);
    }

    public StatusBar getStatusBar() {
        return statusBar;
    }

    class StatusBar extends HBox {
        public StatusBar() {
            setPadding(new Insets(0, 5, 0, 5));

            HBox leftBox = new HBox(10);

            getChildren().addAll(leftBox);

            /**
             * CONTROL SIZES
             */
            setPrefHeight(28);
            setMinHeight(28);
            setMaxHeight(28);

            // Leftbox takes all the space not occupied by the helpbox.
            leftBox.prefWidthProperty().bind(widthProperty());

            setStyle("-fx-border-color: black;");
        }
    }

    class Table extends TableView<ObservableList<String>> {

        private ObservableList<ObservableList<String>> data;

        public Table(MCVE app) {

            prefWidthProperty().bind(app.getDetailsView().widthProperty());
            prefHeightProperty()
                    .bind(app.getDetailsView().heightProperty());

            widthProperty().addListener((obs, oldValue, newValue) -> {
                System.out.println("Table width: " + newValue);
            });

            setRowFactory(r -> {
                TableRow<ObservableList<String>> row = new TableRow<ObservableList<String>>();

                row.setOnDragDetected(e -> {
                    Dragboard db = row.startDragAndDrop(TransferMode.ANY);
                    db.setDragView(row.snapshot(null, null));

                    ArrayList<File> files = new ArrayList<File>();

                    // We create a clipboard and put all of the files that
                    // was selected into the clipboard.
                    ClipboardContent filesToCopyClipboard = new ClipboardContent();
                    filesToCopyClipboard.putFiles(files);

                    db.setContent(filesToCopyClipboard);
                });

                row.setOnDragDone(e -> {
                    e.consume();
                });

                return row;
            });

            ObservableList<String> columnNames = FXCollections.observableArrayList("Col1", "col2", "Col3", "Col4");

            data = FXCollections.observableArrayList();

            for (int i = 0; i < columnNames.size(); i++) {
                final int colIndex = i;

                TableColumn<ObservableList<String>, String> column = new TableColumn<ObservableList<String>, String>(
                        columnNames.get(i));

                column.setCellValueFactory((param) -> new SimpleStringProperty(param.getValue().get(colIndex).toString()));

                    getColumns().add(column);
            }

            // Adds all of the data from the rows the data list.
            for (int i = 0; i < 100; i++) {
                // Each column from the row is a String in the list.
                ObservableList<String> row = FXCollections.observableArrayList();

                row.add("Column 1");
                row.add("Column 2");
                row.add("Column 3");
                row.add("Column 4");

                // Adds the row to data.
                data.add(row);
            }

            // Adds all of the rows in data to the table.
            setItems(data);
        }
    }
}

关于java - Node.snapshot(null, null) 改变场景的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37318953/

有关java - Node.snapshot(null, null) 改变场景的大小的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  3. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  4. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  5. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  6. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  7. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  8. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  9. "\0"null 的 Ruby 测试? - 2

    我在破坏脚本的字符串中出现了一些奇怪的字符。据我所知,通过putbadstring到控制台,它们是"\0\0\0\0"。我想对此进行测试,以便我可以忽略它们...但是如何呢?以为这就是blank?和empty?的用途?!?:>badstring="\0"=>"\u0000">badstring.blank?NoMethodError:undefinedmethod`blank?'for"\u0000":Stringfrom(irb):97from/Users/meltemi/.rvm/rubies/ruby-2.0.0-p195/bin/irb:16:in`'>badstring.em

  10. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

随机推荐