title: Toggling TableColumn.setVisible resets width, setPrefWidth doesn't change it
body: <p>I have a TableView full of nested columns.  On these columns, I have 2 context menu options -- "Hide Column" and "Unhide All Columns", which toggle the visibility of the columns and their children as such.</p>
  
  <p>The tableview is populated after the UI is initialized, so the size of the columns is set to the default width, which is smaller than the size of the longest cell value.  This is what I want to happen.  I don't want the columns to extend to thousands of pixels wide because of a single particularly long entry.</p>
  
  <p>My problem is this:  <strong>when the user hides the column and unhides it, the width of that column stretches out to the smallest length possible to fit the longest cell value.  This is not what I want to happen.</strong>  I want it to ideally keep its original width when the visibility is toggled in this way.</p>
  
  <p>To solve this, I tried setting the max width to the current width before I hide the column, and then unsetting the max width and setting the prefwidth to the former maxwidth after I unhide it (thus locking it from resizing itself).  This doesn't work.</p>
  
  <p>Here's an example to show what's happening.</p>
  
  <p><strong>TestExample.java</strong></p>
  
  <pre><code>package testexample;
  
  import javafx.application.Application;
  import javafx.collections.FXCollections;
  import javafx.collections.ObservableList;
  import javafx.scene.Scene;
  import javafx.scene.control.ContextMenu;
  import javafx.scene.control.MenuItem;
  import javafx.scene.control.TableColumn;
  import javafx.scene.control.TableView;
  import javafx.scene.control.cell.PropertyValueFactory;
  import javafx.scene.layout.AnchorPane;
  import javafx.scene.layout.StackPane;
  import javafx.stage.Stage;
  
  public class Testexample extends Application {
  
      private TableView table;
  
      @Override
      public void start(Stage primaryStage) {
          //Create table
          table = new TableView();
  
          //Create table items
          final ObservableList&lt;DataContainer&gt; data = FXCollections.observableArrayList(
              new DataContainer("Alice", "Red", "Yellow"),
              new DataContainer("Bob", "purple", "green"),
              new DataContainer("Sir Jean-Jaques-Charles III", "Deep green-cyan turqoise", "Fluorescent pink")
          );
  
          //Create table columns
          TableColumn nameColumn = new TableColumn("name");   
          TableColumn colorsColumn = new TableColumn("colors");
          TableColumn color1Column = new TableColumn("color1");
          TableColumn color2Column = new TableColumn("color2");
  
          //Make it so columns can properly display the table items
          nameColumn.setCellValueFactory( new PropertyValueFactory&lt;&gt;("name"));
          color1Column.setCellValueFactory( new PropertyValueFactory&lt;&gt;("color1"));
          color2Column.setCellValueFactory( new PropertyValueFactory&lt;&gt;("color2"));
  
          //Set the header context menus
          addHeaderContextMenus(nameColumn);
          addHeaderContextMenus(colorsColumn);
          addHeaderContextMenus(color1Column);
          addHeaderContextMenus(color2Column);
  
          //Add the columns to the table
          table.getColumns().addAll(nameColumn, colorsColumn);
          colorsColumn.getColumns().addAll(color1Column, color2Column);
  
          //Put the table inside a container
          StackPane root = new StackPane();
          AnchorPane anchor = new AnchorPane();
          root.getChildren().add(anchor);
          anchor.getChildren().add(table);
  
          //anchor the table to the AnchorPane
          AnchorPane.setTopAnchor(table, 1.0);
          AnchorPane.setBottomAnchor(table, 1.0);
          AnchorPane.setLeftAnchor(table, 1.0);
          AnchorPane.setRightAnchor(table, 1.0);
  
          //show the stage
          primaryStage.setTitle("Hello World!");
          primaryStage.setScene(new Scene(root, 300, 300));
          primaryStage.show();
  
          //Add the data to the table (after everything is shown)
          table.setItems(data);
      }
  
      //Start the application
      public static void main(String[] args) {
          launch(args);
      }
  
      //Add context menus to the headers.
      private void addHeaderContextMenus(TableColumn column) {
  
          //create the menu and attach the items
          ContextMenu menu = new ContextMenu();
          MenuItem hideItem = new MenuItem("hide");
          MenuItem unhideAllItem = new MenuItem("unhide all");
          menu.getItems().addAll(hideItem, unhideAllItem);
  
          //Set behavior for hide/unhide
          hideItem.setOnAction((event) -&gt; {
              hideColumn(column);
          });      
          unhideAllItem.setOnAction((event) -&gt; {
              unhideAllColumns();
          });
  
          //attach the menu to the column (header)
          column.setContextMenu(menu);
      }
  
      private void hideColumn(TableColumn column) {
          column.setMaxWidth(column.getWidth());
          column.setPrefWidth(column.getWidth());
          column.setVisible(false);
      }
  
      private void unhideAllColumns() {
          table.getColumns().forEach(column -&gt; {
              unhideColumnsRecursively((TableColumn)column);
          });
      }
  
      private void unhideColumnsRecursively(TableColumn column) {
          column.getColumns().forEach(childColumn -&gt; {
              unhideColumnsRecursively((TableColumn)childColumn);
          });
          if(column.visibleProperty().get() == false) {
              column.setVisible(true);
              double width = column.getWidth();
              column.setMaxWidth(9999999); //arbitrarily large big number
              column.setPrefWidth(width);
              System.out.println("width to set to: " + width);
              System.out.println("current prefwidth: " + column.getPrefWidth());
              System.out.println("current actual width: " + column.getWidth());
          }
      }
  }
  </code></pre>
  
  <p><strong>DataContainer.java</strong></p>
  
  <pre><code>package testexample;
  
  import javafx.beans.property.SimpleStringProperty;
  
  public class DataContainer {
  
      private final SimpleStringProperty name = new SimpleStringProperty();
      private final SimpleStringProperty color1 = new SimpleStringProperty();
      private final SimpleStringProperty color2 = new SimpleStringProperty();
  
      public DataContainer(String name, String color1, String color2) {
          this.name.set(name);
          this.color1.set(color1);
          this.color2.set(color2);
      }
  
      public String getName() {
          return name.get();
      }
  
      public void setName(String name) {
          this.name.set(name);
      }
  
      public String getColor1() {
          return color1.get();
      }
  
      public void setColor1(String color1) {
          this.color1.set(color1);
      }
  
      public String getColor2() {
          return color2.get();
      }
  
      public void setColor2(String color2) {
          this.color2.set(color2);
      }
  }
  </code></pre>
  
  <p>Here's what the happens when I hide/unhide the name column:  <a href="https://i.stack.imgur.com/3M9C4.gif" rel="nofollow noreferrer">example (animated gif)</a></p>
  
  <p>Here's the output:</p>
  
  <pre><code>width to set to: 80.0
  current prefwidth: 80.0
  current actual width: 80.0
  </code></pre>
  
  <p>...which is of course not what the seems to shown, as the width is clearly longer than 80.0 after un-hiding!  This happens for all of the columns, including the "colors" parent column (in that case both color1 and color2 columns extend to the width of the longest cell value string).</p>
  
  <p>Another twist:  the code actually does work <em>if the user makes sure to resize the column they're hiding before they hide it</em>.  <a href="https://i.stack.imgur.com/XKl3j.gif" rel="nofollow noreferrer">Example (animated gif)</a>.</p>
  
  <p><strong>So, what's going on?  Obviously the application is extending the columns to fit the longest data after the visibility is set to true.  How can I make sure that the columns maintain their former lengths?  Why does it only work after the user has resized that column (if it's setting a flag somewhere maybe I can set that flag manually?)</strong></p>