自定义皮肤:样式弹出窗口

时间:2017-08-02 17:41:18

标签: java javafx javafx-8

我正在努力设置一个弹出窗口,它会在自定义skin中创建。

我想我必须使用PopupControl,而不是Popup

PopupControl popup = new PopupControl();
popup.getScene().setRoot(popupContentPane);
popup.setAutoHide(true);
popup.setAnchorLocation(PopupWindow.AnchorLocation.WINDOW_BOTTOM_LEFT);
popup.setStyle("-fx-background-color: red;");
popup.getStyleClass().add("my-popup");
popup.show(getSkinnable(), screenLocation.getX(), screenLocation.getY());

skinnable会覆盖userAgentStylesheet:

@Override
public String getUserAgentStylesheet() {
    return Stylesheets.getDefaultStylesheet();
}

但是样式,styleClass和应用于popupContentPane的任何子节点的styleClass都没有效果。

如果我正确理解the documentation,弹出窗口应该使用ownerNode的样式表(这里是skinnable)。

这个问题有点类似于我的一个老问题,当时没有得到任何答案:Custom control & opaque popup

如何设置弹出窗口的样式?

更新

这里有一个跟随[〜wzbergers]提示的SSCCE,虽然它看起来很奇怪,弹出窗口也需要一个皮肤。样式仍然不起作用:

MinimalApplication:

package test;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class MinimalApplication extends Application {

    @Override
    public void start(Stage primaryStage) {
        MinimalControl minimalControl = new MinimalControl();
        minimalControl.setText("test");
        BorderPane root = new BorderPane(minimalControl);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

}

MinimalControl:

package test;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.Control;
import javafx.scene.control.Skin;
import test.skin.MinimalControlSkin;
import test.skin.Stylesheets;


public class MinimalControl extends Control {

    private static final String DEFAULT_STYLE_CLASS = "minimal-control";

    private final StringProperty text = new SimpleStringProperty(this, "text");

    public MinimalControl() {
        getStyleClass().setAll(DEFAULT_STYLE_CLASS);
    }

    @Override
    public String getUserAgentStylesheet() {
        return Stylesheets.getDefaultStylesheet();
    }

    @Override
    protected Skin<?> createDefaultSkin() {
        return new MinimalControlSkin(this);
    }

    public final String getText() {
        return textProperty().get();
    }

    public final void setText(String text) {
        textProperty().set(text);
    }

    public StringProperty textProperty() {
        return text;
    }
}

MinimalControlSkin:

package test.skin;

import javafx.geometry.Bounds;
import javafx.scene.control.Label;
import javafx.scene.control.SkinBase;
import javafx.scene.layout.BorderPane;
import javafx.stage.PopupWindow;
import test.MinimalControl;

public class MinimalControlSkin extends SkinBase<MinimalControl> {

    private final Label label = new Label();
    private final BorderPane contentPane = new BorderPane(label);
    private final MinimalPopup popup = new MinimalPopup();

    public MinimalControlSkin(MinimalControl control) {
        super(control);
        getChildren().add(contentPane);

        label.textProperty().bind(control.textProperty());
        label.setOnMouseClicked(event -> openPopup());

        popup.setAutoHide(true);
        popup.setAnchorLocation(PopupWindow.AnchorLocation.WINDOW_BOTTOM_LEFT);
    }

    private void openPopup() {
        Bounds localBounds = label.getBoundsInLocal();
        Bounds screenBounds = label.localToScreen(localBounds);

        popup.show(label, screenBounds.getMinX(), screenBounds.getMinY());
    }

}

MinimalPopup:

package test.skin;

import javafx.scene.control.PopupControl;
import javafx.scene.control.Skin;

public class MinimalPopup extends PopupControl {

    private static final String DEFAULT_STYLE_CLASS = "minimal-popup";

    public MinimalPopup() {
        getStyleClass().setAll(DEFAULT_STYLE_CLASS);
    }

    @Override
    protected Skin<?> createDefaultSkin() {
        return new MinimalPopupSkin(this);
    }

}

MinimalPopupContentPane:

package test.skin;

import javafx.beans.property.StringProperty;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;

public class MinimalPopupContentPane extends BorderPane {
    private final Label label = new Label("some popup text");

    public MinimalPopupContentPane() {
        setCenter(label);
    }


    public final String getText() {
        return textProperty().get();
    }

    public final void setText(String text) {
        textProperty().set(text);
    }

    public StringProperty textProperty() {
        return label.textProperty();
    }

}

MinimalPopupSkin:

package test.skin;

import javafx.scene.Node;
import javafx.scene.control.Skin;

public class MinimalPopupSkin implements Skin<MinimalPopup> {

    private final MinimalPopup popup;
    private MinimalPopupContentPane contentPane = new MinimalPopupContentPane();

    public MinimalPopupSkin(MinimalPopup popup) {
        this.popup = popup;
        contentPane.idProperty().bind(popup.idProperty());
        contentPane.styleProperty().bind(popup.styleProperty());
        contentPane.getStyleClass().addAll(popup.getStyleClass());
    }

    @Override
    public MinimalPopup getSkinnable() {
        return popup;
    }

    @Override
    public Node getNode() {
        return contentPane;
    }

    @Override
    public void dispose() {
        contentPane = null;
    }

}

样式表:

package test.skin;

public class Stylesheets {

    private Stylesheets() {
    }

    public static String getDefaultStylesheet(){
        return Stylesheets.class.getResource("modena/modena.css").toExternalForm();
    }
}

测试/皮肤/摩德纳/ modena.css:

.minimal-control { 
    -fx-skin: "test.skin.MinimalControlSkin";
}

.minimal-control .popup {
    -fx-border-color: black; /* -fx-box-border; */
    -fx-border-width: 1px;
    -fx-background-color: red;
}

.minimal-control PopupControl {
    -fx-border-color: black; /* -fx-box-border; */
    -fx-border-width: 1px;
    -fx-background-color: blue;
}

.minimal-popup {
    -fx-border-color: black; /* -fx-box-border; */
    -fx-border-width: 1px;
    -fx-background-color: yellow;
}

.minimal-control .minimal-popup {
    -fx-border-color: black; /* -fx-box-border; */
    -fx-border-width: 1px;
    -fx-background-color: green;
}

1 个答案:

答案 0 :(得分:0)

PopupControl不是一个节点 - 所以你必须设置它的内容窗格样式,或者更好地提供一个将样式绑定到内容窗格的外观,就像下面的例子一样。

PopupControl popup = new PopupControl() {
    @Override
    protected Skin<?> createDefaultSkin() {
      return new PopupControlSkin(this, popupContentPane);
    }
};
...
  public class PopupControlSkin implements Skin<PopupControl> {

  private PopupControl popup;
  private Pane content;

  public PopupControlSkin(final PopupControl control, final Pane content) {
    this.popup = control;
    this.content = content;
    content.idProperty().bind(popup.idProperty());
    content.styleProperty().bind(popup.styleProperty());
    content.getStyleClass().addAll(popup.getStyleClass());
  }

  @Override 
  public Node getNode() {
      return content;
  }

  @Override
  public void dispose(){
  }

  @Override
  public PopupControl getSkinnable(){
    return popup;
  }
}