2

I am trying to write a custom resize policy that acts like TableView.CONSTRAINED_RESIZE_POLICY in that it set the total width of all visible to columns to the total available width in the table, so that the horizontal scroll bar never appears.

I am using the line double widthAvailable = table.getWidth() - getScrollbarWidth(table); to try do to this (see full code below).

Unfortunately, this calculation seems to return 4 too many. My guess is that there is some other thing I am also supposed to be subtracting from the table width that I am missing, which happens to be 4 pixels wide in the default JavaFX theme.

Here is a complete program demonstrating the problem:

package net.joshuad.hypnos.test;

import java.util.List;
import java.util.Locale;
import java.util.Set;

import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class CustomResizeExample extends Application {

    @SuppressWarnings("unchecked")
    private Parent getContent () {
        TableView <Locale> table = new TableView <>( FXCollections.observableArrayList( Locale.getAvailableLocales() ) );
        TableColumn <Locale, String> countryCode = new TableColumn <>( "CountryCode" );
        countryCode.setCellValueFactory( new PropertyValueFactory <>( "country" ) );
        TableColumn <Locale, String> language = new TableColumn <>( "Language" );
        language.setCellValueFactory( new PropertyValueFactory <>( "language" ) );
        table.getColumns().addAll( countryCode, language );

        TableColumn <Locale, Locale> local = new TableColumn <>( "Locale" );
        local.setCellValueFactory( c -> new SimpleObjectProperty <>( c.getValue() ) );

        table.getColumns().addAll( local );
        table.setColumnResizePolicy( new CustomResizePolicy() );

        BorderPane pane = new BorderPane( table );
        return pane;
    }
    @Override
    public void start ( Stage stage ) throws Exception {
        stage.setScene( new Scene( getContent(), 800, 400 ) );
        stage.show();
    }

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

}

@SuppressWarnings ( "rawtypes" ) 
class CustomResizePolicy implements Callback <TableView.ResizeFeatures, Boolean> {

    @SuppressWarnings("unchecked")
    @Override
    public Boolean call ( TableView.ResizeFeatures feature ) {

        TableView table = feature.getTable();
        List <TableColumn> columns = table.getVisibleLeafColumns();
        double widthAvailable = table.getWidth() - getScrollbarWidth ( table );


        double forEachColumn = widthAvailable / columns.size();

        for ( TableColumn column : columns ) {
            column.setMinWidth( forEachColumn );
            column.setMaxWidth( forEachColumn );
        }

        return true;

    }

    private double getScrollbarWidth ( TableView table ) {
        double scrollBarWidth = 0;
        Set <Node> nodes = table.lookupAll( ".scroll-bar" );
        for ( final Node node : nodes ) {
            if ( node instanceof ScrollBar ) {
                ScrollBar sb = (ScrollBar) node;
                if ( sb.getOrientation() == Orientation.VERTICAL ) {
                    if ( sb.isVisible() ) {
                        scrollBarWidth = sb.getWidth();
                    }
                }
            }
        }

        return scrollBarWidth;
    }
}

See how the table is a little wider than it ought to be? I would like to be able to set the columns' width such that no horizontal scrollbar appears.

enter image description here

user1803551
  • 12,965
  • 5
  • 47
  • 74
