ProgressIndicator transparent background - css

So I have this code:
final StackPane g = new StackPane();
final ProgressIndicator p1 = new ProgressIndicator();
p1.setPrefSize(100, 100);
p1.progressProperty().addListener(new ChangeListener<Number>() {
#SuppressWarnings("rawtypes")
#Override
public void changed(ObservableValue ov, Number oldVal, Number newVal) {
if (p1.getProgress() < 0.3) {
p1.setStyle("-fx-progress-color: red;");
} else if (p1.getProgress() < 0.65) {
p1.setStyle("-fx-progress-color: orange;");
} else {
p1.setStyle("-fx-progress-color: green;");
}
}
});
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.setAutoReverse(true);
final KeyValue kv = new KeyValue(p1.progressProperty(), 1);
final KeyFrame kf1 = new KeyFrame(Duration.millis(3000), kv);
timeline.getKeyFrames().add(kf1);
g.getChildren().addAll(p1); //veil
g.setAlignment(Pos.CENTER);
Then I add the stack pane to a scene and the scene to the stage.
I have two stages, the initial stage with all my things and this additional stage with the progress indicator. Here is the problem: the stage that contains the progress indicator has a white squared(box) as background that fits perfect to the other stage, because usually has the same white background. But when the initial background is not white I can see the white background of the progress indicator stage. So here is my question: How can I make this background transparent? I tried the BlendMode class, but this doesn't seem to work. Any ideas?
Thanks in advance!

Use an external style sheet with
.progress-indicator .indicator {
-fx-background-color: transparent ;
}
Here's a complete example (I used the external style sheet to manage the colors too, but this will work anyway):
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.css.PseudoClass;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Control;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ProgressIndicatorTest extends Application {
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
ProgressIndicator pi = new ProgressIndicator();
Task<Void> counter = new Task<Void>() {
#Override
public Void call() throws Exception {
for (int i = 1; i <= 100; i++) {
Thread.sleep(50);
updateProgress(i, 100);
}
return null;
}
};
pi.progressProperty().bind(counter.progressProperty());
pi.progressProperty().addListener((obs, oldProgress, newProgress) -> {
PseudoClass warning = PseudoClass.getPseudoClass("warning");
PseudoClass critical = PseudoClass.getPseudoClass("critical");
if (newProgress.doubleValue() < 0.3) {
pi.pseudoClassStateChanged(warning, false);
pi.pseudoClassStateChanged(critical, true);
} else if (newProgress.doubleValue() < 0.65) {
pi.pseudoClassStateChanged(warning, true);
pi.pseudoClassStateChanged(critical, false);
} else {
pi.pseudoClassStateChanged(warning, false);
pi.pseudoClassStateChanged(critical, false);
}
});
pi.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
root.setStyle("-fx-background-color: antiqueWhite;");
root.getChildren().add(pi);
Scene scene = new Scene(root, 400, 400);
scene.getStylesheets().add("progress.css");
primaryStage.setScene(scene);
primaryStage.show();
new Thread(counter).start();
}
public static void main(String[] args) {
launch(args);
}
}
progress.css:
.progress-indicator .indicator {
-fx-background-color: transparent ;
}
.progress-indicator {
-fx-progress-color: green ;
}
.progress-indicator:critical {
-fx-progress-color: red ;
}
.progress-indicator:warning {
-fx-progress-color: orange ;
}

Try this for css (based on a bugfix for Java 8u40):
.progress-indicator:indeterminate > .spinner {
/** Applying to undo styling from .spinner, reported in RT-37965 */
-fx-background-color: transparent;
-fx-background-insets: 0;
-fx-background-radius: 0;
}

For me, none of the above answers worked.
I finally got it working by:
progressIndicator.getScene().getRoot().setStyle("-fx-background-color: transparent");
If you are using a scene, make the scene transparent by also doing:
scene.setFill(null);

Related

JavaFX TextArea - Controlling the scroll bar sizes

