For a special feature request, i have to avoid to close the combobox by a mouse click on the butten. To solve this problem, i've overidden the hide function of the combobox. That worked very well in all situations, except in the embedded mode under os x.
code:
public class ExtendedComboBox<T> extends ComboBox<T> {
private final BooleanProperty autoHideProperty = new SimpleBooleanProperty(true);
private Robot mouseRobot = Application.GetApplication().createRobot();
@Override
protected Skin<?> createDefaultSkin() {
Skin<?> s = new ComboBoxListViewSkin<T>(this){
@Override
protected boolean isHideOnClickEnabled() {
return getIsHideOnClickEnabled();
}
@Override
protected PopupControl getPopup() {
PopupControl p = super.getPopup();
p.autoHideProperty().bind(autoHideProperty);
return p;
}
};
return s;
}
public boolean getIsHideOnClickEnabled() {return autoHideProperty.getValue();}
public void setIsHideOnClickEnabled(Boolean value) { autoHideProperty.set(value);}
public final BooleanProperty autoHideProperty(){ return autoHideProperty; }
public void initComboBoxSpecialBehavior(){
setIsHideOnClickEnabled(false);
showingProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable,
Boolean oldValue, Boolean newValue) {
final String selectedStyle = "combo-box-showing";
if (newValue) {
if(!getStyleClass().contains(selectedStyle)) {
getStyleClass().add(selectedStyle);
}
}else if(getStyleClass().contains(selectedStyle)){
getStyleClass().remove(selectedStyle);
}
}
});
setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if(!isShowing()){
show();
}
}
});
setOnMouseExited( new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
hide();
}
});
addEventFilter(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
event.consume();
hide();
}
});
}
@Override
public void hide(){
if(!isShowing()) return;
Point2D point = ExtendedComboBox.this.localToScreen(getLayoutBounds().getMinX(), getLayoutBounds().getMinY());
if(point == null) {
return;
}
Bounds buttonBound = new BoundingBox(point.getX(), point.getY(), getWidth(), getHeight()+5); //+2 height necessary for mac, depending on popup-positioning
if (!buttonBound.contains(mouseRobot.getMouseX(), mouseRobot.getMouseY())) {
System.out.println("hide"+buttonBound.toString()+" getMouseX:"+mouseRobot.getMouseX()+" getMouseY:"+mouseRobot.getMouseY());
super.hide();
}
}
}
public class ComboBoxTest extends Application {
private ExtendedComboBox<String> createComboBox(){
ObservableList<String> options = FXCollections.observableArrayList(
"Option 1",
"Option 2",
"Option 3"
);
ExtendedComboBox<String> cp = new ExtendedComboBox<String>();
cp.setItems(options);
cp.setIsHideOnClickEnabled(false);
cp.initComboBoxSpecialBehavior();
return cp;
}
@Override
public void start(Stage primaryStage) {
try {
StackPane root = new StackPane();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
root.getChildren().add(createComboBox());
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
code:
public class ExtendedComboBox<T> extends ComboBox<T> {
private final BooleanProperty autoHideProperty = new SimpleBooleanProperty(true);
private Robot mouseRobot = Application.GetApplication().createRobot();
@Override
protected Skin<?> createDefaultSkin() {
Skin<?> s = new ComboBoxListViewSkin<T>(this){
@Override
protected boolean isHideOnClickEnabled() {
return getIsHideOnClickEnabled();
}
@Override
protected PopupControl getPopup() {
PopupControl p = super.getPopup();
p.autoHideProperty().bind(autoHideProperty);
return p;
}
};
return s;
}
public boolean getIsHideOnClickEnabled() {return autoHideProperty.getValue();}
public void setIsHideOnClickEnabled(Boolean value) { autoHideProperty.set(value);}
public final BooleanProperty autoHideProperty(){ return autoHideProperty; }
public void initComboBoxSpecialBehavior(){
setIsHideOnClickEnabled(false);
showingProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable,
Boolean oldValue, Boolean newValue) {
final String selectedStyle = "combo-box-showing";
if (newValue) {
if(!getStyleClass().contains(selectedStyle)) {
getStyleClass().add(selectedStyle);
}
}else if(getStyleClass().contains(selectedStyle)){
getStyleClass().remove(selectedStyle);
}
}
});
setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if(!isShowing()){
show();
}
}
});
setOnMouseExited( new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
hide();
}
});
addEventFilter(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
event.consume();
hide();
}
});
}
@Override
public void hide(){
if(!isShowing()) return;
Point2D point = ExtendedComboBox.this.localToScreen(getLayoutBounds().getMinX(), getLayoutBounds().getMinY());
if(point == null) {
return;
}
Bounds buttonBound = new BoundingBox(point.getX(), point.getY(), getWidth(), getHeight()+5); //+2 height necessary for mac, depending on popup-positioning
if (!buttonBound.contains(mouseRobot.getMouseX(), mouseRobot.getMouseY())) {
System.out.println("hide"+buttonBound.toString()+" getMouseX:"+mouseRobot.getMouseX()+" getMouseY:"+mouseRobot.getMouseY());
super.hide();
}
}
}
public class ComboBoxTest extends Application {
private ExtendedComboBox<String> createComboBox(){
ObservableList<String> options = FXCollections.observableArrayList(
"Option 1",
"Option 2",
"Option 3"
);
ExtendedComboBox<String> cp = new ExtendedComboBox<String>();
cp.setItems(options);
cp.setIsHideOnClickEnabled(false);
cp.initComboBoxSpecialBehavior();
return cp;
}
@Override
public void start(Stage primaryStage) {
try {
StackPane root = new StackPane();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
root.getChildren().add(createComboBox());
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}