JavaFX2 : can not mix some "setStyle" on Pane - background

DESCRIPTION
On windows7 and with JDK1.8.0_20, I simply try to display some panes with a black border and with a given background color. I am using "setStyle" method for that, with the following documentation http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html#region. The problem code is within the TestPane class.
See below the full running code :
package pane;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class BorderPaneApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("BorderPane");
MainPane mainPane = new MainPane();
Scene scene = new Scene( mainPane, 400, 300, Color.ORANGE);
// do it for the layout
mainPane.prefHeightProperty().bind(scene.heightProperty());
mainPane.prefWidthProperty().bind(scene.widthProperty());
primaryStage.setScene(scene);
primaryStage.show();
}
public class MainPane extends BorderPane{
public TestPane topPane = new TestPane("top", Color.LIGHTSKYBLUE);
public TestPane leftPane = new TestPane("left", Color.AQUA);
public TestPane bottomPane = new TestPane("bottom", Color.AZURE);
public TestPane centerPane = new TestPane("center", Color.LIGHTBLUE);
public MainPane(){
this.setTop(this.topPane);
this.setLeft(this.leftPane);
this.setCenter(this.centerPane);
this.setBottom(this.bottomPane);
}
}
public class TestPane extends BorderPane {
public TestPane(String name, Color color){
// first style part - start
this.setStyle("-fx-border-color: #FFFFFF;");
this.setStyle("-fx-border-width: 1px;");
this.setStyle("-fx-border-style: solid;");
// first style part - end
// second style part - start
this.setStyle("-fx-background-color: " + color.toString().replace("0x", "#") + ";");
// second style part - end
this.setCenter(new Text(name));
}
}
}
After some tries, I can not mix this code :
// first style part - start
this.setStyle("-fx-border-color: #FFFFFF;");
this.setStyle("-fx-border-width: 1px;");
this.setStyle("-fx-border-style: solid;");
// first style part - end
with this one :
// second style part - start
this.setStyle("-fx-background-color: " + color.toString().replace("0x", "#") + ";");
// second style part - end
The last one seems to take over the first and do not display it. The first picture shows the border line sets before the background and the second shows the background sets before the border line.
QUESTION
How to display both style together?
Cheers,
Jakez

setStyle() is a setter method, thus it does not append..
You want to combine all styles into one String:
setStyle("-fx-border-color: #FFFFFF;-fx-border-width: 1px;-fx-border-style: solid;-fx-background-color: " + color.toString().replace("0x", "#") + ";");

Related

Dynamically updating Polyline points in tornadofx

This question is a bit simplistic, but i couldn't figure it out for myself... What I'm trying to do is using a JavaFX Timeline to update my Polyline points. What I've got until now is as follows:
class MainView : View("Hello TornadoFX") {
var myLine: Polyline by singleAssign()
val myTimeline = timeline {
cycleCount = INDEFINITE
}
override val root = hbox {
myLine = polyline(0.0, 0.0, 100.0, 100.0)
myTimeline.apply {
keyFrames += KeyFrame((1/10.0).seconds, {
myLine.points.forEachIndexed { i, d ->
myLine.points[i] = d + 1
}
println(myLine.points)
})
play()
}
}
}
Although the point list does update the values, as shown when printing them, the change is not reflected in the ui.
Thank you very much for your help!
I have not worked with TornadoFX earlier, so I gave a try with the normal JavaFX. Looks like the the UI is updating when the points are updated. May be the issue is something related to your implementation with TornadoFX.
Please check below the working example.
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Polyline;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PolyLinePointsUpdateDemo extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Pane root = new Pane();
Scene scene = new Scene(root, 600,600);
primaryStage.setScene(scene);
primaryStage.setTitle("PolyLine Points Update");
primaryStage.show();
Polyline line = new Polyline(0.0, 0.0, 100.0, 100.0);
root.getChildren().add(line);
Timeline timeline = new Timeline();
timeline.getKeyFrames().add(new KeyFrame(Duration.millis(250), e->{
for (int i = 0; i < line.getPoints().size(); i++) {
double d = line.getPoints().get(i);
line.getPoints().set(i, d+1);
}
System.out.println(line.getPoints());
}));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}
public static void main(String... a){
Application.launch(a);
}
}
Figured out that the issue was simply using an hbox as the parent layout, instead of a pane, which handles the chidren positioning with absolute coordinates.

