JavaFX .setStyle inline sub elements - css

In order to style the background for many elements in JavaFX, you need to use a css file, or to use .setStyle.
In my case I have to style the background of the dropdown from a ComboBox, but I have to use .setStyle not a css file (because I have some dynamic colors that will be used to style different GUI elements). The problem here is that if I use the following css code, the function .setStyle doesn't recognize it as if I were to use a css file.
.setStyle(".combo-box .list-cell{ -fx-background: blue;}");
The code would look like this:
comboBox.setStyle(".combo-box .list-cell{ -fx-background: #"+ Color1.toString().substring(2) + ";}");
Color1 beeing a Color object, that will get a dynamic value depending on the case.
The question is, can I use .list-cell inside the function .setStyle? If so, how? This would help me with other GUI elements were I'll have to use .setStyle.

It's possible to use a looked-up colors for this. You can assign those using setStyle and use them from a CSS stylesheet:
#Override
public void start(Stage primaryStage) {
ComboBox<String> comboBox = new ComboBox<>();
comboBox.getItems().addAll("A", "B", "C");
StackPane root = new StackPane(comboBox);
// set color
root.setStyle("cell-color: blue;");
Scene scene = new Scene(root, 400, 400);
scene.getStylesheets().add("style.css");
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}
style.css
/* default values */
.root {
cell-color: yellow;
}
/* use color */
.combo-box .list-cell {
-fx-background: cell-color;
}

For what I have, I like this solution better.
comboBox.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
public ListCell<String> call(ListView<String> param) {
return new ListCell<String>() {
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(item);
setBackground(new Background(new BackgroundFill(Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY)));
setTextFill(Color.BLUE);
}
};
}
});

Related

JavaFX Text-Area remove borders

