Styling JavaFX Popover - javafx

I need to style a Popover from ControlsFX, but am failing to do so.
I have my own xxx.css stylesheet that I add to a scene, and I've (obviously) successfully styling many JavaFX Controls...
I have set this in the stylesheet (copied and modified from popover.css in ControlsFX):
.popover > .border {
-fx-stroke: linear-gradient(to bottom, rgba(0,0,0, .3), rgba(0, 0, 0, .7));
-fx-stroke-width: 0.5;
-fx-fill: rgba(30 , 30, 30, .95);
-fx-effect: dropshadow(gaussian, rgba(0,0,0,.2), 10.0, 0.5, 2.0, 2.0);
}
But the Popover never gets the border style. How do I get the Popover to pick the style up?

Since the PopOver is displayed in a different window, you can't set your style on the primary scene, but on the PopOvercontrol.
If you look at how the style is applied to the control in its skin class PopOverSkin:
stackPane = new StackPane();
stackPane.getStylesheets().add(
PopOver.class.getResource("popover.css").toExternalForm());
stackPane.getStyleClass().add("popover");
where this stackPane can be accessed with:
#Override
public Node getNode() {
return stackPane;
}
you just need to add your style sheets to that stack pane, right after you have access to the skin, that is, when the popOver is shown:
popOver.show(...);
((Parent)popOver.getSkin().getNode()).getStylesheets()
.add(getClass().getResource("MyPopOver.css").toExternalForm());

Related

How to remove border of ListView in java fx without using css styles

ListView listView = new ListView<>();
//something like
listview.removeBorder or listview.setborder(Empty border)??
Well, it depends on the theme you are using in your application.
In Modena (default JavaFx 8+ theme), ListView borders and background are implemented as a background layers, and each layer is just a plain color fill:
.list-view {
-fx-background-color: -fx-box-border, -fx-control-inner-background; //this line
-fx-background-insets: 0, 1;
-fx-padding: 1;
}
So, to remove borders you need to remove the first color fill (-fx-box-border) and keep the second one (-fx-control-inner-background, which is color constant with a value #F4F4F4 and represents ListView background color):
listView.setBackground(
new Background(new BackgroundFill(Color.valueOf("F4F4F4"), null, null))
);
and you'll probably want to remove that 1px padding that was used for borders:
listView.setPadding(new Insets(0));

JavaFX - Set different hover colors on toggle button based on toggle state

I have a toggle button in my program that starts/stops a script. I would like for this button to be green and say "START" when the button is not selected, and red and say "STOP" when it is selected. More importantly, I would like the unselected hover color to be a slightly darker version of the original green, and the selected hover color to be a slightly darker version of the red color. My current CSS for this button looks like this:
#startStopButton {
-fx-border-color:#d4d4d4;
-fx-background-color:#85eca5;
-fx-background-image: url("startButton.png");
-fx-background-size: 50px;
-fx-background-repeat: no-repeat;
-fx-background-position: 80% 50%;
-fx-alignment: CENTER_LEFT;
-fx-effect: dropshadow(three-pass-box, #e7e7e7, 15, 0, 0, 0);
}
#startStopButton:hover {
-fx-background-color:#80dc9c;
}
#startStopButton:selected{
-fx-background-color: #ff6060;
-fx-text:"STOP";
}
#startStopButton:selected:focused{
-fx-background-color: #ff6060;
-fx-text:"STOP";
}
Currently, this will work fine, except for when the button turns red. In this case, there is no hover effect. Within my FXML controller, there is a function that is activated every time this button is clicked:
private void startStopClick()
{
if(startStopButton.isSelected())
{
startStopButton.setText(" STOP");
// startStopButton.setStyle()
}
else {
startStopButton.setText(" START");
}
}
Is there any way to 1) set the button text within CSS so that I can leave that out of my controller?
2) Get the current toggle button state in CSS, so that I can have multiple hover effects. For example, something like this:
#startStopButton:unselected{
-fx-background-color: #ff6060;
-fx-text:"STOP";
}
If there is no way to do this in CSS, can I set the hover styles in the Java code in the FXML controller?
CSS properties are only available for the look of nodes. With a few exceptions the basic JavaFX nodes don't allow you to specify content via CSS. The text property of buttons is no exception; it cannot be set using CSS.
As for the colors: The rules occuring last override values assigned by rules with the same precedence occuring before them. This means the background color assigned by the rules for #startStopButton:selected and #startStopButton:selected:focused always override the color #startStopButton:hover assigns.
Since in both cases you want a darker color when hovering, the derive function and a lookedup color may work for you.
Example
#Override
public void start(Stage primaryStage) {
ToggleButton btn = new ToggleButton();
btn.getStyleClass().add("start-stop");
btn.textProperty().bind(Bindings.when(btn.selectedProperty()).then(" STOP").otherwise(" START"));
Pane p = new Pane(btn);
Scene scene = new Scene(p);
scene.getStylesheets().add("style.css");
primaryStage.setScene(scene);
primaryStage.show();
}
style.css
.start-stop.toggle-button {
base-color: #85eca5;
-fx-background-color: base-color;
}
.start-stop.toggle-button:selected {
base-color: #ff6060;
}
.start-stop.toggle-button:hover {
-fx-background-color: derive(base-color, -20%);
}
If you cannot use derive since you need to specify different colors for all 4 states you could still rely on looked-up colors to avoid relying on the rule ordering:
.start-stop.toggle-button {
unselected-color: blue;
selected-color: yellow;
-fx-background-color: unselected-color;
}
.start-stop.toggle-button:hover {
unselected-color: red;
selected-color: green;
}
.start-stop.toggle-button:selected {
-fx-background-color: selected-color;
}

