JDK-8186023 : [JavaFX 9] Various ComboBox issues on TabPane with custom skin
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: 9,10
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2017-08-09
  • Updated: 2024-03-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Description
I've noticed some issues when a ComboBox with a custom skin is used in a TabPane with a custom skin. Note: The issue occurs only if the ComboBox skin is specified in an external CSS file. 

- the arrow button is not placed correct, it appears in the top left corner (looks like it has no parent)
- the selected entry does not appear
- the width of the ComboBox is too small
- the NPE issue on focus has been already posted - see JDK-8185854

Please find the related test below - tested with Java 9u175

package test.combobox;

import java.lang.reflect.Field;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.skin.ComboBoxBaseSkin;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ComboTabPaneTest extends Application
{

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

  @Override
  public void start(Stage stage)
  {
    Application.setUserAgentStylesheet(getClass().getResource("/test/combobox/style.css").toExternalForm());
    stage.setScene(new Scene(createContent()));
    stage.setTitle(getClass().getSimpleName());
    stage.show();
  }

  private Parent createContent()
  {
    TabPane tabPane = new TabPane();
    tabPane.getTabs().add(new Tab("Tab", createTabContent()));
    // Note: update package if not in test.combobox 
    tabPane.setStyle("-fx-skin: 'test.combobox.ComboTabPaneTest$TabPaneSkin'");
    
    BorderPane content = new BorderPane();
    content.setCenter(tabPane);
    return content;
  }
  
  private Node createTabContent()
  {
    FlowPane p = new FlowPane();
    p.setPadding(new Insets(40));
    ComboBox<String> combo  = new ComboBox<>();    
    //combo.setStyle("-fx-skin: 'test.combobox.ComboTabPaneTest$ComboBoxListViewSkin'");
    combo.setItems(FXCollections.<String>observableArrayList("Regular", "ReadOnly", "Disabled", "Disabled/ReadOnly"));
    combo.setDisable(false);
    combo.setEditable(false);
    combo.setValue("ReadOnly");
    p.getChildren().add(combo);
    return p;
  }
  
  
  // TabPaneSkin class
  public static class TabPaneSkin extends javafx.scene.control.skin.TabPaneSkin
  {    
    public TabPaneSkin(TabPane tabPane)
    {
      super(tabPane);
    }
  } 
  
  // ComboBoxSkin class
  public static class ComboBoxListViewSkin<T> extends javafx.scene.control.skin.ComboBoxListViewSkin<T>
  {    
    public ComboBoxListViewSkin(ComboBox<T> combo)
    {
      super(combo);
      StackPane arrowButton = null;
      try
      {
        Field field = ComboBoxBaseSkin.class.getDeclaredField("arrowButton");
        field.setAccessible(true);
        arrowButton = (StackPane)field.get(this);
        System.err.println("Parent of arrow-button: " + arrowButton.getParent());      
      }
      catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e)
      {
        e.printStackTrace();
      }
    }
  }    
}

style.css:
.root {
	-fx-font: 11 Tahoma;
    -fx-text-fill: black;
}

 .text {
    -fx-text-fill: #F00;
    -fx-font-smoothing-type: lcd;
}

.combo-box{
    -fx-skin: "test.combobox.ComboTabPaneTest$ComboBoxListViewSkin";
}

.combo-box-base{
    -fx-background-color: #0FF;
    -fx-padding: 2 2;
}

.combo-box-base:editable{
    -fx-background-color: #FF0;
}

.combo-box-base:editable > .text-field {
    -fx-border-image-source: null;
    -fx-background-color: transparent;
    -fx-padding: 1 0;
}

.combo-box-base > .arrow-button  {
   -fx-background-color: red;
   -fx-padding: 0 4;
  }

.combo-box-base > .arrow-button > .arrow {
    -fx-background-color: black;
    -fx-background-insets: 0 0 0 0;
    -fx-padding: 2 4;
    -fx-shape: "M 0 0 H 7 L 3.5 4 z";	
}

/* -------------- STYLES FOR THE DEFAULT LISTVIEW-BASED COMBOBOX ------------- */

.combo-box-popup > .list-view {
    -fx-border-style: solid;    
    -fx-border-width: 1;    
    -fx-border-color: black;    
    -fx-background-color: white;
    -fx-background-insets: 0, 1;
}

.combo-box-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell {
    -fx-padding: 1 10;
    /*-fx-background-color: red;*/
    /*-fx-cell-size: 10;*/
}
.combo-box-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected {
    -fx-background:  green;
    -fx-background-color:  orange !important;
}
.combo-box-popup  > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:hover,
.combo-box-popup  > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected:hover {
    -fx-background-color: silver !important;
}
.combo-box-popup > .list-view > .placeholder > .label {
    -fx-text-fill: blue;
}
Comments
hmm .. self-healing? Looks nearly okay in fx11, except the initial width which is too small and extends to the popup's width on closing
05-08-2019