Styling background of TornadoFX ListView

Is it possible to style a ListView component so that none of the elements have a shaded background?
I.e not like this:
But instead have them all styled like the first, third, fifth item etc.
TIA
In the default stylesheet, modena.css the background color for ListCells is governed by the following lines of code:
.list-cell,
.tree-cell {
-fx-background: -fx-control-inner-background;
-fx-background-color: -fx-background;
-fx-text-fill: -fx-text-background-color;
}
/* ... */
.list-cell:odd {
-fx-background: -fx-control-inner-background-alt;
}
So to remove the alternative color for the odd-numbered cells (note that counting is zero-indexed, so the odd-numbered cells are the 2nd, 4th, etc in the list view), you just need to include the following in your external CSS file, to revert the color for the odd-numbered cells to the same as the even-numbered cells:
.list-cell:odd {
-fx-background: -fx-control-inner-background ;
}
If you need to apply this to one specific ListView, you can set an id on that ListView:
ListView myListView ;
// ...
myListView.setId("plain-list-view");
and then the CSS selector becomes
#plain-list-view .list-cell:odd {
-fx-background: -fx-control-inner-background ;
}
You need to create a custom ListCell with a non-null Background. Once you do this, the automatic colour handling of the ListView for selected rows won't work properly any more. So you'll have to handle that yourself. The selection action will invert the colour of the text to white, but that's all. So you need to set the background colour of the cell based on the "Selected" property of the ListCell. In Java it would look like this:
public class Sample1 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new ListBackgroundWhite(), 300, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
public class ListBackgroundWhite extends ListView<String> {
public ListBackgroundWhite() {
super();
setCellFactory(listView -> new WhiteListCell());
setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}
static class WhiteListCell extends ListCell<String> {
WhiteListCell() {
Background unselectedBackground =
new Background(new BackgroundFill(Color.WHITESMOKE, CornerRadii.EMPTY, Insets.EMPTY));
Background selectedBackground = new Background(new BackgroundFill(Color.BROWN, CornerRadii.EMPTY,
Insets.EMPTY));
backgroundProperty().bind(Bindings.createObjectBinding(() -> isSelected() ? selectedBackground :
unselectedBackground, selectedProperty()));
}
#Override
public void updateItem(String item, boolean isEmpty) {
super.updateItem(item, isEmpty);
if (!isEmpty) {
setText(item);
} else {
setText(null);
}
}
}
}
Once you do this, the cell background is no longer transparent, and the stripe pattern of the ListView itself won't show through.
EDIT:
As pointed out, this IS heavy-handed, except that in most cases a ListView isn't going to be a simple Label with a string in it. It's going to have some sort of layout in the ListCell that is going to require that you create a custom ListCell in any event.
However, messing with the Background directly via a binding to the "Selected" property is clumsy. You can create a new StyleClass, and then just define the modified PseudoClasses in the css. Then add this new StyleClass to the custom ListCell, and then it will handle it automatically as it applies the "EVEN" and "ODD" pseudoclasses.
One thing I found was that since the new "odd" definition gets applied after all of the other definitions in the default Modena css, that the "SELECTED" pseudoclass for ODD lines is suppressed. This means that the odd and even lines look different when they are selected, so a duplicate "SELECTED" definition needed to be added to the new css after the "ODD" definition. Then everything works properly. So the new code looks like this:
The CSS:
.custom-list-cell:odd {
-fx-background: -fx-control-inner-background;
}
.custom-list-cell:selected {
-fx-background: -fx-selection-bar;
-fx-table-cell-border-color: derive(-fx-selection-bar, 20%);
}
The main, now loads the new stylesheet into the Scene:
public class Sample1 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new ListBackgroundWhite(), 300, 200);
scene.getStylesheets().add(getClass().getResource("/css/samples.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
}
And then the only customization to the ListCell is to add the new StyleClass:
public class ListBackgroundWhite extends ListView<String> {
public ListBackgroundWhite() {
super();
setCellFactory(listView -> new WhiteListCell());
setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}
static class WhiteListCell extends ListCell<String> {
WhiteListCell() {
getStyleClass().add("custom-list-cell");
}
#Override
public void updateItem(String item, boolean isEmpty) {
super.updateItem(item, isEmpty);
if (!isEmpty) {
setText(item);
} else {
setText(null);
}
}
}
}
But if you really are just wanting to have a ListView with just simple labels in it, you can just have the cell factory add the StyleClass on to the standard TextFieldListCell:
public ListBackgroundWhite() {
super();
setCellFactory(listView -> {
ListCell<String> cell = new TextFieldListCell<>();
cell.getStyleClass().add("custom-list-cell");
return cell;
});
setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}

Java OOP using Translate Transition and JavaFX

The Translate Transition does not output. It uses a method in the main class. I believe it is not working because it is used as an object. There has to be a different code to implement. It uses a method in a main and then puts it into a tester. However, I do not know how to use it because it uses a constructor/object as well. Then, the object turns and changes into a node which I changed it. I do not know how the Translate Transition method is attached to the object and displays it into the javafx console. Please help solve the problem for positive feedback as it shows.
import javafx.animation.TranslateTransition;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Shape;
import javafx.util.Duration;
public class AnxiousShapes {
private Shape shape;
private double delay ;
private int howFarToMoveX;
private int howFarToMoveY;
public AnxiousShapes(int type, int x, int y, int size, double delay, Color color, int hftmX, int hftmY) {
if (type == 0) {shape = new Circle(x, y, size, color);}
//these are the only lines you can change
//in this main class
//else if (type == 1){shape = new Rectangle(x,y,color);}
//else if (type == 2){shape = new Polygon();}
//else if (type == 3) {shape = new Circle(x, y, size, color);}
//else { System.out.println("Error in type");shape = new
//Circle(???????);}
this.delay = delay;
this.howFarToMoveX = hftmX;
this.howFarToMoveY = hftmY;
}
// getter and setters
public TranslateTransition calculateTt() {
TranslateTransition tt = new TranslateTransition(Duration.seconds(this.delay), this.shape);
tt.setToX(this.shape.getLayoutX() + howFarToMoveX);
tt.setToY(shape.getLayoutY() + howFarToMoveY);
// Let the animation run forever -- if the shape
// tries to move "off-screen" it will return to the beginning
tt.setCycleCount(TranslateTransition.INDEFINITE);
return tt;
}
#Override
public String toString() {
return "AnxiousShape [shape=" + shape + ", delay=" + delay + ", howFarToMoveX=" + howFarToMoveX
+ ", howFarToMoveY=" + howFarToMoveY + "]";
}
}
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.scene.Group;
import javafx.scene.Node;
import java.util.Random;
public class AnxiousShapesTester extends Application {
#Override
public void start(Stage stage) {
// adding the new things
Group root = new Group();
stage.setTitle("Welcome to JavaFX!");
// create the shape circle
AnxiousShapes circle1 = new AnxiousShapes(0, 200, 200, 50, 15,
Color.GREEN, 10 ,35);
root.getChildren().add(circle1.getShape());
// this does not work
// TranslateTransition trans = circle1.calculateTt();
// trans.setNode(root);
// trans.play();
// and I tried this and I already have the movement in constructor for
// delay and x and y but TranslateTransition
// asks for duration.millis(500)
TranslateTransition tt = new
TranslateTransition(Duration.millis(500), root);
tt.play();
Scene scene = new Scene(root, 600, 600, Color.WHITE);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
In a comment, you say, "this does not work." The problem is trans.setNode(root), which attempts to make root "The target node of this TranslateTransition." Your implementation of calculateTt() already specifies this.shape as the target node. Instead, add a suitable accessor to AnxiousShapes and use the transition as constructed; the following changes are illustrated below:
public Shape getShape() { return this.shape; }
…
AnxiousShapes circle1 = new AnxiousShapes(0, 100, 100, 100, 3, Color.GREEN, 400, 400);
root.getChildren().add(circle1.getShape());
TranslateTransition trans = circle1.calculateTt();
trans.play();

ImageButton is visible only after resize - Libgdx

I have a class called "HudBarView" which takes care of the drawing of the HUD Bar at the top of the screen(Pause button, score, etc).
This class extends the Group class(scene2d).
Another class I have is "HUDManager" which takes care of all the HUD work in the game, including HUD Bar.
Now, currently I have only a pause button in my HUD Bar but the problem is - it is visible only after I resize the screen. Very weird problem.
Here is my HudBarView class:
package views.hud.views;
import views.renderers.HUDManager;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import engine.helpers.AssetsManager;
import engine.helpers.Values;
public class HUDBarView extends Group{
private ImageButton pause;
private HUDManager hud_manager;
private Skin skin;
public HUDBarView(HUDManager hud_manager) {
this.hud_manager = hud_manager;
initiate();
}
private void initiate() {
skin = new Skin(AssetsManager.getAsset(Values.BUTTONS_PACK, TextureAtlas.class));
pause = new ImageButton(skin.getDrawable("pause"));
pause.setSize(Values.Pause_Width, Values.Pause_Height);
pause.setPosition(Values.SCREEN_WIDTH - pause.getWidth(), Values.SCREEN_HEIGHT- pause.getHeight());
addActor(pause);
}
}
Here is my HUDManager class:
package views.renderers;
import views.hud.ParticleEffectsActor;
import views.hud.views.HUDBarView;
import aurelienribon.tweenengine.TweenManager;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import engine.helpers.AssetsManager;
import engine.helpers.UIHelper;
import engine.helpers.Values;
public class HUDManager extends Group {
private Stage stage;
private Skin skin;
private Image text;
private HUDBarView hudView;
public HUDManager(Stage stage) {
this.stage = stage;
initiate();
addActor(hudView);
addActor(particles);
}
public void initiate() {
skin = AssetsManager.getAsset(Values.GAME_SKIN_PACK, Skin.class);
hudView = new HUDBarView(this);
particles = new ParticleEffectsActor();
}
public Stage getStage() {
return stage;
}
}
Here are some photos that will help you understand the problem a little bit better:
Before the screen is resized(it doesn't matter how much the screen is resized):
http://i.gyazo.com/5cc675bde2fcbba7492bba69d4a419c6.png
After the screen is resized:
http://i.gyazo.com/d6814f3e15b903d59dab74b83e95292c.png
P.S Here is my render method inside the Game Screen class(I omitted all the irrelevant parts):
public void render(float delta) {
switch(state) {
case RUN:
// if The asset manager is done loading
if(AssetsManager.update() && !doneLoading) {
doneLoading = true;
hudManager = new HUDManager(stage);
stage.addActor(hudManager);
renderer = new GameRenderer(world, camera, batch);
loadingRenderer.dispose();
} else if(doneLoading) {
renderer.render(delta);
stage.draw();
stage.act(delta);
world.update(delta);
manager.update(delta);
}
// Display loading information
else
loadingRenderer.render(AssetsManager.getProgress()*100);
case PAUSE:
break;
}
}
EDIT: After playing a little bit with the code I found out that if I pause and then resume the game it causes the ImageButton to appear on the screen.

JavaFX How to change ProgressBar color dynamically?

I was trying to solve my problem with colored progress bars in this thread. The solution was present, but then I ran into another problem: I can't change color dynamically from my code. I want to do it right from my code, not with pre-defined .css. Generally I can do it, but I run into some difficulties when I try to do it with more than one progess bar.
public class JavaFXApplication36 extends Application {
#Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
ProgressBar pbRed = new ProgressBar(0.4);
ProgressBar pbGreen = new ProgressBar(0.6);
pbRed.setLayoutY(10);
pbGreen.setLayoutY(30);
pbRed.setStyle("-fx-accent: red;"); // line (1)
pbGreen.setStyle("-fx-accent: green;"); // line (2)
root.getChildren().addAll(pbRed, pbGreen);
Scene scene = new Scene(root, 150, 50);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
}
I always get 2 red progressbars with it! It seems that code in line (1) changes the style of ProgressBar class, not the instance.
Another strange moment is that deleting line (1) don't result in 2 green progress bars. So I can figure that line (2) is completely useless!! WHY?! That's definitely getting odd.
Is there any way to set different colors for separate progressbars?
See also the StackOverflow JavaFX ProgressBar Community Wiki.
There is a workaround you can use until a bug to fix the sample code in your question is filed and fixed.
The code in this answer does a node lookup on the ProgressBar contents, then dynamically modifies the bar colour of the progress bar to any value you like.
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class ProgressBarDynamicColor extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) {
PickedColorBar aquaBar = new PickedColorBar(0.4, Color.AQUA);
PickedColorBar fireBar = new PickedColorBar(0.6, Color.FIREBRICK);
HBox layout = new HBox(20);
layout.getChildren().setAll(aquaBar, fireBar);
layout.setStyle("-fx-background-color: -fx-box-border, cornsilk; -fx-padding: 15;");
stage.setScene(new Scene(layout));
stage.show();
aquaBar.wasShown();
fireBar.wasShown();
}
class PickedColorBar extends VBox {
private final ProgressBar bar;
private final ColorPicker picker;
private boolean wasShownCalled = false;
final ChangeListener<Color> COLOR_LISTENER = new ChangeListener<Color>() {
#Override public void changed(ObservableValue<? extends Color> value, Color oldColor, Color newColor) {
setBarColor(bar, newColor);
}
};
public PickedColorBar(double progress, Color initColor) {
bar = new ProgressBar(progress);
picker = new ColorPicker(initColor);
setSpacing(10);
setAlignment(Pos.CENTER);
getChildren().setAll(bar, picker);
}
// invoke only after the progress bar has been shown on a stage.
public void wasShown() {
if (!wasShownCalled) {
wasShownCalled = true;
setBarColor(bar, picker.getValue());
picker.valueProperty().addListener(COLOR_LISTENER);
}
}
private void setBarColor(ProgressBar bar, Color newColor) {
bar.lookup(".bar").setStyle("-fx-background-color: -fx-box-border, " + createGradientAttributeValue(newColor));
}
private String createGradientAttributeValue(Color newColor) {
String hsbAttribute = createHsbAttributeValue(newColor);
return "linear-gradient(to bottom, derive(" + hsbAttribute+ ",30%) 5%, derive(" + hsbAttribute + ",-17%))";
}
private String createHsbAttributeValue(Color newColor) {
return
"hsb(" +
(int) newColor.getHue() + "," +
(int) (newColor.getSaturation() * 100) + "%," +
(int) (newColor.getBrightness() * 100) + "%)";
}
}
}
The code uses inlined string processing of css attributes to manipulate Region backgrounds. Future JavaFX versions (e.g. JDK8+) will include a public Java API to manipulate background attributes, making obsolete the string processing of attributes from the Java program.
Sample program output: