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;
}
Related
I am writing code that allows a user to build a theme for the application, so they need to be able to effectively communicate that they want to change something about some element of JavaFX.
Suppose I have a bar on the top of every view that lets a user change the way some set of things look: button, label, text, and so on.
Here is a basic stylesheet that I am working with. It just puts style on root and button.
basetheme.css
.root {
-fx-background-color: "teal";
}
Button {
-fx-background-color: "orange";
-fx-font-size: 2em;
-fx-text-fill: #0000ff
}
Right now, all the views I have would load this sheet each time they are loaded:
view.getStylesheets().add("views/basetheme.css");
The Button class and its fx properties here would apply to all buttons in the view.
This is the behavior I want. I want the user to have leverage over Button and its properties during runtime.
For instance, if they want to change Button's -fx-font-size property from -fx-font-size: 2em to -fx-font-size: 3em, they can do that. Is this possible?
Currently, I know setStyle will set properties on some elements, but I am looking for a way to do this for not just a single Button, Label, and so on, but for all them. I want there to be run-time changes. For instance, after a user changes some element like button and one of its properties, it reloads that view and the change is applied.
I want to do something like view.setStyle("Button: some properties") and then it add those properties to Button class or overrides it, instead of view.setStyle("some properties") adding properties to root. The latter would not recognize that the property goes on a button, let alone all Buttons in view.
The obvious reason why this might not work this way is that we are not really changing the css file when we do those inline setStyle calls, just setting over the existing property and thus that inline has higher precedence and is updated.
I know I could technically do somebutton.setStyle("some properties"), but I want the user to be able to modify properties for all Button elements by specifying it at the root of a view so the styles trickle down to subelements in the view. This makes things easier.
You could use CSSFx to constantly pull in a CSS file that has bee written by your app.
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.
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....
I created a button in Qt and gave it the QSS attribute background-color: gray;, while my external stylesheet has set the QSS attribute of the same button to background-color: blue;. When I run the application the button is gray, even though the style sheet is applied after the QWidget::show() is called and just before QApplication::exec(), as shown below:
MyWidget w;
w.show();
...
app.setStyleSheet("..."); // contents of external stylesheet
return app.exec();
Is it possible to have QApplication::setStyleSheet() override the QSS attributes assigned to a Widget in Qt.
No, it is not possible to override the QSS attributes the way you want, and trust me, you don't want to. It is not the order in which you call setStyleSheet that matters. It is the hierarchy that matters first. The call order matters only on widgets which are situated on the same level of the hierarchy.
The reason is that the widget has its internal style rules defined which override the parent's style thus the application style in your case. It is a hierarchy that is respected. You can look at this in the following way:
Say you have a QWidget with the following child hierarchy:
QWidget
|__QPushButton
|
|__QFrame
| |
| |_QListView
|
|__QProgressBar
Let's say you want to customize the background-color to all the widgets in your hierarchy. If the call to QApplication::setStyleSheet() would overwrite the stylesheet properties for the children, it would be impossible for you to set a custom style for your children. That's why child widget's QSS properties overwrite parent widget's QSS properties.
Look at it like the usual way to look at widgets. QPushButton is shown on top of QWidget. QFrame is shown on top of QWidget. QListView is also shown on top of QWidget. Styles apply the same way.
What I recommend doing is having only one external QSS file in which you define everything you want.
EDIT:
As N1ghtLight pointed out QSS preserves the class inheritance hierarchy so if you set a property for a class all its derived classes will inherit that property. For example if you have the following stylesheet:
QAbstractButton {
background-color: red;
}
QPushButton {
color: blue;
}
All QPushButtons will have the background color red and the text color blue as the QPushButton inherits the background-color property value from QAbstractButton which is its ancestor while QAbstractButtons which are not QPushButtons will have the background color red but the text color will remain unchanged.
The example above used a type selector. You can apply the style to specific objects by using different selector types. You can see different selector types here.
I have a component which is created dynamically. I want to access the properties on it.
for example i create a vbox and i want to access the text font or gap of the component
var MyVBox: VBox = new VBox;
MyPanel.addChild(MyVBox);
How should it be done?
All properties and methods are accessed with "." (dot) notation.
Example:
myVBox.width = 400;
Styles are set using the setStyle() method. In your case that would be
myVBox.setStyle("fontFamily", "arial");
myVBox.setStyle("verticalGap", 20);
Check the docs at http://livedocs.adobe.com/flex/3/langref/ for the available properties and styles of each component.
The thing to remember when using ActionScript instead of MXML is that the style properties are not accessed as properties on the object but through the getStyle("propertyName") method. Font is a style for example.