Javafx 滚动条拇指变得太小

huangapple go评论63阅读模式
英文:

Javafx scrollbar thumb become too small

问题

当我使用一些包含滚动条的组件,例如TextArea、ListView和ScrollPane时,当内容非常长时,滚动条的拇指变得非常小。如何设置拇指的最小长度?

英文:

When I use some components which contains scrollbars, such as TextArea, ListView and ScrollPane, when the content is very long, the scrollbar's thumb become very small. How can I set a min len of the thumb?

答案1

得分: 5

以下是您提供的文本的翻译部分:

"在这个阶段,没有直接的方法来限制拇指的大小。

但是通过一些小的调整,您可以获得所需的行为 ;-). 如果您愿意使用lookup()方法,请查看下面的方法。

总体思路是查找“thumb”,并在其高度/位置发生变化时动态更新其尺寸。

以下是用于此目的的实用程序类,您可以将所需的控件传递给该类,该实用程序将确保搜索并添加所需的更新到垂直滚动条中。

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Orientation;
import javafx.scene.control.Control;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.Skin;
import javafx.scene.layout.StackPane;

import java.util.Optional;

public class ScrollThumbSizing {
    private static final double THUMB_MIN_HEIGHT = 50;
    private static final String THUMB_STYLECLASS = ".thumb";
    private static final String DISABLE_LISTENERS = "listener";
    private static final String ACTUAL_HEIGHT = "height";

    public static void enable(final Control control) {
        final ChangeListener<Skin<?>> changeListener = (obs, old, skin) -> {
            if (skin != null) {
                searchScrollBar(control);
            }
        };
        control.skinProperty().addListener(changeListener);
        if (control.getSkin() != null) {
            searchScrollBar(control);
        }
    }

    private static void searchScrollBar(final Control control) {
        // 当皮肤加载时,让事情安定下来,稍后执行搜索操作
        Platform.runLater(() -> {
            // 查找垂直滚动条
            Optional<ScrollBar> scrollBar = control.lookupAll(".scroll-bar").stream()
                    .map(node -> (ScrollBar) node)
                    .filter(sb -> sb.getOrientation() == Orientation.VERTICAL)
                    .findFirst();

            scrollBar.ifPresent(sb -> {
                final StackPane thumb = (StackPane) sb.lookup(THUMB_STYLECLASS);
                if (thumb != null) {
                    // 当thumb存在且高度/位置发生变化时,重新计算thumb的尺寸
                    final ChangeListener<? super Number> listener = (obs1, old1, val) -> adjustThumb(sb, thumb);
                    thumb.heightProperty().addListener(listener);
                    thumb.translateYProperty().addListener(listener);
                    adjustThumb(sb, thumb);
                }
            });
        });
    }

    private static void adjustThumb(final ScrollBar scrollBar, final StackPane thumb) {
        final double thumbHeight = thumb.getHeight();
        /* 如果拇指高度小于最小高度,则缓存实际拇指高度 */
        if (thumbHeight < THUMB_MIN_HEIGHT) {
            scrollBar.getProperties().put(ACTUAL_HEIGHT, thumbHeight);
        } else if (thumbHeight > THUMB_MIN_HEIGHT) {
            scrollBar.getProperties().remove(ACTUAL_HEIGHT);
        }

        /* 如果拇指高度小于或等于最小高度,请调整拇指大小 */
        /* DISABLE_LISTENERS键是为了防止无限循环... */
        if (scrollBar.getProperties().get(DISABLE_LISTENERS) == null && thumbHeight <= THUMB_MIN_HEIGHT) {
            /* 禁用监听器 */
            scrollBar.getProperties().put(DISABLE_LISTENERS, true);

            /* 调整拇指到最小高度 */
            thumb.resize(scrollBar.getWidth(), THUMB_MIN_HEIGHT);

            /* 设置拇指在设置为最小高度时的位置 */
            final Object thumbActualHgtObj = scrollBar.getProperties().get(ACTUAL_HEIGHT);
            final double thumbActualHgt = thumbActualHgtObj == null ? 0 : (double) thumbActualHgtObj;
            final double ty = thumb.getTranslateY();
            final double sbHeight = scrollBar.getHeight();
            final double tyMax = sbHeight - thumbActualHgt;
            final double tH = sbHeight - THUMB_MIN_HEIGHT;
            thumb.setTranslateY(ty / tyMax * tH);

            /* 启用监听器 */
            scrollBar.getProperties().remove(DISABLE_LISTENERS);
        }
    }
}

为了演示目的,我将此实用程序应用于TextArea、ScrollPane、ListView和TableView。请查看下面的演示。

设置ScrollThumbSizing之前:

![在这里输入图像描述][1]

