首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >水平ScrollBar在具有约束调整大小策略的TableView中可见。

水平ScrollBar在具有约束调整大小策略的TableView中可见。
EN

Stack Overflow用户
提问于 2022-07-21 03:15:35
回答 2查看 134关注 0票数 2

ScrollBar被调整(缩小)时,TableView的水平TableView (具有受限的调整大小策略)保持闪烁。我相信这是一个长期存在的问题,因为我可以找到JDK-8089009和其他参考问题JDK-8115476 & JDK-8089280的公开发行票。

我现在问这个问题的目的,是看看是否有人有办法或解决办法来解决这个现存的问题。

下面是在JDK-8089009中提供的演示代码,其中问题可以与JavaFX的最新版本(18+)重复。

代码语言:javascript
运行
复制
import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class HorizontalConstrainedTableScrolling extends Application {
    @Override
    public void start(final Stage primaryStage) throws Exception {
        final TableView<Object> left = new TableView<>();
        final TableColumn<Object, String> leftColumn = new TableColumn<>();
        left.getColumns().add(leftColumn);
        left.getItems().add(new Object());
        left.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

        final TableView<Object> right = new TableView<>();
        final TableColumn<Object, String> rightColumn = new TableColumn<>();
        right.getColumns().add(rightColumn);
        right.getItems().add(new Object());

        final SplitPane splitPane = new SplitPane();
        splitPane.setOrientation(Orientation.HORIZONTAL);
        splitPane.getItems().addAll(left, right);

        Label osLabel = new Label(System.getProperty("os.name"));
        Label jvmLabel = new Label(
                System.getProperty("java.version") +
                        "-" + System.getProperty("java.vm.version") +
                        " (" + System.getProperty("os.arch") + ")"
        );

        primaryStage.setScene(new Scene(new BorderPane(splitPane, null, null, new VBox(osLabel, jvmLabel), null)));
        primaryStage.setWidth(600);
        primaryStage.setHeight(400);
        primaryStage.setTitle("TableView in SplitPane");
        primaryStage.show();
    }
}

更新

下面是我通常遇到的使用受限调整大小策略的用法。

要求是,通常一个列是可维护的,而其他所有列都有一些最小/最大宽度,因此它们不能超出这些大小。如果所有列都有足够的空间,那么所有列都应该安装在tableView中,如果空间小于它们所能容纳的空间,那么滚动条就会出现。

下面是演示该示例的演示(使用滚动条问题):

代码语言:javascript
运行
复制
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;

