Change JavaFX MenuButton Icon - javafx

Is there a simple way to change a JavaFX MenuButton arrow to a character or hide it completely?
MenuButton hamburgerMenu = new MenuButton("\u2630");
hamburgerMenu.getItems().addAll(new MenuItem("Ham"), new MenuItem("Buger"));

Add the following style to hide the arrow
.menu-button > .arrow-button > .arrow {
-fx-background-color: transparent;
}
Result
You can also define a different SHAPE using -fx-shape followed by a SVG path.
.menu-button > .arrow-button > .arrow {
-fx-shape: "M 0 -3.5 v 7 l 4 -3.5 z";
}
The output is

There are several ways to do this, here are four. The code is Jython with JavaFX. You can edit this code to meet your needs.
First, the enum, for context.
public enum URLBarArrowConstants {
//URLBarArrow Constants
BYCSS_AND_SHAPE,
BYCSS_AND_NO_SHAPE,
NOCSS_AND_SHAPE,
NOCSS_AND_NO_SHAPE;
}
Second, the css files, for context.
EG #1
/*ComboBox's Arrow is a Region.*/
.menu-button .arrow-button .arrow {
-fx-shape: "...";
-fx-scale-shape: true;
-fx-position-shape: true;
}
EG#2
/*ComboBox's Arrow is a Region.*/
.menu-button .arrow-button .arrow {
/*Setting either of these two will do.*/
-fx-background-color: transparent;
-fx-opacity: 0.0;
}
/*ComboBox's Arrow Button is a Stack Pane.*/
.menu-button .arrow-button{
-fx-background-position: center;
-fx-background-repeat: no-repeat;
-fx-background-image: url("..<file>.png");
}
The method, in my main file.
def setCustomURLBarArrow(self, url_bar, scene, URLBarArrowConstant):
from javafx.scene.paint import Paint
from javafx.scene.shape import Shape, SVGPath, FillRule
Don't configure the ComboBox Arrow by CSS, instead, do it programmatically and change the Regions SVG Shape
if URLBarArrowConstant == URLBarArrowConstants.NOCSS_AND_SHAPE:
#SVG Object
previous_url_bar = SVGPath()
#SVG Path
previous_url_bar.setContent("...") # edit this
#SVG Fill Rule
previous_url_bar.setFillRule(FillRule.NON_ZERO)
#Set Fill --
previous_url_bar.setFill(Paint.valueOf(Color.web("...").toString())) //edit here
#Apply CSS Sheet
url_bar.applyCss()
#Set Region's Shape
arrow_region = url_bar.lookup(".arrow").setShape(previous_url_bar)
Configure the ComboBox Arrow by CSS and change the Regions SVG Shape
elif URLBarArrowConstant == URLBarArrowConstants.BYCSS_AND_SHAPE:
#Apply Stylesheet for URL Bar
scene.getStylesheets().add(File("..<file>.css").toURI().toString()) //edit here
Configure the ComboBox Arrow by CSS but instead, merely hide the arrow by setting the transparency/opacity values and set a background.
elif URLBarArrowConstant == URLBarArrowConstants.BYCSS_AND_NO_SHAPE:
#Apply Stylesheet for URL Bar
scene.getStylesheets().add(File("..<file>.css").toURI().toString()) //edit here
Don't configure the ComboBox Arrow by CSS, instead, do it programmatically and merely hide the arrow by setting the transparency/opacity values and set a background.
elif URLBarArrowConstant == URLBarArrowConstants.NOCSS_AND_NO_SHAPE:
from javafx.scene.paint import Paint
from javafx.scene.layout import CornerRadii
from javafx.scene.layout import Background, BackgroundSize, BackgroundImage, BackgroundPosition, BackgroundRepeat, BackgroundFill
#Apply CSS Sheet
url_bar.applyCss()
#Grab Arrow(Region), ArrowButton(StackPane) ComboBox properties
arrow_region = url_bar.lookup(".arrow")
arrow_button = url_bar.lookup(".arrow-button")
#Either Set Opacity to 0 or set background color to transparent.
arrow_region.setOpacity(0.0)
arrow_region.setBackground( Background( array(BackgroundFill, [BackgroundFill( Paint.valueOf(Color.TRANSPARENT.toString()), CornerRadii.EMPTY, Insets.EMPTY)]) ) )
#Set a Background Image for the .arrow-button StackPane.
arrow_button.setBackground(Background( array(BackgroundImage, [BackgroundImage( Image( String(File('..<file>.png').toURI().toString()), True) , BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, BackgroundSize.DEFAULT)] ) ) ) //if you want, edit this

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;
}

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.

Remove arrow on JavaFX menuButton

