How to fix trembling text with right-align? - javafx

I use Label on JavaFX8 with right-align to enter numbers one by one. The problem is that the text is trembling.
Application running on Ubuntu 18.04, JRE 1.8.0_211. Font used "Roboto Mono", but problem has with any font. I tried using TextField, but the situation is the same. Noticed that there are no problems with left align.
public class AppExample extends Application {
#Override
public void start(Stage primaryStage) {
Label label = new Label();
label.setStyle("-fx-background-color: #ccffcc; -fx-font-weight:bold; -fx-font-size: 24pt");
label.setAlignment(Pos.CENTER_RIGHT);
label.setMaxWidth(Double.MAX_VALUE);
VBox vBox = new VBox(label);
vBox.setFillWidth(true);
vBox.setAlignment(Pos.CENTER);
vBox.setStyle("-fx-background-color: #000");
primaryStage.setScene(new Scene(vBox, 400, 100));
primaryStage.getScene().setOnKeyPressed(event -> {
if (event.getCode().equals(KeyCode.BACK_SPACE)) {
int length = label.getText().isEmpty() ? 0 : label.getText().length()-1;
label.setText(label.getText().substring(0, length));
} else label.setText(label.getText() + event.getText());
});
primaryStage.show();
}
}
I expect that the text should be entered without trembling, what are the possible solutions to the problem?

Related

Blurry text appearance after some JavaFX TextArea manipulations

I see a strange appearance of the text contained in a TextArea aftrer doing some changes of TextArea content and style.
With the simplified code shown below I reproducibly see this when I click the button 4 times:
But this is what I expected to see:
Note: If I then click into the TextArea I see the expected result.
What can can be done to get the expected result?
Note that I need to set textarea min/max width and height to get a nice appearance of the content.
Of course I could set it to a bigger value, but that would destroy the look that is required.
I tried setCache as proposed here but that did not work.
I have JavaFX-8 on Windows 8.1. I would also be interested what results are seen in newer versions.
EDIT
With JavaFX-13 the result is:
The text seems to be moved to the right instead of centered as specified in the css (and also to the bottom). I had ecpected that the text is postioned the same as on initial start of the application.
CSS:
.text-area-centered *.text {
-fx-text-alignment: center ;
}
.text-area-centered .scroll-pane {
-fx-hbar-policy: NEVER;
-fx-vbar-policy: NEVER;
}
Java:
public class Main extends Application {
private static final BackgroundFill blackBGF = new BackgroundFill(Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY);
private static final BackgroundFill whiteBGF = new BackgroundFill(Color.WHITE, CornerRadii.EMPTY, Insets.EMPTY);
private static double textareaXY = 50;
private TextArea textarea = new TextArea();
private int clickNo = 1;
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
VBox vb = new VBox();
root.setCenter(vb);
Button b = new Button("ClickMe");
b.addEventHandler(ActionEvent.ACTION, this::OnClickButton);
vb.getChildren().add(b);
vb.getChildren().add(textarea);
textarea.setEditable(false);
textarea.getStyleClass().add("text-area-centered");
textarea.setBackground(new Background(blackBGF));
textarea.setMinHeight(textareaXY);
textarea.setMaxHeight(textareaXY);
textarea.setMinWidth(textareaXY);
textarea.setMaxWidth(textareaXY);
textarea.setFont(new Font("Courier New",10));
textarea.setText("1 2 3\n4 5 6\n7 8 9");
primaryStage.show();
}
private void OnClickButton(ActionEvent event)
{
if(clickNo == 1)
{
textarea.setText("7");
textarea.setFont(new Font("Courier New Bold",24));
}
else if(clickNo == 2)
{
Region region = ( Region ) textarea.lookup( ".content" );
region.setBackground(new Background(blackBGF));
textarea.setStyle("-fx-text-inner-color: white;");
}
else if(clickNo == 3)
{
Region region = ( Region ) textarea.lookup( ".content" );
region.setBackground(new Background(whiteBGF));
textarea.setStyle("-fx-text-inner-color: black;");
}
else if(clickNo == 4)
{
textarea.setText("1 2 3\n4 5 6\n7 8 9");
textarea.setFont(new Font("Courier New",10));
}
clickNo++;
}
public static void main(String[] args) {
launch(args);
}
}