Grumblesaurus
  • 3,021
  • 3
  • 31
  • 61
  • What is `sb.getWidth() + sb.`? – user1803551 Dec 17 '17 at 15:24
  • `sb.getWidth()` is the entire width. Post a [MCVE]. – user1803551 Dec 17 '17 at 15:32
  • @user1803551: A typo from me trying for solutions. Removed. – Grumblesaurus Dec 17 '17 at 19:24
  • @user1803551: No, sb.getWidth() is not the entireWidth. It is short 4 pixels. – Grumblesaurus Dec 17 '17 at 19:24
  • 1
    Not according to my tests. I bound the width of a label to the width of the scrollbar and it was correct. You are not showing the part of the code with the problem. – user1803551 Dec 17 '17 at 19:45
  • Let me put together a test with a main() and share. – Grumblesaurus Dec 17 '17 at 20:58
  • Yeah, that's what a [MCVE] means. – user1803551 Dec 17 '17 at 21:01
  • I have edited that into the OP. – Grumblesaurus Dec 17 '17 at 21:06
  • How does your example show that `sb.getWidth()` is incorrect? You are using it inside a resizing policy so maybe that's where your problem is, but it's not in getting the width. – user1803551 Dec 17 '17 at 21:17
  • @user1803551: I don't know man. I am having a problem. Like any other time I had a problem that I couldn't solve, I posted a thread with some excerpt code and my best guess about what's wrong. If my guess is wrong, great! If I knew exactly what the problem was and why it was happening, then I wouldn't have the problem. – Grumblesaurus Dec 17 '17 at 21:20
  • But what is the resizing policy supposed to do for you? The behavior you seem to want happens by default. If you don't set it the horizontal scrollbar won't appear. So what are you trying to do? – user1803551 Dec 17 '17 at 21:24
  • This isn't the actual resize policy I am using. It's a minimum example showing the place of difficulty -- calculating the proper total width to spread out amongst all columns. – Grumblesaurus Dec 17 '17 at 21:32
  • You can see the full resize policy here, if you're interested: https://github.com/JoshuaD84/HypnosMusicPlayer/blob/master/src/net/joshuad/hypnos/fxui/HypnosResizePolicy.java – Grumblesaurus Dec 17 '17 at 21:34
  • It's always hard to figure out how to ask questions here. I thought I narrowed the problem down to getScrollBarWidth, but after posting it and talking with you some, it appears that the problem is somewhere else. I'd be glad to edit the OP to try to reflect this new knowledge. Do you think that's a good idea? – Grumblesaurus Dec 17 '17 at 21:36
  • So your *real* question is: "how to spread the total width amongst all columns on table construction?", at least that's what understand. If that's the case, make your title and question reflect that, and mention that you think the scrollbar is interfering with the calculation. – user1803551 Dec 17 '17 at 21:38
  • There's an easy way to ask questions of this nature here: state what you are trying to achieve (currently missing), show how you tried to do that (your second code block), say/show what you expected the result to be (missing) and how what you actually got is different (kinda shown in pictures but unclear). – user1803551 Dec 17 '17 at 21:41
  • @user1803551: 1. Thank you for helping. 2. We probably shouldn't go any longer on this, but if you look at my original post I did that -- I just had a mistaken assumption. I thought I needed to get the width of a scrollbar and was getting the width of the scroll-bar button. 3. I'm editing the OP now with the new question which more accurately surrounds the problem. – Grumblesaurus Dec 17 '17 at 21:43
  • So that's why I was saying that you should write around what the end result that you want is and not around what you think is the cause of the problem - because if it's not the cause you're stuck. It's really worth discussing how to write a good question and the SO team have been working lately on helping users with this. It's a justified mistake. – user1803551 Dec 17 '17 at 21:45
  • Yea. That's a good point. There's also a pressure to be as focused as possible in questions -- it wouldn't be good to say "I want a resize policy that works like XYZ" -- because it's asking for SO to produce like 500 lines of code and solve my full problem, which isn't very reasonable. OP edited. A mod should probably delete/move all this chat. – Grumblesaurus Dec 17 '17 at 21:48

1 Answers1

2

Scenic View is a useful tool to get acquainted with. It gives you many details about the scene graph. The space you are looking for is clipped-container:

enter image description here

enter image description here

Note that setting a CustomResizePolicy the way you did effectively does not allow columns to be resized as they are always allocated an equal share of available space.

Here is the calculation you are probably looking for:

Region region = null;
Set<Node> nodes = table.lookupAll(".clipped-container");
for (Node node : nodes) {
    if (node instanceof Region) {
        region = (Region) node;
    }
}
for (TableColumn<Locale, ?> column : table.getColumns()) {
    column.setPrefWidth(region.getWidth() / table.getColumns().size());
}

I don't completely understand why CONSTRAINED_RESIZE_POLICY is not what you want, as it divides the space equally and does not allow resizing to exceed the allocated space (thus a horizontal scrollbar does not appear), but if you're making some special resize policy the above should help.

user1803551
  • 12,965
  • 5
  • 47
  • 74
  • Thanks. The simplified code in my post is just to show the problem. The actual resize policy is similar to, but does a few things differently than, CONSTRAINED_RESIZE_POLICY. – Grumblesaurus Dec 18 '17 at 03:48