Unpleasantly surprised by TextArea CSS font sizes having wacky effects on the sizes of the scroll bars, I'm trying to get control of the sizes myself. Please refer to the following SSCCE. I can easily control the vertical scroll bar, but the horizontal bar is simply ignoring the sizes I'm setting. Am I expecting something unreasonable here, or is this (yet another) bug in JavaFX? Thanks!
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
TextArea textArea = new TextArea();
int lineCount = 100;
int wordCount = 70;
StringBuilder sb = new StringBuilder();
for (int lineNbr = 0; lineNbr < lineCount; lineNbr++) {
for (int wordNbr = 0; wordNbr < wordCount; wordNbr++) {
sb.append("Sample");
}
sb.append(System.getProperty("line.separator"));
}
textArea.setText(sb.toString());
StackPane root = new StackPane();
root.getChildren().add(textArea);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
double prefSize = 50;
ScrollBar vertScrollBar = (ScrollBar)textArea.lookup(".scroll-bar:vertical");
ScrollBar horizScrollBar = (ScrollBar)textArea.lookup(".scroll-bar:horizontal");
vertScrollBar.setPrefWidth(prefSize); // This works great!
horizScrollBar.setPrefHeight(prefSize); // This doesn't do anything!
horizScrollBar.setMinHeight(prefSize); // Nor does this
horizScrollBar.setPrefWidth(prefSize); // Nor this
horizScrollBar.setMinWidth(prefSize); // Nor this
}
}
ScrollBar vertScrollBar = (ScrollBar) textArea.lookup(".scroll-bar:vertical");
ScrollBar horizScrollBar = (ScrollBar) textArea.lookup(".scroll-bar:horizontal");
System.out.println(vertScrollBar + " " + horizScrollBar);
ScrollBar#35ef2d94[styleClass=scroll-bar]
ScrollBar#35ef2d94[styleClass=scroll-bar]
Same object (vertical ScrollBar).
ScrollPane sPane = (ScrollPane)textArea.getChildrenUnmodifiable().get(0);
ScrollBar horizScrollBar = (ScrollBar)sPane.getChildrenUnmodifiable().get(2);
horizScrollBar.setPrefHeight(prefSize); // This does something!
Update: Better way to receive the two ScrollBars.
ScrollBar[] bars = new ScrollBar[2];
textArea.lookupAll(".scroll-bar").toArray(bars);
bars[0].setPrefWidth(prefSize);
bars[1].setPrefHeight(prefSize);
Edit: Explanation for similar problem with lookupAll(...) and pseudo classes here and here.
Lookups are generally pretty fragile (and I don't think they're really intended to be robust); as noted in the links from the other answer they don't appear to support pseudoclasses.
You can of course just use CSS for this:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
TextArea textArea = new TextArea();
int lineCount = 100;
int wordCount = 70;
StringBuilder sb = new StringBuilder();
for (int lineNbr = 0; lineNbr < lineCount; lineNbr++) {
for (int wordNbr = 0; wordNbr < wordCount; wordNbr++) {
sb.append("Sample");
}
sb.append(System.getProperty("line.separator"));
}
textArea.setText(sb.toString());
StackPane root = new StackPane();
root.getChildren().add(textArea);
Scene scene = new Scene(root, 300, 250) ;
scene.getStylesheets().add("style.css");
primaryStage.setScene(scene);
primaryStage.show();
}
}
with the following in style.css:
.scroll-pane .scroll-bar:horizontal {
-fx-pref-height: 50 ;
}
.scroll-pane .scroll-bar:vertical {
-fx-pref-width: 50 ;
}
This approach, of course, is far more convenient if you have multiple scroll panes in your application and want them all to have the same style of scroll bars.

getting the Id of a button in JavaFX