Set TextArea background color from Color Picker [duplicate]

I am trying to change the background color of my TextField "colorBox0" to "value0" but it gets rid of the border.
Here is a simplified version of my code:
static Paint value0 = Paint.valueOf("FFFFFF");
TextField colorBox0;
colorBox0.setBackground(new Background(new BackgroundFill(value0, CornerRadii.EMPTY, Insets.EMPTY)));
Any help is very much appreciated
Thank you
I found that you can construct a string of css code out of a string and a variable by using the to string method and the substring method like this:
colorBox0
.setStyle("-fx-control-inner-background: #"+value0.toString().substring(2));
Looking at the (shortened) default JavaFX styles for the TextField explains a lot:
.text-input {
-fx-background-color: linear-gradient(to bottom, derive(-fx-text-box-border, -10%), -fx-text-box-border),
linear-gradient(from 0px 0px to 0px 5px, derive(-fx-control-inner-background, -9%), -fx-control-inner-background);
-fx-background-insets: 0, 1;
-fx-background-radius: 3, 2;
}
So the background is a layered background including the border. This technique is used a lot throughout JavaFX. But it is very easy to modify just one color.
First we need to assign a new custom style class to our TextField:
TextField textField = new TextField();
textField.getStyleClass().add("custom");
and the CSS file:
.custom {
-fx-control-inner-background: orange;
}
As you can see, you do not have to override all styles of the textfield, it is sufficient to only override the color variable used for the background.
Try to set the color using CSS:
TextField colorBox0;
colorBox0.setStyle("-fx-background-color: white;");
Elegant solution with colour translation:
static Paint black = Paint.valueOf(Integer.toHexString(Color.BLACK.hashCode()));
TextField textfield;
textField.setStyle(
"-fx-control-inner-background: #"+black.toString().substring(2));

JavaFX Panes: Making a 1-pixel Border