javafx - Navigation Sidebar with Toggle

So in windows 10 you have the windows menu with the icons on the left side:
When clicking on the hamburger icon the menu expands and text is show.
The expanded part is overlaying the content. The text is showing. and it was animated in (sliding transition).
In my application I want to make a similar menu on the right side (see blue part):
I have absolutely no idea how to get this effect. Currently I made a button with a graphic. I only display the graphic and when I click on the hamburger I show all the text by changing the setContentDisplay(ContentDisplay.GRAPHIC_ONLY) to setContentDisplay(ContentDisplay.RIGHT) 2 things that are wrong with this approach.
it pushes the content.
You cannot add a transition.
Any help would be appreciated, especially examples.
Demo
I made a demo that shows what I currently have:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
JFXButton[] jfxButtons = {
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
};
JFXHamburger hamburger = new JFXHamburger();
HamburgerNextArrowBasicTransition transition = new HamburgerNextArrowBasicTransition(hamburger);
transition.setRate(-1);
hamburger.setAlignment(Pos.CENTER_RIGHT);
hamburger.setPadding(new Insets(5));
hamburger.setStyle("-fx-background-color: #fff;");
hamburger.setOnMouseClicked(event -> {
transition.setRate(transition.getRate() * -1);
transition.play();
if (transition.getRate() == -1) {
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
} else {
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setContentDisplay(ContentDisplay.RIGHT);
}
}
});
ScrollPane scrollPane = new ScrollPane();
VBox vBox = new VBox();
scrollPane.setContent(vBox);
vBox.getStyleClass().add("content_scene_right");
vBox.getChildren().add(hamburger);
vBox.getChildren().addAll(jfxButtons);
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setMaxWidth(Double.MAX_VALUE);
jfxButton.setRipplerFill(Color.valueOf("#40E0D0"));
VBox.setVgrow(jfxButton, Priority.ALWAYS);
jfxButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
vBox.setFillWidth(true);
Label labelHoverOverTest = new Label("Testing label");
VBox vbox2 = new VBox();
vbox2.getChildren().addAll(labelHoverOverTest);
vbox2.setAlignment(Pos.CENTER_RIGHT);
root.setRight(scrollPane);
root.setCenter(vbox2);
Scene scene = new Scene(root);
primaryStage.setMinWidth(400);
primaryStage.setMinHeight(400);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I used JFoenix and fontawesomefx for this demo, but it can also be javafx scene buttons with any graphic.
Here are some images of what the demo looks like:
As you can see it pushes it the content in the center and I can't add any transition.
(here is a sample from bootstrap to give you an idea on What I'm trying to make it look like 1: https://bootsnipp.com/snippets/Pa9xl, 2: https://bootsnipp.com/snippets/featured/navigation-sidebar-with-toggle (with this one the content still moves, but it should give you a clear idea on what my vision is))
Problem is that you are using BorderPane and placing everything on same layer, so when content on right changes width it will affect one in the center and such.
In other to avoid this you should make it layered, so for root of view use StackPane, this pane should have 2 children, 1 for main content and 1 for sidebar, make sure that sidebar is above main content, now this 2 can be any Pane that you want. This way sidebar will be placed over main content and it won't push content.
Using code you provided and just adding StackPane you get something like this:
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
BorderPane mainContent = new BorderPane();
BorderPane sidebar = new BorderPane();
JFXButton[] jfxButtons = {
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),};
JFXHamburger hamburger = new JFXHamburger();
HamburgerNextArrowBasicTransition transition = new HamburgerNextArrowBasicTransition(hamburger);
transition.setRate(-1);
hamburger.setAlignment(Pos.CENTER_RIGHT);
hamburger.setPadding(new Insets(5));
hamburger.setStyle("-fx-background-color: #fff;");
hamburger.setOnMouseClicked(event -> {
transition.setRate(transition.getRate() * -1);
transition.play();
if (transition.getRate() == -1) {
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
} else {
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setContentDisplay(ContentDisplay.RIGHT);
}
}
});
ScrollPane scrollPane = new ScrollPane();
VBox vBox = new VBox();
scrollPane.setContent(vBox);
vBox.getStyleClass().add("content_scene_right");
vBox.getChildren().add(hamburger);
vBox.getChildren().addAll(jfxButtons);
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setMaxWidth(Double.MAX_VALUE);
jfxButton.setRipplerFill(Color.valueOf("#40E0D0"));
VBox.setVgrow(jfxButton, Priority.ALWAYS);
jfxButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
vBox.setFillWidth(true);
Label labelHoverOverTest = new Label("Testing label");
VBox vbox2 = new VBox();
vbox2.getChildren().addAll(labelHoverOverTest);
vbox2.setAlignment(Pos.CENTER_RIGHT);
mainContent.setCenter(vbox2);
sidebar.setRight(scrollPane);
root.getChildren().addAll(mainContent, sidebar);
Scene scene = new Scene(root);
primaryStage.setMinWidth(400);
primaryStage.setMinHeight(400);
primaryStage.setScene(scene);
primaryStage.show();
}
As for transition I'm not sure what is problem there, for me it works fine.