I created about 10 buttons in javafx each of them onclick is suppose to change the label field in a certain way. My problem is that I don't want to create 10 different methods for each label I will like to use one method then test the id of the button if correct I preform what I want
example of what I am asking
if (button.id == Info_205_btn) {
System.out.println("clicked");
subject_name.setText("stanly");
}
This is an update after #math answer
Here is the code I did
#FXML
private void chooseSubject() {
for (int i = 0; i < buttonInfo.length; i++) {
buttonInfo[i] = new Button("Info"+i);
buttonInfo[i].setId("Info"+i);
int finalI = i;
buttonInfo[i].setOnAction(event -> checkID(buttonInfo[finalI]));
}
}
#FXML
private void checkID(Button button){
System.out.println("running");
if (button.getId().equals("Info0")) {
System.out.println("clicked");
subject_name.setText("stanly");
}
else if (button.getId().equals("Info1")) {
System.out.println("clicked");
subject_name.setText("stanly1");
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
chooseSubject();
}
also on click I placed the method chooseSubject in FXML controller
For all of your buttons I think you will still need to put a .setOnAction but you can have them all point to the same function
button.setOnAction(event -> checkID(button));
and from that function check the id
private void checkID(Button button){
if (button.getId().equals("Info_205_btn")) {
System.out.println("clicked");
button.setText("stanly");
}
else if (button.getId().equals("Info_206_btn")) {
System.out.println("clicked");
button.setText("stanly");
}
//So on
}
Also if you put all of your buttons into a list or if they are already in a list you can iterate though the list and do the .setOnAction that way
for (int i = 0; i < buttonList.length; i++)
button[i].setOnAction(event -> checkId((Button) event.getSource()));
Here is a test program I just wrote to give you an example
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Button[] buttonList = new Button[10];
for (int i = 0; i < buttonList.length; i++) {
buttonList[i] = new Button("Button "+i);
buttonList[i].setId("Button"+i);
buttonList[i].setOnAction(event -> checkId((Button) event.getSource()));
}
VBox root = new VBox();
root.setAlignment(Pos.CENTER);
root.getChildren().addAll(buttonList);
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setWidth(200);
stage.setScene(scene);
stage.show();
}
private void checkId(Button button) {
for (int i = 0; i <= 10; i++) {
if(button.getId().equals("Button" + i))
if(!button.getText().equals("Button " + i + " Clicked"))
button.setText("Button " + i + " Clicked");
else
button.setText("Button " + i);
}
}
public static void main(String[] args) { launch(args); }
}
Edit: Got carried away

Highlighting rectangle when more than half overlaps

