JavaFX and css misunderstanding - css

In my fxml I have url for css (this fxml created via SceneBuilder)
<AnchorPane>
...
<stylesheets>
<URL value="#../styles/test.css" />
</stylesheets>
</AnchorPane>
and test.css contains
.root{
...
}
If I do preview in SceneBuider everything is ok. But in runtime this style doesn't apply. I change definition to
#AnchorPane{
...
}
and this way everynting is ok both in preview and runtime. What's wrong with .root?

Why it doesn't work
You aren't applying your css to the root node of the scene. You are applying it to the AnchorPane (the <stylesheets> element is a child of the <AnchorPane> element). Therefore if you set a .root css selector for a stylesheet only applied to the AnchorPane, the .root css selector is never going to apply because (as the documentation you quote in your comment states), "the .root style class is applied to the root node of the Scene instance".
Setting a root style class for your pane
You could make it work by setting a .root class on the AnchorPane, for example: <AnchorPane styleClass="root">. Though you may want to use a different style class name (e.g. <AnchorPane styleClass="custom-root"> and leave the .root style class to be reserved for the scene (as overriding .root might have unintended consequences).
Setting a stylesheet for the scene
The other way you could handle it is to not define your css stylesheet in your FXML, but instead to add the css stylesheet to your scene in code using:
scene.getStylesheets().add("/com/example/javafx/app/mystyles.css")
As using .root indicates that you want to change the style for the entire scene, I'd advise using this approach.
If you do so, you can still preview the scene with styles by selecting in SceneBuilder the menu item Preview | Scene Stylesheets | Add a Style Sheet....

Related

Problems with setting TableColumn width in FXML using CSS

Here is my .fxml code:
<TableColumn id="tableColumnVertical" text="">
<graphic>
<VBox>
<Label text="text"/>
</VBox>
</graphic>
</TableColumn>
Here I have simplified .css code:
#tableColumnVertical {
-fx-background-color: Lime;
-fx-min-width: 40;
-fx-max-width: 40;
}
This doesn't set width of TableColumn but sets background. Why?
I can use this code:
<TableColumn id="tableColumnVertical" text="" minWidth="40" maxWidth="40">
and it works. Why inline works and .css does not?
While writing this post I tried adding -fx-pref-width: 40; to .css and now it also works.
1) I would like know why inline works and .css does not (while background-color works)? Why after adding prefWidth it started to work?
2) Can I use both fx:id and id?
3) Also, in some SO answers I saw people advice to use styleClass to set style. When should I use styleClass?
Edit:
a TableColumn also contains the necessary properties to:
Be resized (using minWidth/prefWidth/maxWidth and width properties)
https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TableColumn.html
Not sure if this is accurate, but I decided to post this edit.
The -fx-pref-width is setting the property of the TableColumnHeader (same for -fx-min-width, see below). Setting this property via CSS is buggy: JDK-8087822.
You can use both fx:id and id. If you only set fx:id it will also be used for the id. If you set both, the id is used for CSS and the fx:id is used for injecting the instance into a controller.
You would add a style class if you want to style many nodes the same way.
Note: The following mostly deals with implementation details for JavaFX 11.0.1 (at least, I couldn't find documentation).
The problem is the difference between TableColumnBase.minWidth and Region.minWidth. The former is not styleable from CSS because it is not a StyleableProperty. The latter is and it is that property that defines the -fx-min-width CSS property.
When you do:
<TableColumn id="tableColumnVertical" text="" minWidth="40" maxWidth="40">
You are setting the minWidth property of the TableColumn using a property setter. It is not analogous to setting the CSS property.
However, the JavaFX CSS Reference Guide does document that TableColumn is part of the substructure of a TableView. This would seem to indicate you can style the column via CSS. But again, non of the properties are actually styleable; the getCssMetaData() method returns Collections.emptyList().
TableColumnBase does implement Styleable (where getCssMetaData() comes from) which means it has the following method: getStyleableNode(). The TableColumn implementation of this method, once the TableView has been displayed, returns an instance of TableColumnHeader. What this means is any CSS applied to the TableColumn is actually applied to the TableColumnHeader. It is this latter class that extends Region and thus has the styleable minWidth property. And from some testing the minWidth property of the TableColumnHeader instance is set as expected.
The problem appears to be that the minWidth of the TableColumnHeader has no affect on the TableColumn. The implementation only takes TableColumn.minWidth into account. And this unfortunately means you won't be able to set the minWidth of the TableColumn from CSS.
This behavior might be a bug.

JavaFX: Styling application with CSS Selectors

I have a couple of questions about styling a JavaFX application with CSS Selectors (such as: .table-view for every TableView).
I have created a main CSS-file, in which I want to define the universal style properties for my application. For example: every TableView gets the same color in every screen. I just import the Main.css in every .css that is associated with a .fxml file.
Now I would like to style every HBox in a 'sidebar' the same way. I have tried it like this (as suggested in Oracle's documentation):
.sidebar > .hbox {
/* Just some styling */
}
This is not working to my surprise, but the following pieces of code are working:
.sidebar > HBox {
/* Just some styling */
}
.sidebar HBox {
/* Just some styling */
}
Maybe it has something to do with the fact that .sidebar is a custom style, but I am not sure about this.
So my questions are:
1. Why isn't the first one working?
2. What should be the way to do this? (with .hbox or HBox and > or nothing?)
As you can see in the CSS documentation the HBOX class has no style class defined. Therefore you can't simply use .hbox
http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html#hbox
If you want to lookup only direct children of the toolbar the > sign can be used. Using the > sign in a CSS selector will have some benefit in performance issues because by doing so not the complete child hierarchy under the Toolbar Control need to be scanned. Matching Nodes will only be searched in the first hierarchy of children.
So if you want to select all buttons that are direct children of a sidebar you can do the following:
. sidebar > .button
But if you really want to style all button in a sidebar (even if they are wrapped in panes, etc.) you need to use the following selector:
.sidebar .button
Back to your HBOX question: Even if the HBOX has no defined style class (.hbox) it has a type that can be used for a type selector. As described in the CSS doc all nodes have a type:
Node's getTypeSelector method returns a String which is analogous to a
CSS Type Selector. By default, this method returns the simple name of
the class. Note that the simple name of an inner class or of an
anonymous class may not be usable as a type selector. In such a case,
this method should be overridden to return a meaningful value.
Because of that the HBOX selector is working.

Set css file for default skin

I created css style sheet based on caspian.css. My question is how I can load the new css skin as default skin?
And also how I can change the skins during runtime?
You can either add the stylesheet directly to the Scene or to any Parent to apply it to the node and all decendants. Both classes have a method getStylesheets() that returns a ObservableList<java.lang.String>, that contains the URLs of the stylesheets applied to the object. Modify this list!
If you use fxml, you can specify the stylesheet there too (Of course this will only set the a initial stylesheet).
This is an example how to add the stylesheet at the creation of the scene. Of course you can remove the stylesheet from the list at any time and add another. Style.css is the stylesheet I want to add here and to a.b the package that contains the stylesheet.
// Load some content from some fxml file; Style.css not added there
Parent parent = (Parent) fxmlLoader.load(
getClass().getResourceAsStream("MainFrame.fxml"));
// create scene with content
Scene scene = new Scene(parent);
// alternatively use Node.getScene() for any node to get the scene
// add the stylesheet
scene.getStylesheets().add(
getClass().getClassLoader().getResource("a/b/Style.css").toString());
// ...
ObservableList<T> extends java.util.List<T> and should be easy to use.
Note that the behaviour sometimes may not be quite as expected. e.g. the popup that shows, if you click on a combobox is no decendant of the combobox and the paths from these nodes to from the root node of the scene should have only the root node in common. Therefore the popup will not be styled, if you add the stylesheet to the Pane that contains the combobox (if this is not the root node of the scene).
The following picture contains a screenshot of a combobox with a styled popup. This only works, since the css-file was added to the scene instead of the AnchorPane, that contains the ComboBox. I used different css-classes for the items to color them. (The red rect and text is not part of my application of course)
These are the style classes i used
.indexed-cell.class-value-bad-1 {
-fx-background-color: orange;
}
.indexed-cell.class-value-good-1 {
-fx-background-color: forestgreen;
}
.indexed-cell.class-value-normal {
-fx-background-color: white;
}

skinClass working in mxml, but not in external css

I have a simple button in a mxml file, if I set the skinClass property in the tag itself it works, however, if I set the skinClass property in an external css file, it doesn't apply to the button.
Works:
view.mxml
<s:Button id="btnRefresh" skinClass="skins.RefreshButtonSkin"/>
Doesn't work:
view.mxml
<s:Button id="btnRefresh"/>
style.css
#btnRefresh
{
skinClass: ClassReference("skins.RefreshButtonSkin");
fontSize: 12px;
}
Someone knows how I can get this css working?
Note: I can apply other styles to the button using the css, eg fontSize works
Edit: Additional info
The button is nested in the actionContent part of my view
view.mxml
<s:actionContent>
<s:Button id="btnRefresh"/>
</s:actionContent>
The css file is declared in my main mxml file
main.mxml
<fx:Style source="style.css"/>
I'm compiling for flex 4.5.1, it's a mobile application
It would seem that this is a bug in the ActionBar component. I've tried id selector (#btnRefresh), class selector (.btnRefreshStyle), component selector (s|Button) and #Thembie's suggestion.
I've tried using skinClass and skin-class.
None of these work when the button resides in the actionContent property of the View component. But it all works fine when you move the button to the View component.
So I'm afraid you're stuck with hard-coding that skinclass. You might consider filing a bug report.
s|Button#btnRefresh
{
skinClass: ClassReference("skins.RefreshButtonSkin");
}
defaults.css in the mobile theme has style rules for ActionBar with a higher CSS "specificity" level than the ID selector you're using.
Short answer: Use #actionGroup #btnRefresh as your selector.
Long answer: ActionBar has the following selectors for rules to support the "defaultButtonAppearance" style in the mobile theme:
ActionBar Group#navigationGroup Button
ActionBar Group#actionGroup Button
ActionBar.beveled Group#navigationGroup Button
ActionBar.beveled Group#actionGroup Button
These are in place to make it easy to swap out the flat-look buttons with the iOS-styled "beveled" buttons.
Jason was right, the default.css in mobile theme override your s|Button#btnRefresh style.
In order for your skin to work, just make your style stronger like:
s|ActionBar s|Group#navigationGroup s|Button#btnRefresh{...}

Defining Flex 4 Skins with CSS

I am trying to define my Flex 4 Skins via CSS but I my custom skin will not display. Here is what I am doing:
In my application I import my css and define the styleName in my button:
<fx:Style source="styles.css"/>
<s:Button label="Button" styleName="circle"/>
Here is my CSS:
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/mx";
s|Button.circle
{
skinClass: ClassReference("skins.buttons.CircleButton");
}
My understanding is that my button should be supplied it's skinClass via the CSS but it fails to work. If I define the skinClass directly like below it works fine:
<s:Button label="Button" skinClass="skins.buttons.CircleButton"/>
Any help would be appreciated.
Make sure you have your CSS file under the root Application file first. Second, I would try to do the css without the type selector, so instead of s|Button.circle, just do .circle.
EDIT
You can also try putting the style in a Style tag within the same container as your button to see if that works. Are you sure your application can find your style.css? Showing more code might help the situation.
Per the official Flex CSS documentation:
Class Selector: A CSS class selector
matches components that meet a class
condition. The CSS syntax to declare a
class selector is to prefix the
condition with a dot. You can either
declare a class selector as a
condition of a type selector, or
universally to any type that meets the
class condition.
.header { background-color: #CCCCCC; }
HBox.footer { background-color: #999999; }
Note: In Flex a class condition is met
using the styleName attribute on a
component. For example, you may have
two classes of HBox: "header" and
"footer". Above, the first selector
applies to any component with
styleName="header"; the second
selector should only apply to HBox
components with styleName="footer"
(something that actually needs to be
fixed and enforced in Gumbo, as
to-date class selectors have only been
universal and any type in the selector
is ignored).
It looks like selectors may not be working in Gumbo...

Resources