Set different size of button text lines, css, javafx

I made a button using scenebuilder which has two lines of text inside (first line is the function for button, and second one is a little explanation), and I would like to set different sizes for them, through css. Is this possible in any way, or is there more practical way for doing this?
Thank you for your help.
You cannot achieve this with a single text element like the one used for the button text, but you can add a Label as graphic and apply different text sizes via css:
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Text");
Label explanation = new Label("This is the explanation");
explanation.getStyleClass().add("explanation");
btn.setGraphic(explanation);
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 300);
scene.getStylesheets().add(getClass().getResource("explanation.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
explanation.css
.button {
-fx-font-size: 20;
-fx-content-display: bottom;
}
.button>.explanation {
-fx-font-size: 10;
}

JavaFX Right Coordinate of a CustomMenuItem

I have a Class that extends the CustomMenuItem. This MenuItems are added to a ContextMenu. Now i need to get the X-Coordinates from the right side of the CustomMenuItem.
The Problem is, that I have no idea how I can get the Coordinates.
The CustMenuItem has no function for getting the Coordinates like getX() or getY().
So how can I solve this problem?
This thing I would like to get:
Here we can see a Sample for a Context Menu (red lines). In the Context Menu are a lot of different CustomMenuItems implemented. Now I would like to get the right top corner Coordinate of the CustomMenuItem.
Thank you for your very nice help.
Before dealing with menu items, let's start saying that a ContextMenu is a popup window, so it has Windowproperties. You can ask for (x,y) left, top origin, and for (w,h).
But you have to take into account the effects, since by default it includes a dropshadow. And when it does, there's an extra space added of 24x24 pixels to the right and bottom.
.context-menu {
-fx-effect: dropshadow( gaussian , rgba(0,0,0,0.2) , 12, 0.0 , 0 , 8 );
}
Since this default dropshadow has a radius of 12px, and Y-offset to the bottom of 8px, the right and bottom coordinates of the context menu, including the 24x24 area, are given by:
X=t.getX()+cm.getWidth()-12-24;
Y=t.getY()+cm.getHeight()-(12-8)-24;
where t could be a MouseEvent relative to the scene, and values are hardcoded for simplicity.
Let's see this over an example. Since you don't say how your custom menu items are implemented, I'll just create a simple Menu Item with graphic and text:
private final Label labX = new Label("X: ");
private final Label labY = new Label("Y: ");
#Override
public void start(Stage primaryStage) {
final ContextMenu cm = new ContextMenu();
MenuItem cmItem1 = createMenuItem("mNext", "Next Long Option",t->System.out.println("next"));
MenuItem cmItem2 = createMenuItem("mBack", "Go Back", t->System.out.println("back"));
SeparatorMenuItem sm = new SeparatorMenuItem();
cm.getItems().addAll(cmItem1,cmItem2);
VBox root = new VBox(10,labX,labY);
Scene scene = new Scene(root, 300, 250);
scene.setOnMouseClicked(t->{
if(t.getButton()==MouseButton.SECONDARY || t.isControlDown()){
// t.getX,Y->scene based coordinates
cm.show(scene.getWindow(),t.getX()+scene.getWindow().getX()+scene.getX(),
t.getY()+scene.getWindow().getY()+scene.getY());
labX.setText("Right X: "+(t.getX()+cm.getWidth()-12-24));
labY.setText("Bottom Y: "+(t.getY()+cm.getHeight()-4-24));
}
});
scene.getStylesheets().add(getClass().getResource("root.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setTitle("Scene: "+scene.getWidth()+"x"+scene.getHeight());
}
private MenuItem createMenuItem(String symbol, String text, EventHandler<ActionEvent> t){
MenuItem m=new MenuItem(text);
StackPane g=new StackPane();
g.setPrefSize(24, 24);
g.setId(symbol);
m.setGraphic(g);
m.setOnAction(t);
return m;
}
If you remove the effect:
.context-menu {
-fx-effect: null;
}
then these coordinates are:
X=t.getX()+cm.getWidth();
Y=t.getY()+cm.getHeight();
Now that we have the window, let's go into the items.
MenuItem skin is derived from a (private) ContextMenuContent.MenuItemContainer class, which is a Region where the graphic and text are layed out.
When the context menu is built, all the items are wrapped in a VBox, and all are equally resized, as you can see if you set the border for the item:
.menu-item {
-fx-border-color: black;
-fx-border-width: 1;
}
This is how it looks like:
So the X coordinates of every item on the custom context menu are the same X from their parent (see above, with or without effect), minus 1 pixel of padding (by default).
Note that you could also go via private methods to get dimensions for the items:
ContextMenuContent cmc= (ContextMenuContent)cm.getSkin().getNode();
System.out.println("cmc: "+cmc.getItemsContainer().getBoundsInParent());
Though this is not recommended since private API can change in the future.
EDIT
By request, this is the same code removing lambdas and css.
private final Label labX = new Label("X: ");
private final Label labY = new Label("Y: ");
#Override
public void start(Stage primaryStage) {
final ContextMenu cm = new ContextMenu();
MenuItem cmItem1 = createMenuItem("mNext", "Next Long Option",action);
MenuItem cmItem2 = createMenuItem("mBack", "Go Back", action);
SeparatorMenuItem sm = new SeparatorMenuItem();
cm.getItems().addAll(cmItem1,cmItem2);
VBox root = new VBox(10,labX,labY);
Scene scene = new Scene(root, 300, 250);
scene.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
if(t.getButton()==MouseButton.SECONDARY || t.isControlDown()){
// t.getX,Y->scene based coordinates
cm.show(scene.getWindow(),t.getX()+scene.getWindow().getX()+scene.getX(),
t.getY()+scene.getWindow().getY()+scene.getY());
labX.setText("Right X: "+(t.getX()+cm.getWidth()-12-24));
labY.setText("Bottom Y: "+(t.getY()+cm.getHeight()-4-24));
}
}
});
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setTitle("Scene: "+scene.getWidth()+"x"+scene.getHeight());
}
private MenuItem createMenuItem(String symbol, String text, EventHandler<ActionEvent> t){
MenuItem m=new MenuItem(text);
StackPane g=new StackPane();
g.setPrefSize(24, 24);
g.setId(symbol);
SVGPath svg = new SVGPath();
svg.setContent("M0,5H2L4,8L8,0H10L5,10H3Z");
m.setGraphic(svg);
m.setOnAction(t);
return m;
}
private final EventHandler<ActionEvent> action = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("action");
}
};

Change label javafx on keyboard input

I would like a javafx label to be automatically updated to what is being typed into a textfield, currently i have it changing only when enter is clicked. I am using a mix of swing and javafx.
is this possible?
thanks
exprField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Platform.runLater(new Runnable() {
#Override
public void run() {
fxLabel.setText(exprField.getText());
}
});
}
});
You can use the Binding-Mechanism for this purpose.
GridPane p = new GridPane();
TextField tf = new TextField("DEFAULT");
Label l1 = new Label("...");
l1.textProperty().bind(tf.textProperty());
p.add(tf, 0, 0);
p.add(l1, 1, 0);
Scene sc = new Scene(p, 500, 500);
arg0.setScene(sc);
arg0.show();
This code sets a textbox and a label into a gridpane. The text property of the label is bound to the text property of the textfield, which means as soon as the textfields changes, the text of the label gets updated according to whatever text is now in the textfield.
More information can be found here: http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm

Resources