I am using an JavaFX Alert with a text area on it.
The problem I have is that the text area does not use the full space of the Alert, as well as having white (borders).
My code:
TextArea area = new TextArea("");
area.setWrapText(true);
area.setEditable(false);
area.getStylesheets().add(getClass().getResource("/model/app.css").toExternalForm());
Alert alert = new Alert(AlertType.NONE);
alert.getDialogPane().setPrefWidth(750);
alert.getDialogPane().setPrefHeight(800);
alert.getDialogPane().setContent(area);
formatDialog(alert.getDialogPane());
alert.setTitle("Lizenz Info");
Window w = alert.getDialogPane().getScene().getWindow();
w.setOnCloseRequest(e -> {
alert.hide();
});
w.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.ESCAPE) {
w.hide();
}
}
});
alert.setResizable(true);
alert.showAndWait();
My corresponding css sheet:
.text-area .content {
-fx-background-color: #4c4c4c;
}
.text-area {
-fx-text-fill: #ff8800;
-fx-font-size: 15.0px;
}
.text-area .scroll-pane {
-fx-background-color: #4c4c4c;
}
.text-area .scroll-pane .viewport {
-fx-background-color: #4c4c4c;
}
.text-area .scroll-pane .content {
-fx-background-color: #4c4c4c;
}
.viewport and .content on .scrollpane did not have any effect whatsoever.
I want the white borders either to be gone, or have the same color as the background, also to use the full space of the dialog. Can someone help?
As #jewelsea suggested, I think Alert is not the right choice here. Your desired layout can be acheived by using Dialog (as in below code).
Dialog<String> dialog = new Dialog<>();
dialog.setTitle("Lizenz Info");
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK);
dialog.getDialogPane().setContent(area);
dialog.setResizable(true);
dialog.showAndWait();
Having said that, you can fix the existing issues as below:
Remove white space around text area: You can remove the white space by setting the padding of TextArea to 0. Include the below code in the css file.
.text-area{
-fx-padding:0px;
}
Changing the white space background : The .text-area and .content styleclasses are on same node. So instead of declaring with space between them
.text-area .content {
-fx-background-color: #4c4c4c;
}
you have to declare without the space between the styleclasses (in below code)
.text-area.content {
-fx-background-color: #4c4c4c;
}
Here is a similar example to Sai's but uses a standard stage.
It uses a UTILITY style, but you could use a different style if you prefer.
Basically, if you don't want the additional styling and functionality of the alerts and dialogs (and you don't seem to with at least the example you have given), then you can just use a standard stage to display your content rather than the dialog classes provided in the javafx.control package.
The alert.css file referenced in the example is the CSS from your question.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.*;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class TextAreaUtility extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
Button showAlert = new Button("Show Alert");
showAlert.setOnAction(this::showAlert);
stage.setScene(new Scene(showAlert));
stage.show();
}
private void showAlert(ActionEvent e) {
TextArea textArea = new TextArea("");
textArea.setWrapText(true);
textArea.setEditable(false);
Scene scene = new Scene(textArea, 750, 800);
scene.getStylesheets().add(
TextAreaUtility.class.getResource(
"alert.css"
).toExternalForm()
);
Stage utility = new Stage(StageStyle.UTILITY);
utility.initOwner(((Button) e.getSource()).getScene().getWindow());
utility.initModality(Modality.APPLICATION_MODAL);
utility.setTitle("Alert Title");
utility.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode() == KeyCode.ESCAPE) {
utility.hide();
}
});
utility.setResizable(true);
utility.setScene(scene);
utility.showAndWait();
}
}
Debugging nodes and styles info
If you want to see the nodes and style names in your scene graph and you aren't using a tool like ScenicView, a quick debug function is:
private void logChildren(Node n, int lvl) {
for (int i = 0; i < lvl; i++) {
System.out.print(" ");
}
System.out.println(n + ", " + n.getLayoutBounds());
if (n instanceof Parent) {
for (Node c: ((Parent) n).getChildrenUnmodifiable()) {
logChildren(c, lvl+1);
}
}
}
Which you can attach to run when the window is displayed:
w.setOnShown(se -> logChildren(alert.getDialogPane().getScene().getRoot(), 0));
When you run this on a standard dialog you will see quite a few nodes in the scene graph with attached styles that you can find defined in the modena.css file within the JavaFX SDK. You will also see that some of the bounding boxes for the layout that are not related to your text area have width and height.
Those dialog styles by default have padding attached to them, which is why you are seeing padding around your TextArea. The padding is not in the text area but the content regions containing it within the dialog. To get rid of it, you need to set the padding in your custom CSS to override the default. I don't have the CSS for that, it is difficult to create sometimes and overriding default padding is probably best avoided when possible.

Mnemonics - how to set color?

I have multiple buttons in in my javafx appliaction with mnemonics.
When I press "Alt" the mnemonics appear in a dark color but I want them to be white.
What is the right css selector for this?
I tried:
.mnemonic-underline: {
-fx-stroke: white;
}
But after that the underlines are visible all the time.
This should work:
:show-mnemonics > .mnemonic-underline {
-fx-stroke: white;
}
Example program:
public class MnemonicStylingSSCCE extends Application {
#Override
public void start(Stage stage) {
// Init label
final Label mnemonic = new Label("_Mnemonic");
mnemonic.setMnemonicParsing(true);
// Init scene
final Scene scene = new Scene(mnemonic);
scene.getStylesheets().add(MnemonicStylingSSCCE.class.getResource("mnemonic.css").toExternalForm());
stage.setScene(scene);
// Request focus & show
stage.requestFocus();
stage.show();
}
}
Side note - the content of mnemonic.css is CSS shown above (but with the red color instead of white).

JavaFX 8 - How to change the color of the prompt text of a NOT editable combobox via CSS?