设置ScrollThumbSizing之后(50px):

![在这里输入图像描述][2]

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ScrollThumbSizing_Demo extends Application {
    @Override
    public void start(final Stage stage) throws Exception {
        GridPane root = new GridPane();
        root.setPadding(new Insets(10));
        root.setVgap(10);
        root.setHgap(10);
        ColumnConstraints columnConstraints = new ColumnConstraints();
        columnConstraints.setPercentWidth(100);
        root.getColumnConstraints().addAll(columnConstraints, columnConstraints);

        // TextArea
        TextArea textArea = new TextArea();
        textArea.setMinHeight(150);
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 2000; i++) {
            builder.append("abc" + i).append(System.lineSeparator());
        }
        textArea.setText(builder.toString());

        // ListView
        ListView<String> listView = new ListView<>();
        for (int i = 0; i < 1000; i++) {
            listView.getItems().add("Item " + i);
        }

        // TableView
        TableView<String> tableView = new TableView<>();
        TableColumn<String, String> col = new TableColumn<>("Column");
        col.setCellValueFactory(p -> new SimpleStringProperty(p.getValue()));
        tableView.getColumns().add(col);
        for (int i = 0; i < 1000; i++) {
            tableView.getItems().add("T Item " + i);
        }

        // ScrollPane
        ScrollPane scrollPane = new ScrollPane();
        scrollPane.setMinHeight(150);
        StackPane content = new StackPane();
        content.setMinSize(100, 1500);
        content.setStyle("-fx-background-color:linear-gradient(to bottom, gray,red,yellow,green,pink,orange, white);");
        scrollPane.setContent(content);

        root.addRow(0, textArea, scrollPane);
        root.addRow(1, listView, tableView);
        Scene scene = new Scene(root, 400, 350);
        stage.setScene(scene);
        stage.setTitle("ScrollThumbSizing Demo");
        stage.show();

        // 您可以在显示舞台之前/之后添加此代码。
        ScrollThumbSizing.enable(textArea);
        ScrollThumbSizing

<details>
<summary>英文:</summary>

At this stage there is no direct way to limit the size of the thumb.

But with some little tweaking you can get the desired behavior ;-). If you are OK with using the lookup() method, please check the below approach.

The general idea is to lookup for the &quot;thumb&quot; and dynamically update its dimensions, whenever its height/position is changed.

Below is a utility class for this purpose, to which, you can pass the required control and utility will ensure to search and add the required updates to the vertical scroll bar.

    import javafx.application.Platform;
    import javafx.beans.value.ChangeListener;
    import javafx.geometry.Orientation;
    import javafx.scene.control.Control;
    import javafx.scene.control.ScrollBar;
    import javafx.scene.control.Skin;
    import javafx.scene.layout.StackPane;
    
    import java.util.Optional;
    
    public class ScrollThumbSizing {
        private static final double THUMB_MIN_HEIGHT = 50;
        private static final String THUMB_STYLECLASS = &quot;.thumb&quot;;
        private static final String DISABLE_LISTENERS = &quot;listener&quot;;
        private static final String ACTUAL_HEIGHT = &quot;height&quot;;
    
        public static void enable(final Control control) {
            final ChangeListener&lt;Skin&lt;?&gt;&gt; changeListener = (obs, old, skin) -&gt; {
                if (skin != null) {
                    searchScrollBar(control);
                }
            };
            control.skinProperty().addListener(changeListener);
            if (control.getSkin() != null) {
                searchScrollBar(control);
            }
        }
    
        private static void searchScrollBar(final Control control) {
            // When the skin is loaded, let the things settle and do search operation at later stage
            Platform.runLater(() -&gt; {
                // Find the vertical scroll bar
                Optional&lt;ScrollBar&gt; scrollBar = control.lookupAll(&quot;.scroll-bar&quot;).stream()
                        .map(node -&gt; (ScrollBar) node)
                        .filter(sb -&gt; sb.getOrientation() == Orientation.VERTICAL)
                        .findFirst();
    
                scrollBar.ifPresent(sb -&gt; {
                    final StackPane thumb = (StackPane) sb.lookup(THUMB_STYLECLASS);
                    if (thumb != null) {
                        // When the thumb exists, and if the height/position is changed, recompute the thumb dimensions.
                        final ChangeListener&lt;? super Number&gt; listener = (obs1, old1, val) -&gt; adjustThumb(sb, thumb);
                        thumb.heightProperty().addListener(listener);
                        thumb.translateYProperty().addListener(listener);
                        adjustThumb(sb, thumb);
                    }
                });
            });
        }
    
        private static void adjustThumb(final ScrollBar scrollBar, final StackPane thumb) {
            final double thumbHeight = thumb.getHeight();
            /* Caching the actual thumb height if it is less than the minimum height */
            if (thumbHeight &lt; THUMB_MIN_HEIGHT) {
                scrollBar.getProperties().put(ACTUAL_HEIGHT, thumbHeight);
            } else if (thumbHeight &gt; THUMB_MIN_HEIGHT) {
                scrollBar.getProperties().remove(ACTUAL_HEIGHT);
            }
    
            /* If the thumb height is less than or equal to the minimum height, adjust the thumb size */
            /* DISABLE_LISTENERS key is to NOT let the things happen in loop forever... */
            if (scrollBar.getProperties().get(DISABLE_LISTENERS) == null &amp;&amp; thumbHeight &lt;= THUMB_MIN_HEIGHT) {
                /* Disabling the listeners */
                scrollBar.getProperties().put(DISABLE_LISTENERS, true);
    
                /* Resizing the thumb to minimum height */
                thumb.resize(scrollBar.getWidth(), THUMB_MIN_HEIGHT);
    
                /* Positioning the thumb when set to minimum height */
                final Object thumbActualHgtObj = scrollBar.getProperties().get(ACTUAL_HEIGHT);
                final double thumbActualHgt = thumbActualHgtObj == null ? 0 : (double) thumbActualHgtObj;
                final double ty = thumb.getTranslateY();
                final double sbHeight = scrollBar.getHeight();
                final double tyMax = sbHeight - thumbActualHgt;
                final double tH = sbHeight - THUMB_MIN_HEIGHT;
                thumb.setTranslateY(ty / tyMax * tH);
    
                /* Enabling the listeners */
                scrollBar.getProperties().remove(DISABLE_LISTENERS);
            }
        }
    }

