While the CSS styling tutorials mention both default style sheet (caspian.css) and default classes for built-in controls (like .line for Line), my controls seem to lack both (checked by debugger).
As a result, the do not react for additional custom CSS if I do not set their class explicitly, which is annoying and destroys the whole point of global CSS styling.
I would be grateful for any ideas of what may cause such behaviour.
In JavaFX, three CSS selectors are supported, which are analogous to Type Selectors, Class selectors, and ID selectors in standard CSS. It's important to be a bit careful with the word "class", which has different meanings in the Java world and the CSS world: a Java class is a CSS Type; a CSS class is set on a node via a property called styleClass.
The Type Selector is determined by the result of calling the method getTypeSelector, which is declared in the interface Styleable. Node implements this interface, and implements getTypeSelector to return
getClass().getName() without the package name
So any Node may be styled by specifying its simple class name:
Label {
-fx-text-fill: green ;
}
Line {
-fx-stroke: red ;
}
etc.
CSS classes are determined by the getStyleClass() method in Styleable, which returns a list of strings. (Note that nodes may have multiple style classes, though I have never understood why this is a List rather than a Set.) By default, this list is empty, but Control subclasses set this value via their default skin to be the "css-ized" version of the class name (Button becomes button, ComboBox becomes combo-box, etc.). Thus
.label {
-fx-text-fill: green ;
}
works, but
.line {
-fx-stroke: red ;
}
does not work without previously setting the style class:
Line line = new Line();
line.getStyleClass().add("line");
Finally, ID Selectors work by specifying an id on the node. Ids are intended to be unique among all nodes in the scene graph. So you can do
Line line = new Line();
line.setId("my-line");
with
#my-line {
-fx-stroke: red ;
}
So in your example, the style class is not set by default (Line is not a Control subclass). You must either set it "by hand", or use a type selector.
One last note: you mentioned that your line "lacked caspian.css". I'm not quite sure what that means (as Lines are not styled at all by the default stylesheet), but the default stylesheet is only loaded the first time a Control is instantiated. This is intended as a performance enhancement for scene graphs that use no controls (and so would not benefit from the default stylesheet anyway).
Related
I have a style.css file which contains styles such as:
.tab{
-fx-background-color:rgb(15,63,103);
... etc ...
}
.selectedTab{
-fx-background-color:rgb(52,105,155);
... etc ...
}
I am trying to change a Button's css at runtime when certain conditions are met.
I know you can set a style by typing the css inline with the:
mBtn.setStyle("-fx-background-color:rgb(15,63,103);");
Although to me that seems less clean than referencing styles in the .css file.
So I set my buttons CSS initially using:
newBtn.getStylesheets().add(getClass().getResource("styles.css").toExternalForm());
newBtn.getStyleClass().add("tab");
But then later, when I try and change it using:
mBtn.getStyleClass().removeAll();
mBtn.getStyleClass().add("selectedTab");
it doesn't change. Do I need to refresh/redraw the Node after changing it's style?
Also, generally, what is the preferred way to set styles in JavaFX. Is it with setStyle("..."); method or is it by linking it to a stylesheet, or is it a third way I haven't considered.
Thank you for your time :)
Edit: Solved by user fabian with first comment. The problem was removeAll() is a method that removes all the elements specified as arguments. What I intended to do is actually use the clear() function.
In Javafx there is an option to set colors/styles for buttons e.g.,
button.setStyle("-fx-background-color: red");
Is there any syntax for checking a buttons style for witch color the button has?
Basically I want to do something like:
if (button.style("-fx-background-color: red")) {
something....
}
Yes, you can do it via .contains() or via regular expression (.matches()) by using getStyle() (for example, in your case, it would be button.getStyle().contains("-fx-background-color: red").
However, keep in mind that both setStyle() and getStyle() only refer to inline styles. Therefore, they will not include the styles that are passed via CSS selectors in attached CSS files.
Generally, using visual properties for determining semantic properties is not considered a good practice. If you have buttons that are supposed to exhibit a particular behavior, consider extending the Button class and adding those as proper properties instead.
Button button = new Button();
String[] styles = button.getStyle().split(";");
for(String style : styles){
if(style.contains("-fx-background-color")){
String color = style.split(": ")[1]; // the color of the button
}
}
I am building a costume button by extending from a Label.
I know that you can use CSS within .java files with:
setStyle("-fx-background-color: #101010");
which is pretty cool and I am using this quite often.
But there is my problem: It seems like this doesn't work for hover effects.
In an external CSS file you can have:
#LabelButton:hover {
-fx-background-color: #aaaaaa;
}
I would like to have this feature with "XXX:hover" inside my Java File because the hex color code must be variable and this isn't possible when using external CSS files. So what I kinda want to have it this:
setStyle("hover:-fx-background-color: #101010");
But I can't find the right syntax for it let alone there is a syntax.
If there is no such feature, how should I do it then?
Thanks!
There is no way to use selectors of any kind in inline CSS. The inline style is always applied to the node regardless of it's state (with the exception of you assigning the corresponding node property).
You could bind the style property to the hover property of the node.
myButton.styleProperty().bind(Bindings.when(myButton.hoverProperty())
.then("-fx-background-color: #101010")
.otherwise("-fx-background-color: #aaaaaa"));
This could become very ugly if you e.g. want to style focused buttons and pressed buttons differently. For this reason I recommend combining CSS and inline CSS to achieve the desired style:
You can define your own variables color variables in CSS:
stylesheet
.label-button { /* using style class for selector (ids are for single nodes) */
/* assign default values */
-fx-normal-background: yellow;
-fx-hovered-background: red;
-fx-background-color: -fx-normal-background;
}
.label-button:hover {
-fx-background-color: -fx-hovered-background;
}
java code
myButton.setStyle("-fx-normal-background: #101010; -fx-hovered-background: #aaaaaa;");
Note: Javafx newbie
Problem:
Many websites and tutorial show one how to set the style of a button using classes or ID's.
After setting the style from an Id, I need to restore the style to the previous state or simply the .button class.
Some Styles:
I have the following css (extract) used for all my buttons:
.button {
-fx-text-fill: white;
-fx-font-family: "Arial Narrow";
-fx-font-weight: bold;
-fx-background-color: linear-gradient(#61a2b1, #2A5058);
-fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 5, 0.0 , 0 , 1 );
}
and an Id for a button that is selected:
#button-selected {
-fx-background-color: linear-gradient(#3f6770, #82c0ce);
}
The code (extract):
//load stylesheet from resources into scene someScene.getStylesheets().add(Main.class.getResource("/gui.css").toExternalForm());
//...
Button b = new Button("some button");
//...
b.getStyleClass().add("button"); <----- adds .button class style to button
some trigger later on calls:
(activeButton, bSelectedButton) -> {
//...
if (!activeButton.equals(bSelectedButton)){
//restore activeButton to ".button" class
bSelectedButton.setId("button-selected");
}
//...
}
As a short summary above: (to put question into a practical application)
A trigger occurs, e.g. mouse click event, calling the lambda.
This checks if the buttons are the "same buttons", if not then:
clear the previous button's formatting activeButton,
and set the new button's bSelectedButton style with the #button-selected id.
Please note:
I have tried:
.button:pressed {
-fx-background-color: linear-gradient(#3f6770, #82c0ce);
}
but it does not change the colours as expected after the click (on the button)
Question:
How do I "unsetId" / "removeId" to restore the previous style of the button,
or simply how do I set the active style on the button from a loaded style sheet?
Use a toggle button rather than a standard button
You seem to be re-inventing the wheel. A selectable button is a ToggleButton, you should probably be using that. A toggle button has a selected psuedo-state that is used to configure the styling when the button is selected.
Aside comment on -fx-background-color usage
As an aside it is usually not best to directly set -fx-background-color for controls, but instead to set one of the higher level looked up colors, such as -fx-base. See modena.css for the definitions of these looked up colors and examples of how to use them (as well as the pseudo-state selectors).
Aside comment on -fx-effect usage
Setting a drop shadow effect on things can often lead to blurred text. For this reasons (and others), the standard way to simulate a shadow 3D effect for JavaFX controls is layered backgrounds, which is a bit complicated, but documented somewhat sparsely in the JavaFX CSS reference and abundant samples are in the modena.css file.
Advice on css id usage
The css id of an element should not change. It is used to identify the element, and should be unique in a given document. So you should not set and unset the id to something like button-selected. Instead you should use classes or pseudo-classes for maintaining keys to dynamic styling information.
You could effectively "unset" a CSS id by setting it to null, but I wouldn't advise that.
Related toggle button styling
Related answer mentions styling for ToggleButtons (but slightly different from the kind of styling you are asking for):
JavaFX - create custom button with image
Style by custom psuedo-class
If you really need to create your own psuedo-class, then see:
Example of using new Pseudoclass API in JavaFX 8 by james-d.
GuiGarage post on psuedo-classes
Style by style class setting
If you don't need or want to use pseudo-classes, then you can set different style classes on your control and use "and" style selectors:
styleclass.anotherstyleclass {
\\ your style attributes
}
For instance:
.button.selected {
-fx-base: palegreen;
}
With this method you would need to add and remove the additional style classes from the node's style class list as needed.
Generic selectable node styling
If you want a very generic selectable node style which is not tied to a button type, then see the solution here:
https://stackoverflow.com/a/40939611/1155209
In order to switch style by css file, you can use these commands:
scene.getStylesheets().clear();
setUserAgentStylesheet(null);
scene.getStylesheets().add(getClass().getResource("theme1.css").toExternalForm());
For your purpose, restoring previous style, I think you cannot do directly, but you can do as follows:
1) Use variable to store previousStyle.
2) When you switch to new style, you have to set value previousStyle is current style.
So, if you want to restore to previous style, you just call the previousStyle.
My solution does obey all css rules.
According to w3schools :
one should use an the id selector (denoted by #your_id_name) when referring to a specific/unique object.
The id of an element should be unique within a page, so the id selector is used to select one unique element!
NOTE: This rule is not adhered to in my solution
Solution:
CSS contains:
#button-default {
-fx-text-fill: white;
-fx-font-family: "Arial Narrow";
-fx-font-weight: bold;
-fx-background-color: linear-gradient(#61a2b1, #2A5058);
-fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 5, 0.0 , 0 , 1 );
}
#button-default:hover {
-fx-background-color: linear-gradient(#82c0ce, #3f6770);
}
#button-selected {
-fx-background-color: linear-gradient(#3f6770, #82c0ce);
}
Code:
When creating my buttons, I set the id there:
Button b = new Button();
//....
b.setId("button-default");
and some trigger event:
//....
(activeButton, newSelectedButton) -> {
if (!activeButton.equals(newSelectedButton)){
activeButton.setId("button-default");
newSelectedButton.setId("button-selected");
}
}
//....
A short summary:
The button is created with a specific id from the css file.
When some event gets triggered requiring the style change:
The button to be reset to the default style with an id referred to as button-default
Followed by setting the new buttons style with style referred to as button-selected
Note again: Not recommended since it does not adhere to standard practices, but I posted it here for completeness sake.
I'm looking for a way to dynamically change the style of a GWT CellTable at runtime. I want to make the table look "disabled" by graying the color scheme, to match up with other input fields that are disabled. Right now, I can prevent people from using the table, but they don't get any visual hint.
I have a resource bundle to set the style of the table, like described here and here:
public interface DataTableStyle extends CellTable.Resources {
#Override
#Source({ CellTable.Style.DEFAULT_CSS, "DataTable.css" })
CellTable.Style cellTableStyle();
}
That's passed into the constructor, and has been working fine for a while now:
public DataTable(int pageSize) {
super(pageSize, getStyle());
}
protected static DataTableStyle getStyle() {
return GWT.create(DataTableStyle.class);
}
What I can't figure out is how to dynamically adjust the style of the table at runtime. I'm not sure whether it's not possible, or whether I'm just missing something.
I'm pretty sure that I can't change the style resources attached to the cell table once they're set. Since I can't do that, it seems like I should be able to use either addStyleDependentName() or addStyleName() in combination with additional CSS styles, but I can't figure out the right combination of changes.
To test, I tried to override my existing definition of .cellTableHeader. I know that I'm targeting the right style, because if I change background: #000000 to background: magenta in the original style, it works.
.cellTableHeader {
background: #000000;
color: #ffffff;
text-shadow: none;
}
One example I worked off of is here. That page suggests using CSS like this:
.cellTableHeader.cellTable-disabled {
background: magenta; /* just to make it obvious */
}
Then, in my code:
userTable.addStyleDependentName("disabled")
By itself, the .cellTableHeader.cellTable-disabled style results in a runtime error:
The following unobfuscated classes were present in a strict CssResource:
cellTable-disabled
Fix by adding String accessor method(s) to the CssResource interface for obfuscated classes, or using an #external declaration for unobfuscated classes.
The recommended workarounds are either to use #external on the style or annotate #NotStrict on the resource bundle. Both of those get me past the runtime error, but the style doesn't take effect. I've also tried various other things:
.cellTableHeader.disabled {
background: magenta; /* just to make it obvious */
}
or
.cellTableHeader .disabled {
background: magenta; /* just to make it obvious */
}
or
.cellTableHeader disabled {
background: magenta; /* just to make it obvious */
}
but at this point I'm really just grasping at straws.
There is no way to change the style resource directly at runtime.
I see two solutions:
Custom CellTableBuilder
With this solution the Style used by the CellTableBuilder is replaced at runtime, when the table is re-drawn the new style will be applied. This solution has an issue, the CellTable don't use the CellTableBuilder to set selection styles, therefore replacing style on the builder has no effect on the selection style.
Here a demo of the custom CellTableBuilder solution with the source code.
Style Proxy
A different solution is to proxy the Style used by the CellTable and the builder. At runtime you can change the effective Style used by the proxy. Because the DefaultCellTableBuilder stores the style values at construction time you need to create a custom one that don't cache it. I've found no issues, but I've not deeply tested it
Here a demo of the style proxy solution with the source code.