I am struggling and will no doubt have to buy a manual to understand JavaFX CSS, or the JavaFX CSS Reference Guide...
But what I want to do is make a 1 pixel border around some of my nodes, such as a TableView or ScrollPane on one side, and a GridPane or ScrollPane on the other side of a Scene I'm working on. I say "or", because I'll take either one. Ha ha!
(And regardless of whether it's filled up with controls or not)
Cheers.
Here's a test sample for demoing some ways to make borders in CSS:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class TableViewBorderTest extends Application {
#Override
public void start(Stage primaryStage) {
HBox root = new HBox(5);
TableView<String> table = new TableView<>();
table.getColumns().add(new TableColumn<String, String>("Data"));
ScrollPane scroller = new ScrollPane();
scroller.setMinWidth(200);
GridPane grid = new GridPane();
grid.setMinWidth(200);
grid.getStyleClass().add("grid");
root.getChildren().addAll(table, scroller, grid);
// padding so we can easily see borders:
root.setPadding(new Insets(10));
Scene scene = new Scene(root);
scene.getStylesheets().add("border-table.css");
primaryStage.setScene(scene);
primaryStage.show();
// remove focus from tables
root.requestFocus();
}
public static void main(String[] args) {
launch(args);
}
}
You can run this with just an empty border-table.css file. The first thing to notice is that the table view and scroll pane already have a 1-pixel border in a medium gray (slightly darker than the default background):
This border is defined (see how later) in the default stylesheet, modena.css, and is set to a "looked-up color" called -fx-box-border. Just for demo purposes, to make it easier to see the border, you can reassign this color with the following in border-table.css:
.root {
-fx-box-border: red ;
}
This gives
Notice that the table header and column headers use the same color as a border. If you compare to the first image, you can probably see the borders more clearly in it too.
To replace the border in the table view and scroll pane, you can define borders in the css file. The simplest, but not necessarily the best, way is to define a -fx-border-color. Replace the border-table.css with the following:
.table-view, .scroll-pane {
-fx-border-color: green ;
}
The default value of -fx-border-width is 1, so this gives a one-pixel green border:
For the GridPane, note that it has no default border and also has no style class (see CSS docs). In the Java code, I defined a style class for it:
grid.getStyleClass().add("grid");
so we can add the same border just by adding this style class to the selector:
.table-view, .scroll-pane, .grid {
-fx-border-color: green ;
}
It's interesting to note that the default stylesheet, modena.css doesn't use -fx-border-... properties at all. Instead, it creates borders by creating two (or more) "nested backgrounds". For example, it has:
.scroll-pane,
.split-pane,
.list-view,
.tree-view,
.table-view,
.tree-table-view,
.html-editor {
-fx-background-color: -fx-box-border, -fx-control-inner-background;
-fx-background-insets: 0, 1;
-fx-padding: 1;
}
This defines, for TableView, ScrollPane, and other similar controls, two background colors. The first (so painted first, i.e. underneath) is a solid background fill in the looked-up color -fx-box-border, and the second (painted on top) is a solid background fill in the looked-up color -fx-control-inner-background. The first background fill has 0 insets, and the second has a 1-pixel inset, meaning that the bottom background fill will be visible for 1 pixel width around the edge of the control. (The padding ensures nothing is placed over this effective 1-pixel border.)
I haven't tested this at all, but it's claimed that the nested background approach is more efficient than drawing borders (I guess the native graphics is vey fast at rectangular background fills).
So you could use the same approach and replace border-table.css with
.table-view, .scroll-pane {
-fx-background-color: blue, -fx-control-inner-background ;
-fx-background-insets: 0, 1 ;
}
.grid {
-fx-background-color: blue, -fx-background ;
-fx-background-insets: 0, 1 ;
-fx-padding : 1 ;
}
And you could even introduce a looked-up color to make it easier to modify the style of the app:
.root {
-my-border: blue ;
}
.table-view, .scroll-pane {
-fx-background-color: -my-border, -fx-control-inner-background ;
-fx-background-insets: 0, 1 ;
}
.grid {
-fx-background-color: -my-border, -fx-background ;
-fx-background-insets: 0, 1 ;
-fx-padding : 1 ;
}
(this has exactly the same effect as the previous, but there is just one place to change the color definition instead of two).
Note these last two versions override the default focus border, which is implemented in the default style sheet by defining a different set of background colors when the controls are focused. You can restore these with:
.root {
-my-border: blue ;
}
.table-view, .scroll-pane {
-fx-background-color: -my-border, -fx-control-inner-background ;
-fx-background-insets: 0, 1 ;
}
.table-view:focused, .scroll-pane:focused {
-fx-background-color: -fx-faint-focus-color, -fx-focus-color, -fx-control-inner-background;
-fx-background-insets: -1.4, -0.3, 1;
-fx-background-radius: 2, 0, 0;
}
.grid {
-fx-background-color: -my-border, -fx-background ;
-fx-background-insets: 0, 1 ;
-fx-padding : 1 ;
}
which references two more looked-up colors, -fx-faint-focus-color and -fx-focus-color (the first is just a partially-transparent version of the second); of course you could redefine these for your own focus colors if you chose.

Is it possible to "tint" a button in JavaFX 2

I have a JavaFX 2 application, where all my buttons use the default style (grey gradient). In some special areas of the application, the background color is red, yellow or green. In these areas, I also have buttons.
Instead of re-styling all the different states (normal, hover, pressed) of the button in all three colors, I'd like to just give the button the tint of the background. Is this possible, and how?
If not, is there a way to easily re-style the base button style, and have the hover and pressed states (pseudo-selectors) automatically derived from this style?
If that's not possible, I'm open for suggestions.. My most important goal is to avoid redundant/duplicate declarations (especially of gradients), in case someone wants to add a different color panel later, or just change the shade of one of the background colors.
CSS for the red panel/button:
#my-red-panel {
-fx-border-width: 1;
-fx-border-radius: 5;
-fx-background-radius: 5;
-fx-smooth: true;
-fx-border-color: rgb(209, 65, 42);
-fx-background-color: rgba(255, 78, 50, 0.89);
}
#my-red-panel .button {
-fx-background: rgba(0, 0, 0, 0); /* Now borders look good, but button is still grey*/
}
My best bet so far, is to use a semi-transparent gradient, like so:
#my-red-panel .button {
-fx-background-color: linear-gradient(rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0.2));
}
I still have to declare each state, but at least I can change the underlying colors without having to modify each state. The main problem is that this overrides the entire look of the button, so I was hoping for something better... :-/
Not tested, but try experimenting with:
#my-red-panel {
-fx-base: rgba(255, 78, 50, 0.89);
}
or perhaps:
#my-red-panel .button {
-fx-base: ... ;
}
depending on the exact effects you want.
The trick here is that the default css (caspian.css for JavaFX2.2 or modena.css for JavaFX8) use some pre-defined lookup colors. You can dig out the source for these to see how they are used. If you redefine these lookups for a node in the scene graph, the new definition is propagated to all child nodes.

Resources