public class ConstrainedResizePolicyDemo extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        TableColumn<Person, String> fnCol = new TableColumn<>("First Name");
        fnCol.setMinWidth(100);
        fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());

        TableColumn<Person, String> act1Col = new TableColumn<>("Act1");
        act1Col.setMinWidth(50);
        act1Col.setMaxWidth(50);
        act1Col.setResizable(false);
        act1Col.setCellValueFactory(param -> param.getValue().act1Property());

        TableColumn<Person, String> priceCol = new TableColumn<>("Price");
        priceCol.setMinWidth(100);
        priceCol.setMaxWidth(150);
        priceCol.setCellValueFactory(param -> param.getValue().priceProperty());

        TableColumn<Person, String> act2Col = new TableColumn<>("Act2");
        act2Col.setMinWidth(50);
        act2Col.setMaxWidth(50);
        act2Col.setResizable(false);
        act2Col.setCellValueFactory(param -> param.getValue().act2Property());

        TableColumn<Person, String> totalCol = new TableColumn<>("Total");
        totalCol.setMinWidth(100);
        totalCol.setMaxWidth(150);
        totalCol.setCellValueFactory(param -> param.getValue().totalProperty());

        TableColumn<Person, String> act3Col = new TableColumn<>("Act3");
        act3Col.setMinWidth(50);
        act3Col.setMaxWidth(50);
        act3Col.setResizable(false);
        act3Col.setCellValueFactory(param -> param.getValue().act3Property());

        TableColumn<Person, String> bidCol = new TableColumn<>("Bid");
        bidCol.setMinWidth(100);
        bidCol.setMaxWidth(150);
        bidCol.setCellValueFactory(param -> param.getValue().bidProperty());

        ObservableList<Person> persons = FXCollections.observableArrayList();
        persons.add(new Person("Harry", "A", "200.00", "B", "210.00", "C", "300.00"));
        persons.add(new Person("Kingston", "D", "260.00", "E", "610.00", "F", "700.00"));

        TableView<Person> tableView = new TableView<>();
        tableView.getColumns().addAll(fnCol, act1Col, priceCol, act2Col, totalCol, act3Col, bidCol);
        tableView.setItems(persons);
        tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

        Scene scene = new Scene(tableView, 600, 150);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Constrained Resize Policy TableView");
        primaryStage.show();
    }

    class Person {
        private StringProperty firstName = new SimpleStringProperty();
        private StringProperty act1 = new SimpleStringProperty();
        private StringProperty price = new SimpleStringProperty();
        private StringProperty act2 = new SimpleStringProperty();
        private StringProperty total = new SimpleStringProperty();
        private StringProperty act3 = new SimpleStringProperty();
        private StringProperty bid = new SimpleStringProperty();

        public Person(String fn, String act1, String price, String act2, String total, String act3, String bid) {
            setFirstName(fn);
            setAct1(act1);
            setPrice(price);
            setAct2(act2);
            setTotal(total);
            setAct3(act3);
            setBid(bid);
        }

        public StringProperty firstNameProperty() {
            return firstName;
        }

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

        public StringProperty act1Property() {
            return act1;
        }

        public void setAct1(String act1) {
            this.act1.set(act1);
        }

        public StringProperty priceProperty() {
            return price;
        }

        public void setPrice(String price) {
            this.price.set(price);
        }

        public StringProperty act2Property() {
            return act2;
        }

        public void setAct2(String act2) {
            this.act2.set(act2);
        }

        public StringProperty totalProperty() {
            return total;
        }

        public void setTotal(String total) {
            this.total.set(total);
        }

        public StringProperty act3Property() {
            return act3;
        }

        public void setAct3(String act3) {
            this.act3.set(act3);
        }

        public StringProperty bidProperty() {
            return bid;
        }

        public void setBid(String bid) {
            this.bid.set(bid);
        }
    }
}
EN

回答 2

Stack Overflow用户

发布于 2022-07-21 10:10:54

和以往一样,对于长期存在的错误,唯一的出路就是黑客攻击。其基本思想是根据调整大小策略将滚动条的大小约束设置为0:对于约束策略,固定为0,对于无约束策略,则设置通常的useComputed。下面是实现hack的实用程序方法。

备注

  • 必须在表可见后调用。
  • 必须在策略在运行时发生更改时调用。
  • 注意:当调整大小到很小的值时,似乎仍然有一个轻微的视觉伪像:看起来像一个箭头(或两者都出现)(不是它们的背景,只是箭头)。

守则:

代码语言:javascript
运行
复制
public static void updateScrollBar(final TableView<Object> table) {
    // lookup the horizontal scroll bar
    ScrollBar hbar = null;
    Set<Node> scrollBars = table.lookupAll(".scroll-bar");
    for (Node node : scrollBars) {
        ScrollBar bar = (ScrollBar) node;
        if (bar.getOrientation() == Orientation.HORIZONTAL) {
            hbar = bar;
            break;
        }
    }

    // choose sizing constraint as either 0 or useComputed, depending on policy
    Callback<?, ?> policy = table.getColumnResizePolicy();
    double pref = policy == CONSTRAINED_RESIZE_POLICY ? 0 : USE_COMPUTED_SIZE;

    // set all sizing constraints
    hbar.setPrefSize(pref, pref);
    hbar.setMaxSize(pref, pref);
    hbar.setMinSize(pref, pref);
}
票数 2
EN

Stack Overflow用户

发布于 2022-11-15 08:28:13

我使用的是从JavaFX 8开始对我有效的解决方案,在JavaFX 19中仍然是这样,但是使用这个解决方案意味着您必须遵守一些规则。为了使其发挥作用:

  • 任何具有TableColumn集的maxWidth都不能调整大小。
  • 可调整大小的列必须相邻,否则调整大小有时会显示hbar。
  • 然后,您应该禁用所有列的重新排序,这样用户就不能在此解决方案不起作用的情况下重新排列它们。一旦这是有序的,你只需要一个绑定和一个侦听器。绑定在调整表大小时注意滚动条,监听器在调整列大小时负责滚动条。

下面的代码适用于您的第一个示例代码。不需要侦听器,因为只有一个列:

代码语言:javascript
运行
复制
leftColumn.prefWidthProperty().bind(left.widthProperty().subtract(1));

下面的代码适用于第二个示例代码,包括可重排序和可调整大小的更改。绑定和侦听器可以应用于您选择的TableColumns,条件是所选列是可调整大小的,并且没有设置maxWidth:

代码语言:javascript
运行
复制
    @Override
    public void start(Stage primaryStage) throws Exception {
        TableColumn<Person, String> fnCol = new TableColumn<>("First Name");
        fnCol.setMinWidth(100);
        fnCol.setReorderable(false);
        fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());
        
        TableColumn<Person, String> priceCol = new TableColumn<>("Price");
        priceCol.setMinWidth(100);
        priceCol.setReorderable(false);
        priceCol.setCellValueFactory(param -> param.getValue().priceProperty());

        TableColumn<Person, String> totalCol = new TableColumn<>("Total");
        totalCol.setMinWidth(100);
        totalCol.setReorderable(false);
        totalCol.setCellValueFactory(param -> param.getValue().totalProperty());

        TableColumn<Person, String> bidCol = new TableColumn<>("Bid");
        bidCol.setMinWidth(100);
        bidCol.setReorderable(false);
        bidCol.setCellValueFactory(param -> param.getValue().bidProperty());

        TableColumn<Person, String> act1Col = new TableColumn<>("Act1");
        act1Col.setMinWidth(50);
        act1Col.setMaxWidth(50);
        act1Col.setResizable(false);
        act1Col.setReorderable(false);
        act1Col.setCellValueFactory(param -> param.getValue().act1Property());

        TableColumn<Person, String> act2Col = new TableColumn<>("Act2");
        act2Col.setMinWidth(50);
        act2Col.setMaxWidth(50);
        act2Col.setResizable(false);
        act2Col.setReorderable(false);
        act2Col.setCellValueFactory(param -> param.getValue().act2Property());

        TableColumn<Person, String> act3Col = new TableColumn<>("Act3");
        act3Col.setMinWidth(50);
        act3Col.setMaxWidth(50);
        act3Col.setResizable(false);
        act3Col.setReorderable(false);
        act3Col.setCellValueFactory(param -> param.getValue().act3Property());

        ObservableList<Person> persons = FXCollections.observableArrayList();
        persons.add(new Person("Harry", "A", "200.00", "B", "210.00", "C", "300.00"));
        persons.add(new Person("Kingston", "D", "260.00", "E", "610.00", "F", "700.00"));

        TableView<Person> tableView = new TableView<>();
        tableView.setPadding(Insets.EMPTY);
        tableView.getColumns().addAll(fnCol, priceCol, totalCol, bidCol, act1Col, act2Col, act3Col);
        tableView.setItems(persons);
        tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        
        fnCol.widthProperty().addListener((obs, ov, nv)->{
            if (nv != null && !ov.equals(nv) && (double)nv > 0) {
                if ((double)nv > (double)ov) {
                    fnCol.prefWidthProperty().unbind();
                    fnCol.setPrefWidth(tableView.getWidth() - act1Col.getWidth() - priceCol.getWidth() - act2Col.getWidth() - totalCol.getWidth() - act3Col.getWidth() - bidCol.getWidth());
                    fnCol.prefWidthProperty().bind(
                        tableView.widthProperty()
                        .subtract(act1Col.widthProperty())
                        .subtract(priceCol.widthProperty())
                        .subtract(act2Col.widthProperty())
                        .subtract(totalCol.widthProperty())
                        .subtract(act3Col.widthProperty())
                        .subtract(bidCol.widthProperty())
                    );
                }
            }
        });
        fnCol.prefWidthProperty().bind(
            tableView.widthProperty()
            .subtract(act1Col.widthProperty())
            .subtract(priceCol.widthProperty())
            .subtract(act2Col.widthProperty())
            .subtract(totalCol.widthProperty())
            .subtract(act3Col.widthProperty())
            .subtract(bidCol.widthProperty())
        );

        Scene scene = new Scene(tableView, 600, 150);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Constrained Resize Policy TableView");
        primaryStage.show();
    }

我假设这样做的原因很简单,因为何时精确计算列宽,何时触发水平滚动条可见性,以及所有这些事情发生的顺序。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73060277

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档