I have a JavaFX application with a pane that contains rectangles. These rectangles can be moved by dragging the mouse.
When I drag a rectangle over another rectangle, I would like the second (background) rectangle to be highlighted. This works, see code below
private boolean moveInProgress;
private Point2D prevPos;
public void onMousePressed(MouseEvent event) {
setMouseTransparent(true);
Point2D point = new Point2D(event.getSceneX(), event.getSceneY());
if (!moveInProgress) {
moveInProgress = true;
prevPos = point;
LOG.debug("Mouse move started on location " + prevPos);
}
event.consume();
}
public void onMouseDragged(MouseEvent event) {
if (moveInProgress) {
Point2D point = new Point2D(event.getSceneX(), event.getSceneY());
this.toFront();
double[] translationVector = new double[2];
translationVector[0] = point.getX() - prevPos.getX();
translationVector[1] = point.getY() - prevPos.getY();
setTranslateX(getTranslateX() + translationVector[0]);
setTranslateY(getTranslateY() + translationVector[1]);
prevPos = point;
}
event.consume();
}
public void onMouseReleased(MouseEvent event) {
setMouseTransparent(false);
if (moveInProgress) {
moveInProgress = false;
}
event.consume();
}
public void onDragDetected(MouseEvent event) {
startFullDrag();
event.consume();
}
public void onMouseDragEntered(MouseDragEvent event) {
getStyleClass().add("drag-target");
event.consume();
}
public void onMouseDragExited(MouseDragEvent event) {
if (getStyleClass().contains("drag-target")) {
getStyleClass().remove("drag-target");
}
event.consume();
}
I would like to highlight the underlying rectangle when more than half of my dragging rectangle overlaps. In this picture, I would like to highlight the red rectangle, since the grey rectangle overlaps more than half of it.
The problem is that the MouseDragEntered and MouseDragExited events are fired based on my mouse position. When my mouse position is for example the black dot in the picture, my mouse events will only be fired when my mouse enters the red rectangle.
Can anyone give me some pointers how to highlight the red rectangle when during a drag action of the grey rectangle, more than half of it overlaps?
One approach is to have each rectangle observe the bounds of the rectangle that is being dragged. Then it's reasonably easy to do a computation using Shape.intersect (or by other means) to see if the rectangle is 50% covered by the rectangle being dragged. The tricky part here is adding the listeners to the rectangle being dragged and removing them again when the rectangle stops being dragged.
Here's a quick example. I think I have things set up a little differently from the way you have them set up, but you should be able to adapt this to your use case easily enough.
import java.util.Random;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.css.PseudoClass;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
public class DraggingHighlightRectangles extends Application {
private final Random rng = new Random();
private final ObjectProperty<Rectangle> draggingRectangle = new SimpleObjectProperty<>();
#Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
pane.setMinSize(600, 600);
Button newRectButton = new Button("New Rectangle");
newRectButton.setOnAction(e -> pane.getChildren().add(createRectangle()));
BorderPane.setAlignment(newRectButton, Pos.CENTER);
BorderPane.setMargin(newRectButton, new Insets(5));
BorderPane root = new BorderPane(pane);
root.setBottom(newRectButton);
Scene scene = new Scene(root);
scene.getStylesheets().add("style.css");
primaryStage.setScene(scene);
primaryStage.show();
}
private Rectangle createRectangle() {
Rectangle rect = new Rectangle(rng.nextInt(400)+100, rng.nextInt(500)+50, 100, 50);
rect.setFill(randomColor());
rect.getStyleClass().add("rect");
ChangeListener<Bounds> boundsListener = (obs, oldBounds, newBounds) -> {
double myArea = rect.getWidth() * rect.getHeight() ;
Shape intersection = Shape.intersect(draggingRectangle.get(), rect);
Bounds intersectionBounds = intersection.getBoundsInLocal();
double intersectionArea = intersectionBounds.getWidth() * intersectionBounds.getHeight() ;
rect.pseudoClassStateChanged(PseudoClass.getPseudoClass("highlight"), intersectionArea >= 0.5 * myArea);
};
draggingRectangle.addListener((obs, oldRect, newRect) -> {
if (oldRect != null) {
oldRect.boundsInLocalProperty().removeListener(boundsListener);
}
if (newRect != null && newRect != rect) {
newRect.boundsInLocalProperty().addListener(boundsListener);
}
rect.pseudoClassStateChanged(PseudoClass.getPseudoClass("highlight"), false);
});
class MouseLocation { double x, y ; }
MouseLocation mouseLocation = new MouseLocation();
rect.setOnMousePressed(e -> {
draggingRectangle.set(rect);
rect.toFront();
mouseLocation.x = e.getX() ;
mouseLocation.y = e.getY() ;
});
rect.setOnMouseDragged(e -> {
rect.setX(rect.getX() + e.getX() - mouseLocation.x);
rect.setY(rect.getY() + e.getY() - mouseLocation.y);
mouseLocation.x = e.getX() ;
mouseLocation.y = e.getY() ;
});
rect.setOnMouseReleased(e -> draggingRectangle.set(null));
return rect ;
}
private Color randomColor() {
return Color.rgb(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256));
}
public static void main(String[] args) {
launch(args);
}
}
My stylesheet, style.css, just contains
.rect:highlight {
-fx-fill: yellow ;
}

Creating TicTacToe in javafx

I am writing a TicTacToe program that displays a tic-tac-toe board that has the following qualities:
A cell may be X, O, or empty.
What to display at each cell is randomly decided upon startup of program.
Input the X's and O's as text instead of images.
In my program, I have the X's and O's as .gif files. I was wondering how the code would look when placing the X's and O's as text instead of images? Thanks in advance!
here is my code:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.text.Text;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class TicTacToe extends Application {
#Override
public void start(Stage primaryStage) {
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int random = (int)(Math.random() * 3);
if (random != 2) {
String text = (random > 0) ? "/image/x.gif" : "/image/o.gif";
pane.add(new ImageView(new Image(image)), j, i);
}
}
}
Scene scene = new Scene(pane, 150, 150);
primaryStage.setTitle("Tic Tac Toe");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
// Create a scene and place it in the stage
Scene scene = new Scene(pane);
primaryStage.setTitle("TicTacToe"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
public static void main(String[] args) {
launch(args);
}
}
Replace "/image/x.gif" with "X" and "/image/o.gif" with "O" and instead of using an ImageView, use a Label and set the text of the label to the text variable then add it to your Pane