Hi JavaFX Stylesheet expert,
How do I remove the default arrow on JavaFX menuButton.
I have figured how to change the color and make in unvisible with
.menu-button {
-fx-mark-color: transparent;
}
or
.menu-button .arrow {
-fx-background-color: transparent;
}
but, I don't want the gap because of the unvisible arrow.
Thanks for your advice.
Best Regards,
Ivan
If we look into the source code of MenuButtonSkinBase, the sub structure of MenuButton seems to be
MenuButton
|——— label (LabeledImpl)
|——— arrowButton (StackPane)
|——— arrow (StackPane)
So to hide the "arrow" it is enough to set padding to 0 for both StackPanes:
.menu-button > .arrow-button {
-fx-padding: 0;
}
.menu-button > .arrow-button > .arrow {
-fx-padding: 0;
}
There are several ways to do this, here are four. The code is Jython with JavaFX. You can edit it for your needs.
First, the enum, for context.
public enum URLBarArrowConstants {
//URLBarArrow Constants
BYCSS_AND_SHAPE,
BYCSS_AND_NO_SHAPE,
NOCSS_AND_SHAPE,
NOCSS_AND_NO_SHAPE;
}
Second, the css files, for context.
EG #1
/*ComboBox's Arrow is a Region.*/
.combo-box .arrow-button .arrow {
-fx-shape: "...";
-fx-scale-shape: true;
-fx-position-shape: true;
}
EG#2
/*ComboBox's Arrow is a Region.*/
.combo-box .arrow-button .arrow {
/*Setting either of these two will do.*/
-fx-background-color: transparent;
-fx-opacity: 0.0;
}
/*ComboBox's Arrow Button is a Stack Pane.*/
.combo-box .arrow-button{
-fx-background-position: center;
-fx-background-repeat: no-repeat;
-fx-background-image: url("..<file>.png");
}
The method, in my main file.
def setCustomURLBarArrow(self, url_bar, scene, URLBarArrowConstant):
from javafx.scene.paint import Paint
from javafx.scene.shape import Shape, SVGPath, FillRule
Don't configure the ComboBox Arrow by CSS, instead, do it programmatically and change the Regions SVG Shape
if URLBarArrowConstant == URLBarArrowConstants.NOCSS_AND_SHAPE:
#SVG Object
previous_url_bar = SVGPath()
#SVG Path
previous_url_bar.setContent("...") # edit this
#SVG Fill Rule
previous_url_bar.setFillRule(FillRule.NON_ZERO)
#Set Fill --
previous_url_bar.setFill(Paint.valueOf(Color.web("...").toString())) //edit here
#Apply CSS Sheet
url_bar.applyCss()
#Set Region's Shape
arrow_region = url_bar.lookup(".arrow").setShape(previous_url_bar)
Configure the ComboBox Arrow by CSS and change the Regions SVG Shape
elif URLBarArrowConstant == URLBarArrowConstants.BYCSS_AND_SHAPE:
#Apply Stylesheet for URL Bar
scene.getStylesheets().add(File("..<file>.css").toURI().toString()) //edit here
Configure the ComboBox Arrow by CSS but instead, merely hide the arrow by setting the transparency/opacity values and set a background.
elif URLBarArrowConstant == URLBarArrowConstants.BYCSS_AND_NO_SHAPE:
#Apply Stylesheet for URL Bar
scene.getStylesheets().add(File("..<file>.css").toURI().toString()) //edit here
Don't configure the ComboBox Arrow by CSS, instead, do it programmatically and merely hide the arrow by setting the transparency/opacity values and set a background.
elif URLBarArrowConstant == URLBarArrowConstants.NOCSS_AND_NO_SHAPE:
from javafx.scene.paint import Paint
from javafx.scene.layout import CornerRadii
from javafx.scene.layout import Background, BackgroundSize, BackgroundImage, BackgroundPosition, BackgroundRepeat, BackgroundFill
#Apply CSS Sheet
url_bar.applyCss()
#Grab Arrow(Region), ArrowButton(StackPane) ComboBox properties
arrow_region = url_bar.lookup(".arrow")
arrow_button = url_bar.lookup(".arrow-button")
#Either Set Opacity to 0 or set background color to transparent.
arrow_region.setOpacity(0.0)
arrow_region.setBackground( Background( array(BackgroundFill, [BackgroundFill( Paint.valueOf(Color.TRANSPARENT.toString()), CornerRadii.EMPTY, Insets.EMPTY)]) ) )
#Set a Background Image for the .arrow-button StackPane.
arrow_button.setBackground(Background( array(BackgroundImage, [BackgroundImage( Image( String(File('..<file>.png').toURI().toString()), True) , BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, BackgroundSize.DEFAULT)] ) ) ) //if you want, edit this

Setting Background of TextArea

I would like to provide for user possiblity to select color of TextArea:
private void updateTextArea(){
textArea.setStyle("-fx-text-fill: #" + textColor + "; -fx-background-color: #" + backgroundColor);
}
however this doesnt change color of whole background. Ive found on the Internet that to change backgroud of text Area I need to do something like this in external CSS file.
.text-area .content {
-fx-background-color: black ;
}
how Can I do this with setStyle()?
You can do this by fetching the content node out of the TextArea and applying the style to it. But it works only after the TextArea is shown on the stage.
Usage :
Node node = textArea.lookup(".content");
node.setStyle("-fx-background-color: black;");

Resources