I have to use a Radio Button to make three Radio Buttons Red, Blue, and Green. The radio buttons are not changing to those colors. In addition to those changes, the others must stay black font. I commented out the Red setTextFill Font and there was no effect. I also commented the Black fonts and they did not do make an effect. The isSelection works.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class ButtonRadio extends Application {
#Override
public void start(Stage primaryStage) {
// primary stage
primaryStage.setTitle("javaFX");
// label for text
Label labelfirst = new Label("Choose a button");
// vBox for buttons
VBox layout = new VBox(3);
// radio buttons
RadioButton radio1, radio2, radio3;
radio1 = new RadioButton("Red");
radio2 = new RadioButton("Blue");
radio3 = new RadioButton("Green");
// ToggleGroup for entering
ToggleGroup group = new ToggleGroup();
// radio button variables of toggle groups
radio1.setToggleGroup(group);
radio2.setToggleGroup(group);
radio3.setToggleGroup(group);
// if statements for radio buttons and fonts red, blue, green
if (group.getSelectedToggle() != null) {
if (radio1.isSelected()) {
radio1.setTextFill(Color.RED);
radio2.setTextFill(Color.BLACK);
radio3.setTextFill(Color.BLACK);
} else if (radio2.isSelected()) {
radio2.setTextFill(Color.BLUE);
radio1.setTextFill(Color.BLACK);
radio3.setTextFill(Color.BLACK);
}
else if (radio3.isSelected())
{
radio3.setTextFill(Color.GREEN);
radio1.setTextFill(Color.BLACK);
radio2.setTextFill(Color.BLACK);
}
}
// layout to put in parent
layout.getChildren().addAll(labelfirst, radio1, radio2, radio3);
// put in scene and stage to show
Scene scene1 = new Scene(layout, 400, 250);
primaryStage.setScene(scene1);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Edit:
I tried adding a listener. It still does not work.
if (radio1.isSelected()) {
radio1.setOnAction((event) -> {
radio1.setTextFill(Color.RED);
});
Your if statement will only run once, checking the selected status of your RadioButtons only when the application first runs.
You need to listen for changes to the selected RadioButton and act accordinly. This is easily done by adding a listener to the ToggleGroup's selectedToggleProperty().
Remove your if block and replace it with something like this:
group.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
// Set the previously-selected RadioButton text to BLACK
if (oldValue != null) ((RadioButton) oldValue).setTextFill(Color.BLACK);
// Set the color for the newly-selected RadioButton
if (newValue.equals(radio1)) {
((RadioButton) newValue).setTextFill(Color.RED);
} else if (newValue.equals(radio2)) {
((RadioButton) newValue).setTextFill(Color.BLUE);
} else if (newValue.equals(radio3)) {
((RadioButton) newValue).setTextFill(Color.GREEN);
}
});
Related
I am working on an app in JavaFX using SceneBuilder, and I want to add an CSS code that will display label when I hover on a button, I tried:
.label
{
-fx-text-fill: transparent;
}
.button:hover ~ .label
{
-fx-text-fill: black;
}
All the elements are in the same container.
So my question is how can I affect label using button?
You will not be able to do this purely with JavaFX CSS since the Label is not a descendant of the button.
You can, however, alter the style of the Label by listening to the hoverProperty of your Button and setting the style for the Label appropriately:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Sample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Sample layout
VBox root = new VBox(5);
root.setAlignment(Pos.TOP_CENTER);
root.setPadding(new Insets(5));
// Create the Button and Label
Button button = new Button("Hover Me!");
Label label = new Label("You hovered like a pro!");
// Add a listener to the button's hoverProperty. When it is triggered, we can update the
// styleclass of the label.
button.hoverProperty().addListener((observable, oldValue, newValue) -> {
// If the current state is true, add the button-hovered styleclass
if (newValue) {
label.getStyleClass().add("button-hovered");
} else {
// Otherwise, we remove that class
label.getStyleClass().remove("button-hovered");
}
});
// Add the button and label to the layout
root.getChildren().addAll(button, label);
// Create the scene
Scene scene = new Scene(root);
// Apply CSS
scene.getStylesheets().add("css/style.css");
primaryStage.setScene(scene);
primaryStage.show();
}
}
HOWEVER, in your case, you may be going about it the wrong way since you just want to keep the Label hidden until the user hovers over the Button. In that case, it is probably simpler to just bind the visibleProperty of the Label to your hoverProperty of the Button. Doing so takes just one line of code instead of using the listener:
label.visibleProperty().bind(button.hoverProperty());
Of course, you'll want to remove the .label selector from your CSS if you go this route, since it will still make the text transparent.
I'm new with Java, I would like to know how to prevent MenuButton popup from closing when I click on the item, I tried the following function, which I found on this site, but does not seem to do anything. I need this in order to make a clone of my C# application whit the purpose of learning Java.
#FXML
private MenuButton menuButton;
#FXML
void initialize() {
CheckMenuItem menuButtonItem1 = new CheckMenuItem("Item 1");
CheckMenuItem menuButtonItem2 = new CheckMenuItem("Item 2");
CheckMenuItem menuButtonItem3 = new CheckMenuItem("Item 3");
menuButtonItem1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
e.consume();
}
});
menuButtonItem2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
e.consume();
}
});
menuButtonItem3.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
e.consume();
}
});
}
The CustomMenuItem class provides a setHideOnClick() method that will handle this. In order to use it, you'll wrap a standard Node in this CustomMenuItem:
CheckBox checkBox = new CheckBox("Item 1");
CustomMenuItem customMenuItem = new CustomMenuItem(checkBox);
customMenuItem.setHideOnClick(false);
Below is a full example for you to try:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.MenuButton;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CheckMenuKeepOpen extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
// Create the MenuButton
MenuButton menuButton = new MenuButton("Click Me");
for (int i = 0; i < 5; i++) {
// In order to keep the menu open when selecting a CheckBox, we need to wrap it in a CustomMenuItem
CustomMenuItem menuItem = new CustomMenuItem(new CheckBox("Item #" + i));
// This method is pretty obvious; it keeps the menu open when selecting this item.
menuItem.setHideOnClick(false);
menuButton.getItems().add(menuItem);
}
root.getChildren().add(menuButton);
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
}
We found using custom menu item would lose the styling of normal menu items. Instead we solved by using a Menu (i.e. a sub menu) with no items in which other than arrows to the right looks identical to a normal menu item but does not close when clicked. Then finally used css to remove the arrow to the right.
I’m trying to build a board game interface where the user can switch between multiple eras, each one with its own board. To do so, I’m creating 4 different board, each within its own pane, and I’m toggling the nodes Visibility and disabling the nodes that aren’t being used. The problem I have is the mouse event handlers I’m using to see where the user is clicking only work on the top layer, the last one that was rendered. The event Handlers underneath don’t work even if they are enabled.
Here’s what I wrote:
static EventHandler<MouseEvent> eventMouseClickRoad = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
final Shape innerShape = (Shape) (e.getTarget());
System.out.println("click");
Color color = (Color) innerShape.getFill();
if(color.getOpacity() != 1)
{
innerShape.setFill(Color.RED);
//and do the data treatment
}
}
};
public void boardControler(Vector2DList sideList,PointList hexEdge,Pane groupPane,float scaleX, float scaleY, float buttonSize)
{
//set road button
for(Vector2D v : sideList.getVectorList()){
Path mypath = new Path(new MoveTo(v.getP1().getX(),v.getP1().getY()),new LineTo(v.getP2().getX(),v.getP2().getY()));
groupPane.getChildren().add(mypath);
}
for(Vector2D v : sideList.getVectorList()){
float midX=(v.getP1().getX()+v.getP2().getX())/2;
float diffY=v.getP1().getY()-v.getP2().getY();
float diffX=v.getP1().getX()-v.getP2().getX();
Rectangle rectangle = new Rectangle(midX-buttonSize/2,midY-Math.abs(diffY)+buttonSize+(Math.abs(diffY)-scaleY/4),buttonSize,(scaleY/2)-(buttonSize*2));
rectangle.setRotate(Math.toDegrees(Math.atan(diffY/diffX))+90);
rectangle.setFill(Color.TRANSPARENT);
rectangle.addEventFilter(MouseEvent.MOUSE_ENTERED, Event.eventMouseEntered);
rectangle.addEventFilter(MouseEvent.MOUSE_EXITED, Event.eventMouseExit);
rectangle.addEventFilter(MouseEvent.MOUSE_CLICKED, Event.eventMouseClickRoad);
groupPane.getChildren().add(rectangle);
}
}
And this is what i use to toggle the board that's being used:
to disable
for(Node n : groupPane2.getChildren())
{
n.setDisable(true);
n.setManaged(false);
n.setVisible(false);
}
to enable
for(Node n : groupPane2.getChildren())
{
n.setDisable(false);
n.setManaged(true);
n.setVisible(true);
}
Perhaps using a StackPane would be the solution here. Your question doesn't include much code to show all of your context, but the MCVE below may help to demonstrate the idea.
Basically, we create a StackPane as our root display container for all of your boards. Your "boards" can be anything, a Pane, another StackPane, or a VBox like in my example. This should allow you to continue using whatever layout system you currently are.
One thing to note, it appears that each board will need to have a background set, or the lower boards will show through and may accept mouse events.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class StackPaneSample extends Application {
public static void main(String[] args) {
launch(args);
}
private static StackPane stackPane = new StackPane();
#Override
public void start(Stage primaryStage) {
// Simple interface
VBox root = new VBox(5);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
// Create our StackPane
stackPane.setStyle("-fx-border-color: black");
VBox.setVgrow(stackPane, Priority.ALWAYS);
// Let's create 3 "boards" for our StackPane. A background color seems necessary to hide layers below the top one
VBox board1 = new VBox() {{
setStyle("-fx-background-color: whitesmoke");
setAlignment(Pos.CENTER);
setUserData("Board #1");
getChildren().add(new Label((String) getUserData()));
}};
VBox board2 = new VBox() {{
setStyle("-fx-background-color: whitesmoke");
setAlignment(Pos.CENTER);
setUserData("Board #2");
getChildren().add(new Label((String) getUserData()));
}};
VBox board3 = new VBox() {{
setStyle("-fx-background-color: whitesmoke");
setAlignment(Pos.CENTER);
setUserData("Board #3");
getChildren().add(new Label((String) getUserData()));
}};
stackPane.getChildren().add(board1);
stackPane.getChildren().add(board2);
stackPane.getChildren().add(board3);
// Create three buttons that will switch between the boards
Button btnBoard1 = new Button("Board #1");
Button btnBoard2 = new Button("Board #2");
Button btnBoard3 = new Button("Board #3");
HBox hbButtons = new HBox(20) {{
setAlignment(Pos.CENTER);
setPadding(new Insets(5));
getChildren().addAll(btnBoard1, btnBoard2, btnBoard3);
}};
// Finish out layout
root.getChildren().addAll(
stackPane,
new Separator(Orientation.HORIZONTAL),
hbButtons
);
// ** Now let's add our functionality **
// Print out which board has been clicked upon
// We need to first cast our List to VBox
for (Node vbox : stackPane.getChildren()) {
vbox.setOnMouseClicked(event -> System.out.println("Clicked on " + vbox.getUserData()));
}
// Set the buttons to set the top board
btnBoard1.setOnAction(event -> selectBoard(board1));
btnBoard2.setOnAction(event -> selectBoard(board2));
btnBoard3.setOnAction(event -> selectBoard(board3));
// Show the Stage
primaryStage.setWidth(400);
primaryStage.setHeight(300);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
// Method to remove the board and readd it, placing it on top of all others.
private static void selectBoard(VBox board) {
stackPane.getChildren().remove(board);
stackPane.getChildren().add(board);
}
}
The Result:
I am, admittedly, not familiar with the Cartesian coordinates you mention in your comment, so perhaps this won't work for you. Adding more code/context to your question might help us narrow down the issue better.
I am creating a JavaFX application and I am having problems changing the background colors for certain components. For the buttons I am able to change their background radius, but not their background color. For the TableView I am unable to change the background color as well.
Here is my code and a picture of what I am seeing.
import javafx.geometry.Pos;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class HomeUI extends Application {
private TableView transactionTable = new TableView();
private Button importButton = new Button("Import");
private Button trendButton = new Button("Trends");
private Button transactionButton = new Button("Transactions");
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
// Set the text of defined fields
primaryStage.setTitle(" Budget Tracker");
// Import button information
// Create Anchor pane
AnchorPane anchorPane = new AnchorPane();
anchorPane.setPrefHeight(668.0);
anchorPane.setPrefWidth(1112.0);
anchorPane.setStyle("-fx-background-color: #545e75;");
// VBox to hold all buttons
VBox vBox = new VBox();
vBox.setPrefWidth(195);
vBox.setPrefHeight(668);
vBox.prefHeight(668);
vBox.prefWidth(203);
vBox.setStyle("-fx-background-color: #82a0bc;");
vBox.setLayoutX(0);
vBox.setLayoutY(0);
vBox.setAlignment(Pos.CENTER);
// importButton settings
importButton.setMnemonicParsing(false);
importButton.setPrefWidth(300);
importButton.setPrefHeight(80);
importButton.setStyle("-fx-background-color: #cacC9cc");
importButton.setStyle("-fx-background-radius: 0;");
// trendButton settings
trendButton.setPrefWidth(300);
trendButton.setPrefHeight(80);
trendButton.setStyle("-fx-background: #bcbdc1");
trendButton.setStyle("-fx-background-radius: 0");
// transactionButton settings
transactionButton.setPrefWidth(300);
transactionButton.setPrefHeight(80);
transactionButton.setStyle("-fx-base: #aeacb0");
transactionButton.setStyle("-fx-background-radius: 0");
// Add buttons to the vBox
vBox.getChildren().addAll(importButton, trendButton, transactionButton);
// TableView settings
transactionTable.setPrefHeight(568);
transactionTable.setPrefWidth(694);
transactionTable.setLayoutX(247);
transactionTable.setLayoutY(50);
transactionTable.setStyle("-fx-background-color: CAC9CC;");
transactionTable.setEditable(false);
// Add components to anchorPane
anchorPane.getChildren().addAll(vBox, transactionTable);
// Add anchorPane to scene and show it
primaryStage.setScene(new Scene(anchorPane));
primaryStage.show();
}
}
Buttons
By setting the style property, you replace the old style. Doing this multiple times does not combine the styles. You should set a value that combines the rules.
Instead of
transactionButton.setStyle("-fx-base: #aeacb0");
transactionButton.setStyle("-fx-background-radius: 0");
use
transactionButton.setStyle("-fx-base: #aeacb0; -fx-background-radius: 0;");
TableView
TableView shows little of it's own background. Most coloring you'll see is the background color of the TableRows that are added as descendants of the TableView. You'll need to use a CSS stylesheet to do this though (unless you want to use a rowFactory to do the styling).
.table-view .table-row-cell {
-fx-background-color: #CAC9CC;
}
I would like to be able to capture the MOUSEENTER event when hovering over a tab.
I have tried to do it from the Graphic of the tab, which is not the optimal solution, but it is a Node object with such events.
This is what I wrote:
tab.getGraphic().setOnMouseEntered((MouseEvent event) -> {
System.out.println("..... mouse entered");
//...
});
This solution does not error but is ignored by Javafx, any way to do this?
UPDATE: The way to create the tab and add its graphic, is like the following excerpt. The tab itself works fine and the graphic displays fine.
Tab tab = addChatTab(root, strName, strID, chat, false);
// setup tab graphic
switch (win.type) {
case wtChat:
if (chat !=null)
if (chat.isPublic()) {
tab.setGraphic(new ImageView(Main.me.imgTabPublic));
} else {
if (chat.isDCC())
tab.setGraphic(new ImageView(Main.me.imgTabDCC));
else tab.setGraphic(new ImageView(Main.me.imgTabPrivate));
}
break;
case wtWall:
tab.setGraphic(new ImageView(Main.me.imgTabWall));
break;
case wtMessage:
tab.setGraphic(new ImageView(Main.me.imgTabMessage));
break;
}
If you set a mouse handler on a graphic, then the handler will only be invoked when the mouse interacts with the graphic itself. In this example, the first tab has both text and a graphic set, so the mouse handler is not invoked when the mouse moves onto the text. The second tab sets no text but uses a label as the graphic, with the label containing the text. In that case the mouse handler is invoked when the mouse moves onto the text or image.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class TabPaneHoverTest extends Application {
#Override
public void start(Stage primaryStage) {
// hover only applies on graphic:
Tab tab1 = new Tab("Tab 1");
tab1.setGraphic(new Rectangle(16, 16, Color.RED));
// Tab only uses graphic (no text),
// so hover appears to apply to whole tab:
Tab tab2 = new Tab();
Label tab2Graphic = new Label("Tab 2", new Rectangle(16, 16, Color.GREEN));
tab2.setGraphic(tab2Graphic);
tab1.getGraphic().setOnMouseEntered(e -> System.out.println("Hover on tab 1"));
tab2.getGraphic().setOnMouseEntered(e -> System.out.println("Hover on tab 2"));
BorderPane root = new BorderPane(new TabPane(tab1, tab2));
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}