The title says everything. I want to change the color of the prompt text of a not editable combobox, so that the text has the same color like the prompt text of a editable combobox.
In my CSS-file I tried to use -fx-prompt-text-fill in .combo-box, .combo-box-base, .combo-box-base .text-field and .combo-box-base .text-input, but nothing worked.
What styleclass do I have to use?
When the ComboBox is not editable, there is no TextField, and the property -fx-prompt-text-fill is no longer valid, since the control displayed instead, a ListCell, doesn't extend TextInputControl.
In order to set the style of this cell, we can provide our custom styled ListCell:
#Override
public void start(Stage primaryStage) {
ComboBox comboBox = new ComboBox();
comboBox.getItems().addAll("Item 1", "Item 2", "Item 3");
comboBox.setPromptText("Click to select");
comboBox.setEditable(false);
comboBox.setButtonCell(new ListCell(){
#Override
protected void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if(empty || item==null){
// styled like -fx-prompt-text-fill:
setStyle("-fx-text-fill: derive(-fx-control-inner-background,-30%)");
} else {
setStyle("-fx-text-fill: -fx-text-inner-color");
setText(item.toString());
}
}
});
Scene scene = new Scene(new StackPane(comboBox), 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
Hi I do beleive that I m providing a better solution
First
in your CSS file create the following
.input .text-field {
-fx-prompt-text-fill: #a0a0a0; // or any color you want
}
than in the scene builder set your combobox class to input after attaching the CSS file
That works like a sharm for me

JavaFX8 tree tabel view customize separate cells

In a tree-table-view there are child items that have in turn other child items. I need to customize, say, the text of certain cells of those pseudo-root items.
Is there a way to assign a css class/style to those items?
Update:
Ok, got it working with the following cellFactory:
treeTblColumnName.setCellFactory(new Callback<TreeTableColumn<FileModel, String>, TreeTableCell<FileModel, String>>() {
#Override
public TreeTableCell<FileModel, String> call(TreeTableColumn<FileModel, String> param) {
TreeTableCell<FileModel, String> cell = new TreeTableCell<FileModel, String>() {
#Override
protected void updateItem(String t, boolean bln) {
super.updateItem(t, bln); //To change body of generated methods, choose Tools | Templates.
System.out.println(this.getTableColumn().);
Label lbl = new Label(t);
lbl.setStyle("-fx-font-weight: bold; -fx-font-size: 14pt; -fx-text-fill: white;");
setGraphic(lbl);
}
};
return cell;
}
});
Now, how can I distinguish between classes? FileModel is an interface which is implemented by several classes. In this cellFactory I need to know what type is the current cell->item in order to apply different styling on it.
Thanks.
You can use instanceof:
FileModel fileModel = getTreeTableRow().getItem();
if(fileModel instanceof ExeFileModel){
//set style here
} else if(fileModel instanceof TxtFileModel){
//use another style here
}

Javafx ListView selection bar text color when using CellFactory

Is there any way to change the selection bar text color in a list view?
Preferably using CSS. In a TableView, you can use:
-fx-selection-bar-text: white;
But this does not work for a ListView.
UPDATE: The above case happens when using CellFactories to render the cells.
lvRooms.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
#Override public ListCell<String> call(ListView<String> list) {
return new RoomCell();
}
});
In the Cell Factory class, I'd gladly cover the case when the row is selected.
But: It is called just once at the beginning, not every time the selection bar is moved, and therefore the isSelected() method always renders false.
UPDATE 2: This is the RoomCell implementation:
class RoomCell extends ListCell<String> {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
Log.debug("RoomCell called, item: "+item);
final Label lbl = new Label(item); // The room name will be displayed here
lbl.setFont(Font.font("Segoe UI", FontWeight.BOLD, 18));
lbl.setStyle("-fx-text-fill: black");
//lbl.setTextFill(isSelected()?Color.WHITE: Color.BLACK);
if (isSelected()) // This is always false :(
lbl.setStyle("-fx-text-fill: yellow");
if (Rooms.getBoolean(item, "OwnerStatus")) {
lbl.setEffect(new DropShadow(15, Color.BLUEVIOLET));
lbl.setGraphic(new ImageView(
new Image(getClass().getResourceAsStream("images/universal.png"))));
} else {
lbl.setGraphic(new ImageView(
new Image(getClass().getResourceAsStream("images/yin-yang.png"))));
lbl.setEffect(new DropShadow(15, Color.WHITE));
}
setGraphic(lbl);
}
}
}
-fx-selection-bar-text is a color palette (not css property) defined in a root default CSS selector, which is selector of the Scene. I don't know how are you using it but if you define it (globally since it is scene's selector) like:
.root{
-fx-selection-bar-text: red;
}
in your CSS file then all controls' css properties using -fx-selection-bar-text will be red. ListView will be affected as well (see commented out original usages below).
However if you want to customize the ListView's style only, override the default properties this way
(Note: only -fx-text-fill are overriden. Original values are commented out, where -fx-selection-bar-text is used):
/* When the list-cell is selected and focused */
.list-view:focused .list-cell:filled:focused:selected {
-fx-background-color: -fx-focus-color, -fx-cell-focus-inner-border, -fx-selection-bar;
-fx-background-insets: 0, 1, 2;
-fx-background: -fx-accent;
/* -fx-text-fill: -fx-selection-bar-text; */
-fx-text-fill: red;
}
/* When the list-cell is selected and selected-hovered but not focused.
Applied when the multiple items are selected but not focused */
.list-view:focused .list-cell:filled:selected, .list-view:focused .list-cell:filled:selected:hover {
-fx-background: -fx-accent;
-fx-background-color: -fx-selection-bar;
/* -fx-text-fill: -fx-selection-bar-text; */
-fx-text-fill: green;
}
/* When the list-cell is selected, focused and mouse hovered */
.list-view:focused .list-cell:filled:focused:selected:hover {
-fx-background: -fx-accent;
-fx-background-color: -fx-focus-color, -fx-cell-focus-inner-border, -fx-selection-bar;
-fx-background-insets: 0, 1, 2;
/* -fx-text-fill: -fx-selection-bar-text; */
-fx-text-fill: yellow;
}
These CSS properties and more are avaliable in built-in caspian.css.
UPDATE: I strongly advice you to read the Cell API. From there
... We represent extremely large data sets using only very few Cells.
Each Cell is "recycled", or reused.
Be warned about the different String items may use the same cell, ending with misleading visual effects/renderings, like isSelected() in your code. Additionally in API it says
Because by far the most common use case for cells is to show text to a
user, this use case is specially optimized for within Cell. This is
done by Cell extending from Labeled. This means that subclasses of
Cell need only set the text property, rather than create a separate
Label and set that within the Cell.
So I refactored your code as follows.
class RoomCell extends ListCell<String> {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
Log.debug("RoomCell called, item: "+item);
setFont(Font.font("Segoe UI", FontWeight.BOLD, 18));
ImageView iView = new ImageView();
if (Rooms.getBoolean(item, "OwnerStatus")) {
iView.setEffect(new DropShadow(15, Color.BLUEVIOLET));
iView.setImage(new Image(getClass().getResourceAsStream("images/universal.png")));
} else {
iView.setEffect(new DropShadow(15, Color.WHITE));
iView.setImage(new Image(getClass().getResourceAsStream("images/yin-yang.png")));
}
setGraphic(iView); // The image will be displayed here
setText(item); // The room name will be displayed here
}
}
}
All -fx-text-fill styles of the cell's text will change according to definitions in CSS file.
Now here is a trade-off between cell's text dropshadow effect and its fill colors from CSS file:
-- if you want to use dropshadow effect, you should go like current way, namely creating label, setting its text, give dorpshadow effect to the label and setGraphic(label). However this time you will not prefer to set the text (setText(item)) of the cell thus text color styles in CSS file will have no effect.
-- On other hand, if you prefer the code that I have refactored, then you should to disable -fx-background-color of the cell (which extends Labeled) by setting it to transparent or null and set the -fx-effect to dropshadow in CSS file to be able to apply dropshadow effect to the text directly. Clearing the background of the cell is not the preferred way either IMO. An explanation by the code:
Label lbl = new Label("This text will have a dropshadow on itself directly");
lbl.setEffect(new DropShadow(15, Color.BLUE));
Label another_lbl = new Label("This text will have a dropshadow applied on the background bounds, not to text");
another_lbl.setEffect(new DropShadow(15, Color.BLUE));
another_lbl.setStyle("-fx-background-color:gray");
Test them to see the difference. That's all.

Resources