6 Replies Latest reply: Jan 31, 2013 4:25 PM by Puce RSS

    Custom control & opaque popup

    Puce
      Hi,

      I'm developing a custom control. I've create a custom Skin for this control where I layout a TextField and a Button. When the button gets clicked a Popup windows should be opened.

      For this I've created an anonymous sublcass of PopupControl in the Skin implementation.

      The trouble I'm having is that the PopupControl is transparent. How can I make it opaque? I tried to configure the background in the css but without success:

      .my-control .popup-control{
      -fx-background-color: yellow;
      }

      Any other way? Or should I use a Popup instead of PopupControl? (I understand that PopupControl is stylable, where Popup isn't, so I guess I should use PopupControl?)
        • 1. Re: Custom control & opaque popup
          David Grieve
          And you are not using MenuButton because...?
          Have you looked at using ContextMenu instead of PopupControl for the popup?

          In answer to your question, a PopupControl gets its styles from the "anchor" node's Scene, but is not a child of the anchor node. In other words, the selector ".my-control .popup-control" doesn't match anything. Give your PopupControl an extra style-class or an id and use that in the selector:
          PopupControl myButtonPopup = new PopupControl();
          myButtonPopup.getStyleClass().add("my-button-popup");
          Then use ".my-button-popup" as a selector.
          • 2. Re: Custom control & opaque popup
            Puce
            Hi David,

            Thanks for your response.

            I guess you could get some similar effect using a MenuButton and a CustomMenuItem, but if feels more like a "misuse" since I don't want to create a menu. And it's also visually a bit different than I want it.

            I tried you PopupControl suggestion, but still without success.

            Here is about what I have (the PopupControl is used inside a Skin):
            public class SomeControlSkin implements Skin<SomeControl> {
            
                private SomeControl control;
              
                private OtherControl otherControl = new OtherControl();
                private PopupControl popupControl = new PopupControl() {
                    { // instance initializer of PopupControl
            
                        setSkin(new Skin<PopupControl>() {
                            private PopupControl skinnable = popupControl;
                            private Node node = otherControl;
                            @Override
                            public PopupControl getSkinnable() {
                                return skinnable;
                            }
            
                            @Override
                            public Node getNode() {
                                return node;
                            }
            
                            @Override
                            public void dispose() {
                                skinnable = null;
                                node = null;
                            }
                        });
            
                        getStyleClass().add("some-control-popup");
                    }
                };
            
               public SomeControlSkin(SomeControl someControl){
                  this.someControl = someControl;
                  otherControl.fooProperty().bind(someControl.fooProperty());
                  ...
               }
            
            ...
            
            }
            .some-control { 
                -fx-skin: "somePackage.SomeControlSkin";
            }
            
            .some-control .popup-control{ 
                -fx-background-color: yellow;
            }
            
            .some-control-popup{
                -fx-background-color: aliceblue;
            }
            
            .some-control .some-control-popup{
                -fx-background-color: yellow;
            }
            I'm not sure how to get the content to the PopupControl. Is setting a custom skin really the right way? The content is shown, but the background stays transparent.

            Edited by: Puce on 28.01.2013 15:29
            • 3. Re: Custom control & opaque popup
              David Grieve
              This is pretty wonky. The popup should get its stylesheets from the scene of the owner node. It may be that the owner node's scene doesn't have any stylesheets at the time the popup is created and the popup doesn't listen for changes in the owner's scene's stylesheets (there is a bug against this).

              As a workaround, you can listen to the ownerNode property of the popup and grab the ownerNode's scene's stylesheets when the owner node is set.
              ownerNodeProperty().addListener(new ChangeListener<Node>() {
              
                  @Override
                  public void changed(ObservableValue<? extends Node> ov, Node t, Node t1) {
                      popupControl.getScene().getStylesheets().addAll(t1.getScene().getStylesheets());
                  }
              });
              getStyleClass().add("some-control-popup");
              It would be helpful if you could file a JIRA issue at http://javafx-jira.kenai.com
              • 4. Re: Custom control & opaque popup
                Puce
                I'm writing a library. The scene and its styesheets are defined by the user of the library and are thus out of my control.

                The relevant code is inside a Skin implemenation of a custom control.
                The CSS is referenced by the getUserAgentStylesheet() method of the custom control.
                The custom control has the styleClass "custom-control".

                Basically the Skin says:
                - render the cutom control as a TextField and a Button
                - if this button (part of the Skin) gets pressed: pop up a window with another custom control (which has it own Skin etc.)

                I'm not sure if PopupControl is the right thing to use here, though. I also tried with Popup but it didn't work either:
                public class SomeControlSkin implements Skin<SomeControl> {
                 
                    private SomeControl control;
                  
                    private OtherControl otherControl = new OtherControl();
                    private Popup popup = new Popup();
                 
                   public SomeControlSkin(SomeControl someControl){
                      this.someControl = someControl;
                      otherControl.fooProperty().bind(someControl.fooProperty());
                
                      ...
                
                      popupControl.getContent().add(otherControl);   
                
                      ...
                   }
                 
                ...
                 
                }
                and
                .some-control { 
                    -fx-skin: "somePackage.SomeControlSkin";
                }
                 
                .some-control .popup{ 
                    -fx-background-color: yellow;
                }
                
                .some-control .other-control{ 
                    -fx-background-color: yellow;
                }
                (there is no styleClass property for Popup)
                • 5. Re: Custom control & opaque popup
                  Puce
                  Note: I cross-posted this question here: http://stackoverflow.com/questions/14610639/custom-control-opaque-popup
                  • 6. Re: Custom control & opaque popup
                    Puce
                    I managed to get a small step further. The following will fill the Popup:
                    popupControl.getScene().setFill(Color.YELLOW);
                    But how can I do this with CSS?

                    I even tried:
                    .some-control { 
                        -fx-skin: "somePackage.SomeControlSkin";
                        -fx-background-color: black;
                        -fx-background-insets: 0;
                        -fx-fill: black;
                    }
                    
                    .other-control { 
                        -fx-skin: "somePackage.OtherControlSkin";
                        -fx-background-color: black;
                        -fx-background-insets: 0;
                        -fx-fill: black;
                    }
                    But it didn't change the background no matter if I added the control to a Popup or to the main scene!? (I'm not sure if fill or background should do the trick and I'm not sure if I have to set the insets and to what value, though).

                    I also tried to add a styleClass:
                       popupControl.getContent().add(otherControl);
                       otherControl.getStyleClass().add("other-control-popup");
                    and
                    .other-control-popup {
                        -fx-background-color: black;
                        -fx-background-insets: 0;
                        -fx-fill: black;
                    }
                    But this didn't work either.