Show drop down menu on mouse over

I want to create drop down menu like this:
I want when I place the mouse over the text to see combo box which I can use to select a value. When I remove the mouse I want to see simple Label. How I can do this?
Unhovered:
On Hover:
On Click and Choose:
On Choice Complete:
import javafx.application.Application;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class Hoverboard extends Application {
public class TextChooser extends StackPane {
private Label label = new Label();
private ComboBox<String> combo = new ComboBox<>();
public TextChooser(String... options) {
StackPane.setAlignment(label, Pos.CENTER_LEFT);
StackPane.setAlignment(combo, Pos.CENTER_LEFT);
label.textProperty().bind(
combo.getSelectionModel().selectedItemProperty()
);
label.visibleProperty().bind(
combo.visibleProperty().not()
);
label.setPadding(new Insets(0, 0, 0, 9));
combo.getItems().setAll(options);
combo.getSelectionModel().select(0);
combo.setVisible(false);
label.setOnMouseEntered(event -> combo.setVisible(true));
combo.showingProperty().addListener(observable -> {
if (!combo.isShowing()) {
combo.setVisible(false);
}
});
combo.setOnMouseExited(event -> {
if (!combo.isShowing()) {
combo.setVisible(false);
}
});
getChildren().setAll(label, combo);
}
}
#Override
public void start(Stage stage) throws Exception {
TextChooser textChooser = new TextChooser(
"xyzzy", "frobozz", "foobar"
);
VBox layout = new VBox(textChooser);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(Hoverboard.class);
}
}
Here is also css style version: https://github.com/varren/JavaFX-CSS-Styled-ComboBox-Demo
A little bit different from the default one, but you can play with css to get what you want. Default styles can be found in jxrt.jar!/com/sun/javafx/scene/control/skin/caspian/caspian.css
CSS
#changed{
-fx-background-color: transparent;
}
#changed .arrow,
#changed .arrow-button{
-fx-background-color: transparent;
}
/* this part is from default stiles fxrt.jar!/com/sun/javafx/scene/control/skin/caspian/caspian.css */
#changed:hover{
-fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color;
-fx-background-radius: 5, 5, 4, 3;
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
-fx-padding: 0;
}
#changed:showing > .arrow-button {
-fx-color: -fx-pressed-base;
}
#changed:hover > .arrow-button > .arrow{
-fx-background-insets: 1 0 -1 0, 0;
-fx-background-color: -fx-mark-highlight-color, -fx-mark-color;
-fx-padding: 0.166667em 0.333333em 0.166667em 0.333333em; /* 2 4 2 4 */
-fx-shape: "M 0 0 h 7 l -3.5 4 z";
}
JAVA
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
HBox root = new HBox();
primaryStage.setTitle("Combo Box Style From Css");
ComboBox combobox = new ComboBox<String>(FXCollections.observableArrayList("One", "Two", "Three"));
combobox.getSelectionModel().select(0);
combobox.setId("changed");
ComboBox normalCombobox = new ComboBox<String>(FXCollections.observableArrayList("One", "Two", "Three"));
normalCombobox.getSelectionModel().select(0);
root.getChildren().addAll(combobox, normalCombobox);
Scene scene = new Scene(root, 300, 275);
scene.setFill(Color.WHITE);
String css = Main.class.getResource("styles.css").toExternalForm();
scene.getStylesheets().clear();
scene.getStylesheets().add(css);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
DEMO
Two potential approaches:
Try to use CSS to modify the look of the ComboBox so it looks like a normal text field; hide the arrow and border, and re-show them on :hover. You'll want to lookup the CSS reference for ComboBox: http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html#combobox
Use a normal TextField, and display a border (and arrow) on :hover. Attach a mouse-listener to the TextField to display a PopupControl on mouse click. Put a ListView inside the PopupControl so it behaves like a ComboBox. You'll need to create a class that implements Skin for your popup control. You should be able to find some examples on the web.

Resources