Is there a way to display an integer on the slider thumb in javafx? Just curious because I am trying to make a clean UI and cannot find anything on displaying an integer on the slider thumb.
One way to address the requirement is by accessing the thumb node and include a Text/Label node. Please check the below demo for what i mean.
You can adjust the thumb padding and the text size for fine tuning.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class SliderTextDemo extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Slider slider = new Slider(1, 10, 3);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setMajorTickUnit(1f);
slider.setBlockIncrement(1f);
slider.setSnapToTicks(true);
Text text = new Text();
slider.skinProperty().addListener((obs,old,skin)->{
if(skin!=null){
StackPane thumb = (StackPane)slider.lookup(".thumb");
thumb.setPadding(new Insets(10));
thumb.getChildren().add(text);
}
});
slider.valueProperty().addListener((obs,old,val)->text.setText(val.intValue()+""));
slider.setValue(2);
VBox root = new VBox(slider);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(20));
root.setSpacing(20);
Scene scene = new Scene(root,600,200);
primaryStage.setScene(scene);
primaryStage.setTitle("Slider Text Demo");
primaryStage.show();
}
}
UPDATE:
If you don't want to rely on accessing the skin,you can indeed implement/initialize the Slider as below. That way you can create a custom Slider and can reuse in multiple places.
Slider slider = new Slider(1, 10, 3) {
Text text;
#Override
protected void layoutChildren() {
super.layoutChildren();
if (text == null) {
text = new Text(((int) getValue()) + "");
valueProperty().addListener((obs, old, val) -> text.setText(val.intValue() + ""));
StackPane thumb = (StackPane) lookup(".thumb");
thumb.setPadding(new Insets(10));
thumb.getChildren().add(text);
}
}
};
Related
Is it possible with Popup opacity mask top and bottom JavaFX? I have TextField autocomplete with Popup. So the idea is to put an opacity mask.
Below is another way you can give a try, for getting the opacity masked effect. Though it is not exactly the same implementation, I took some ideas from the link you provided :).
I created a small utility where you can pass the Popup instance. The utility builds the mask panes and include to the root node of the Popup.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class PopupOpacityMaskDemo extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
root.setStyle("-fx-background-color:grey;");
root.setOnMouseClicked(e -> {
ListView<String> content = new ListView<>();
content.getItems().addAll(IntStream.range(100, 200).mapToObj(i -> i + "").collect(Collectors.toList()));
content.setPrefSize(200, 250);
Popup popup = new Popup();
popup.setAutoHide(true);
popup.getContent().add(content);
popup.setX(e.getScreenX());
popup.setY(e.getScreenY());
popup.show(root.getScene().getWindow());
MaskUtil.applyMask(popup);
});
Scene scene = new Scene(root, 200, 200);
primaryStage.setScene(scene);
primaryStage.setTitle("Demo");
primaryStage.show();
}
static class MaskUtil{
static void applyMask(Popup popup) {
double fadeSize = 70;
Pane pane = (Pane)popup.getScene().getRoot();
// Build the mask panes
Pane topMask = buildMaskPane(pane, fadeSize, false);
Pane bottomMask = buildMaskPane(pane, fadeSize, true);
// Just ensuring to remove any masks (if you are reusing the Popup)
pane.getChildren().removeAll(pane.lookupAll(".mask"));
pane.getChildren().addAll(topMask, bottomMask);
// Update the bottom mask position by listening to height of pane
pane.heightProperty().addListener((obs, old, h) -> bottomMask.setLayoutY(h.doubleValue() - fadeSize));
if (pane.getHeight() > 0) {
bottomMask.setLayoutY(pane.getHeight() - fadeSize);
}
}
private static Pane buildMaskPane(Pane pane, double fadeSize, boolean isBottom) {
Pane mask = new Pane();
mask.setMouseTransparent(true); // Turn this to 'false' if you don't want to interact over mask
mask.setPrefHeight(fadeSize);
mask.prefWidthProperty().bind(pane.widthProperty());
mask.maxHeightProperty().bind(mask.prefHeightProperty());
mask.minHeightProperty().bind(mask.prefHeightProperty());
mask.getStyleClass().add("mask");
mask.setStyle(String.format("-fx-background-color:linear-gradient(to %s, #555555, transparent)", isBottom ? "top" : "bottom"));
return mask;
}
}
}
When I translate a node outside of the bounds of it's parent. The minimum size of the parent of the parent is set to it's current size. You can see it with this demo:
package com.neonorb.test;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.io.IOException;
/**
* Created by chris on 7/20/15.
*/
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
Label label = new Label("translating label");
Label markerLabel = new Label("marker label");
Button button = new Button("button");
VBox leftSpace = new VBox();
Label leftLabel = new Label("left space");
leftSpace.getChildren().add(leftLabel);
Rectangle rectangle = new Rectangle();
rectangle.setFill(Color.RED);
rectangle.heightProperty().bind(leftSpace.heightProperty());
rectangle.widthProperty().bind(leftSpace.widthProperty());
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
new Thread() {
public void run() {
Platform.runLater(() -> label.setTranslateY(1000.0));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Platform.runLater(() -> label.setTranslateY(0.0));
}
}.start();
}
});
BorderPane borderPane = new BorderPane();
BorderPane center = new BorderPane();
center.setCenter(label);
center.setBottom(markerLabel);
borderPane.setCenter(center);
borderPane.setTop(button);
borderPane.setLeft(leftSpace);
borderPane.setRight(rectangle);
primaryStage.setScene(new Scene(borderPane));
primaryStage.show();
}
}
The reason for the side bar things (the VBox and Rectangle) is because they exist in my real application. The VBox just holds more content, and the Rectangle is there to keep the center components centered (normally transparent, but here it is colored for visibility). As you can see, the width and height of the rectangle are binded to the VBox's height:
rectangle.heightProperty().bind(leftSpace.heightProperty());
rectangle.widthProperty().bind(leftSpace.widthProperty());
To reproduce the problem, you can increase the height of the window a little (about an inch), then hit the button. The node will be translated down 1000 pixels and back. Now try to shrink the window, the text at the bottom, ("marker label"), will start to be hidden by the bottom of the window.
I fixed it by using a Region instead of a Rectangle and setting it's preferred size.
I was wondering how to make the caret visible and/or flash whilst using a TextField or TextArea. The ones I have created in my GUI work as the letters appear when typed but there is no visible caret.
I've looked through the TextField documentation but none are about making it visible or not. I expected to find something along the lines "setCaretVisible(Boolean);"
Do I have to make it visible via CSS? If so, any suggestions would be most welcome!
Please see code that I've quickly put together to illustrate the problem:
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Test extends Application {
public static void main(String[] arguments) { launch(arguments); }
#Override public void start(Stage stage) {
Scene scene = new Scene(new Group());
scene.setRoot(new BuildLayout(stage));
stage.setTitle("Application Name");
stage.setScene(scene);
stage.initStyle(StageStyle.UNDECORATED);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setFullScreen(true);
stage.setFullScreenExitHint("");
stage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
stage.show();
}
}
final class BuildLayout extends BorderPane {
protected BuildLayout(Stage stage) {
TabPane tabpane = new TabPane();
Tab tab = new Tab();
tab.setGraphic(new Text("Video Browser"));
tab.setClosable(false);
tab.setContent(new Input(1));
tabpane.getTabs().addAll(tab);
setTop(new Toolbar(stage));
setCenter(tabpane);
}
}
final class Input extends VBox {
Input(int id) {
HBox hbox = new HBox();
TextField videoTitle = new TextField("video_title");
TextArea description = new TextArea( "video_description");
Button share = new Button("share");
Button unshare = new Button("unshare");
setPadding(new Insets(5,10,10,5));
setAlignment(Pos.TOP_CENTER);
hbox.getChildren().addAll(videoTitle, new Text(" Creator: " + " Date: " + " Views: " + " "));
if(true) {
videoTitle.setEditable(true);
description.setEditable(true);
if(true) {
hbox.getChildren().add(share);
} else { hbox.getChildren().add(unshare); }
}
getChildren().addAll(hbox, description);
}
}
final class Toolbar extends HBox {
protected Toolbar(Stage stage) {
Button close = new Button("close");
close.setOnAction((ActionEvent e) -> { stage.close(); });
setAlignment(Pos.CENTER_LEFT);
getChildren().addAll(close);
}
}
Many thanks,
This problem only occurs on Mac and not Windows (untested Linux). The fix is to downgrade to a JavaFX 2.2 compliant maximised window as the setMaximized() from JavaFX 8 also isn't Mac compatible.
Modifying the start method with some code found here:
#Override public void start(Stage stage) {
Scene scene = new Scene(new Group());
scene.setRoot(new BuildLayout(stage));
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getVisualBounds();
stage.setTitle("Application Name");
stage.setScene(scene);
stage.setX(bounds.getMinX());
stage.setY(bounds.getMinY());
stage.setWidth(bounds.getWidth());
stage.setHeight(bounds.getHeight());
stage.show();
}
Produces a fullscreen application with visible and flashing caret.
When there is no record in any table it shows a message 'No content in table', which is by default functionality of TableView in JavaFx.
So here my question is, does the same can be possible with ListView in JavaFx ? Like, if there is no item in any ListView then it will show a message same as TableView, instead of a blank/empty fields.
You have to try this:-
listView.setPlaceholder(new Label("No Content In List"));
its 100% working....
JavaFX8 has a setPlaceholder(...) method for ListView.
In earlier versions, you need to roll your own somehow. This is a bit of a hack: it wraps the ListView in a stack pane, with a white rectangle and the placeholder displayed over the top of the list view. The placeholder and rectangle have their visible property bound, so they are only visible if the list is empty.
There may be easier ways that I'm not seeing right away...
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ListViewPlaceholderTest extends Application {
#Override
public void start(Stage primaryStage) {
final ListView<String> listView = new ListView<>();
final IntegerProperty counter = new SimpleIntegerProperty();
final Button addButton = new Button("Add item");
addButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
counter.set(counter.get()+1);
listView.getItems().add("Item "+counter.get());
}
});
final Button removeButton = new Button("Remove");
removeButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
listView.getItems().remove(listView.getSelectionModel().getSelectedIndex());
}
});
removeButton.disableProperty().bind(Bindings.equal(listView.getSelectionModel().selectedIndexProperty(), -1));
final HBox buttons = new HBox(5);
buttons.setPadding(new Insets(10));
buttons.getChildren().addAll(addButton, removeButton);
final BorderPane root = new BorderPane();
root.setCenter(createPlaceholderForListView(listView, new Label("No content in List")));
root.setBottom(buttons);
final Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private Node createPlaceholderForListView(ListView<?> listView, Node placeholder) {
final StackPane pane = new StackPane();
final Rectangle rect = new Rectangle(0, 0, Color.WHITE);
rect.widthProperty().bind(listView.widthProperty());
rect.heightProperty().bind(listView.heightProperty());
pane.getChildren().addAll(listView, rect, placeholder);
placeholder.visibleProperty().bind(Bindings.isEmpty(listView.getItems()));
rect.visibleProperty().bind(placeholder.visibleProperty());
rect.setMouseTransparent(true);
return pane ;
}
}
With fxml:
<ListView fx:id="foundContentList">
<placeholder>
<Label text="Nothing found" />
</placeholder>
</ListView>
Not entirely sure but I don't think there is a setPlaceholder method(to set the default message when no content in table) for ListView.
The workaround that I use is to create an Object in the list that indicate "No content" and show that on the listview and also disable it.
For example:
ObservableList noContent= FXCollections.observableArrayList("No content found");
ListView listView = new ListView(noContent);
listView.setDisable(true);
I want to create tabs panel with icons similar to the Firefox configuration panel with JavaFX:
Is there any example which I can use to see how to implement this?
Tabs, like many other elements in JavaFX, have a method called setGraphic(Node value), in which you can put any JavaFX node. Example:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
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.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class TabPaneTest extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tabs");
Group root = new Group();
Scene scene = new Scene(root, 400, 250, Color.WHITE);
TabPane tabPane = new TabPane();
BorderPane borderPane = new BorderPane();
for (int i = 0; i < 5; i++) {
Tab tab = new Tab();
tab.setGraphic(new Circle(0, 0, 10));
HBox hbox = new HBox();
hbox.getChildren().add(new Label("Tab" + i));
hbox.setAlignment(Pos.CENTER);
tab.setContent(hbox);
tabPane.getTabs().add(tab);
}
// bind to take available space
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
borderPane.setCenter(tabPane);
root.getChildren().add(borderPane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Result:
I know its an old thread, but i didnt find a direct answer anywhere. So i thought of posting it some that it will be helpfull for some searching for it.
This is what i did to get a tab like firefox preferences screen.
Add the image to the tab with setGraphics and add the following code to the application css file. My image size was 48x48. So i went for height as 70.
.tab-label {
-fx-content-display: top;
}
.tab-pane {
-fx-tab-min-height: 70;
-fx-tab-max-height: 70;
}
How to add image directly from image url:
Tab tab = new Tab();
tab.setGraphic(buildImage("patch/to/image");
// Helper method to create image from image patch
private static ImageView buildImage(String imgPatch) {
Image i = new Image(imgPatch);
ImageView imageView = new ImageView();
//You can set width and height
imageView.setFitHeight(16);
imageView.setFitWidth(16);
imageView.setImage(i);
return imageView;
}