For the demonstration purpose, I applied this utility on TextArea, ScrollPane, ListView &amp; TableView. Please check the below demo.

**Before setting ScrollThumbSizing:**

[![enter image description here][1]][1]

**After setting ScrollThumbSizing (50px):**

[![enter image description here][2]][2]

    import javafx.application.Application;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.geometry.Insets;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.layout.ColumnConstraints;
    import javafx.scene.layout.GridPane;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class ScrollThumbSizing_Demo extends Application {
        @Override
        public void start(final Stage stage) throws Exception {
            GridPane root = new GridPane();
            root.setPadding(new Insets(10));
            root.setVgap(10);
            root.setHgap(10);
            ColumnConstraints columnConstraints = new ColumnConstraints();
            columnConstraints.setPercentWidth(100);
            root.getColumnConstraints().addAll(columnConstraints,columnConstraints);
    
            // TextArea
            TextArea textArea = new TextArea();
            textArea.setMinHeight(150);
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i &lt; 2000; i++) {
                builder.append(&quot;abc&quot; + i).append(System.lineSeparator());
            }
            textArea.setText(builder.toString());
    
            // ListView
            ListView&lt;String&gt; listView = new ListView&lt;&gt;();
            for (int i = 0; i &lt; 1000; i++) {
                listView.getItems().add(&quot;Item &quot; + i);
            }
    
            // TableView
            TableView&lt;String&gt; tableView = new TableView&lt;&gt;();
            TableColumn&lt;String, String&gt; col = new TableColumn&lt;&gt;(&quot;Column&quot;);
            col.setCellValueFactory(p -&gt; new SimpleStringProperty(p.getValue()));
            tableView.getColumns().add(col);
            for (int i = 0; i &lt; 1000; i++) {
                tableView.getItems().add(&quot;T Item &quot; + i);
            }
    
            // ScrollPane
            ScrollPane scrollPane = new ScrollPane();
            scrollPane.setMinHeight(150);
            StackPane content = new StackPane();
            content.setMinSize(100, 1500);
            content.setStyle(&quot;-fx-background-color:linear-gradient(to bottom, gray,red,yellow,green,pink,orange, white);&quot;);
            scrollPane.setContent(content);
    
            root.addRow(0, textArea, scrollPane);
            root.addRow(1, listView, tableView);
            Scene scene = new Scene(root, 400,350);
            stage.setScene(scene);
            stage.setTitle(&quot;ScrollThumbSizing Demo&quot;);
            stage.show();
    
            // You can add this before/after showing the stage.
            ScrollThumbSizing.enable(textArea);
            ScrollThumbSizing.enable(listView);
            ScrollThumbSizing.enable(tableView);
            ScrollThumbSizing.enable(scrollPane);
        }
    }

  [1]: https://i.stack.imgur.com/eoJdB.png
  [2]: https://i.stack.imgur.com/D2hPl.png

</details>



huangapple
  • 本文由 发表于 2023年5月30日 10:19:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76361246.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定