I want to set Label to graphic. I tested this code:
private static final ImageView livePerformIcon;
static
{
livePerformIcon = new ImageView(MainApp.class.getResource("/images/Flex.jpg").toExternalForm());
}
final Label label = new Label();
label.setStyle("-fx-background-image: url(\"/images/Flex.jpg\");");
livePerformIcon.setFitHeight(20);
livePerformIcon.setFitWidth(20);
label.setGraphic(livePerformIcon);
But I don't see any image.
The only way that I found to make it work is this:
label.setStyle("-fx-background-image: url(\"/images/Flex.jpg\");");
Is there a way to solve this?
Not sure, but AFAIK controls should be created on the JavaFX Application thread, but you're creating ImageView in a static initializer, which I'm not sure if it's executed on the Application thread.
Besides: Do you really want livePerformIcon to be static???
This one made from the data used in the docs, works perfectly for me
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class LabelWithImages extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Label With Image Sample");
stage.setWidth(400);
stage.setHeight(180);
HBox hbox = new HBox();
//Replace the image you want to put up
Image image = new Image(getClass().getResourceAsStream("a.png"));
Label label = new Label("Demo Label");
label.setGraphic(new ImageView(image));
hbox.setSpacing(10);
hbox.getChildren().add((label));
((Group) scene.getRoot()).getChildren().add(hbox);
stage.setScene(scene);
stage.show();
}
}
Code snippets below will set the value of the property graphic of a label. You can use any of the two. I prefer using javafx css, just to implement the model-view-controller design.
// programmatically, provided with image input stream
label.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("path/to/image.png"))));
// javafx css, provided with image url
.label {
-fx-graphic: url("path/to/image.png");
}
Related
I have a question. I need to make a GridPane with a directory choose that will then lead me to a modal dialog showing photos. I cannot figure how to do the modal dialog that also has to be a GridPane or a HBox...so the question is , how do I get to show a Modal Dialog after selecting the Folder and pressing the "Show" Button... Thanks a lot!
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
public class FotoView extends Application {
#Override
public void start(Stage primaryStage) {
TextField tf = new TextField();
Button b1 = new Button("Search");
Button b2 = new Button("Show");
DirectoryChooser dc = new DirectoryChooser();
GridPane gp = new GridPane();
gp.add(tf, 0 , 0);
gp.add(b1, 1, 0);
gp.add(b2, 0, 1);
b1.setOnAction(e-> dc.showDialog(primaryStage));
primaryStage.setScene(new Scene(gp)) ;
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
} ```
Below is a quick example where a first window has a button that opens up a DirectoryChooser. Once a directory has been selected a second smaller window opens up with the Modality set to APPLICATION_MODAL. In this second window you could add the image(s) that you load and add them to the GridPane.
import java.io.File;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(final String[] args) {
launch(args);
}
#Override
public void start(final Stage aStage) throws Exception {
final HBox root = new HBox();
final Button browseBtn = new Button("Click to open a Directory chooser");
root.getChildren().add(browseBtn);
browseBtn.setOnAction(e -> {
final DirectoryChooser chooser = new DirectoryChooser();
final File dir = chooser.showDialog(aStage);
openNewModalStage(aStage, dir);
});
final Scene scene = new Scene(root, 500, 500);
aStage.setScene(scene);
aStage.show();
}
private void openNewModalStage(final Stage aStage, final File aDirectory) {
final Stage stage = new Stage();
final GridPane grid = new GridPane();
final Scene scene = new Scene(grid);
grid.setStyle("-fx-background-color:black");
grid.setPrefWidth(400);
grid.setPrefHeight(400);
// get your images from 'aDirectory' and add them to your grid pane.
stage.setScene(scene);
// set the new windows Modality.
stage.initModality(Modality.APPLICATION_MODAL);
stage.show();
}
}
This way you would only need the one button and the dialog would show as soon as you've selected a directory. However, if you would still want a Search and Show button then just store the directory as a variable and add a listener on the 'show' button and move the openNewModalStage call to that one and remove the second argument.
Edit:
Also, depending on how many images and exactly what you want to display in the modal window, you might want to reconsider the GridPane and use a TilePane, or an hbox/vbox inside of a scroll pane. It's just a thought but I don't know what you will be doing with the GridPane.
I am trying to implement the Slider such that user can drag only by given increments. I tried in different ways by using the Slider API, but didnt get the desired results. Below is a quick demo of what I had tried. I am expecting to drag the thumb only in increments of 10 not with intermediate values. snapToTicks is doing what I required, but only after finishing the drag. I am trying to not move the thumb till the next desired block increment is reached.
Can anyone let me know how can i achieve this. Below is the screenshot while dragging.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class SliderDemo extends Application {
public static void main(String... args){
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Label label = new Label();
label.setStyle("-fx-font-size:30px");
Slider slider = new Slider(5,240,5);
slider.setBlockIncrement(10);
slider.setMajorTickUnit(10);
slider.setMinorTickCount(0);
slider.setShowTickLabels(true);
slider.setShowTickMarks(true);
slider.setSnapToTicks(true);
slider.valueProperty().addListener((obs,old,val)->label.setText((int)Math.round(val.doubleValue())+""));
VBox root = new VBox(slider,label);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(20));
root.setSpacing(20);
Scene scene = new Scene(root,600,200);
stage.setScene(scene);
stage.show();
}
}
The solution is to set the value of the slider directly inside of the listener. The listener will not be called again
final ChangeListener<Number> numberChangeListener = (obs, old, val) -> {
final double roundedValue = Math.floor(val.doubleValue() / 10.0) * 10.0;
slider.valueProperty().set(roundedValue);
label.setText(Double.toString(roundedValue));
};
slider.valueProperty().addListener(numberChangeListener);
If you use Math.floor() instead of round you get a more intuatuive behavior of the thumb.
Can anyone tell me why sometimes JavaFX displays the content of a TextField with a blur effect on it? It seems to be random and occurs in any of my TextFields. Please see the image attached.
Focusing on the intermittent rendering artifact mentioned here, the 2 glyph looks like it's been rendered twice, with one copy shifted horizontally relative to the other. Such apparently random anomalies are notoriously difficult to identify. Myriad causes may include incorrect synchronization, improper layout, defects in the host platform's rendering pipeline, etc. For reference, the example below may allow you to test on disparate platforms.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* #see https://stackoverflow.com/a/53989899/230513
*/
public class TextFieldTest extends Application {
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("TextFieldTest");
BorderPane root = new BorderPane();
root.setCenter(createContent());
root.setBottom(createVersion());
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
private Node createContent() {
HBox row1 = new HBox(4);
Label channelsLabel = new Label("Channels:");
TextField channelsText = new TextField("2");
channelsText.setPrefWidth(32);
Label separatorLabel = new Label("Separator:");
TextField separatorText = new TextField("!");
separatorText.setPrefWidth(32);
row1.setPadding(new Insets(8));
row1.getChildren().addAll(
channelsLabel, channelsText, separatorLabel, separatorText);
HBox row2 = new HBox(4, new Label("Label:"), new TextField());
row2.setPadding(new Insets(8));
return new VBox(row1, row2);
}
private Label createVersion() {
Label label = new Label(
System.getProperty("os.name") + " v"
+ System.getProperty("os.version") + "; Java v"
+ System.getProperty("java.version"));
label.setPadding(new Insets(8));
return label;
}
public static void main(String[] args) {
launch(args);
}
}
As shown in the Modena example, an intentional blur effect indicates that the text field is focused:
The detail that gives rise to the blurred effect in your image is a compound border, seen below at 2x:
Comparable effects are seen here for buttons (top row) and default buttons (bottom row):
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Main extends Application {
#Override
public void start(Stage stage) {
try {
Scene pie;
Scene begin;
//pie scene
ObservableList<PieChart.Data> pieChartData=FXCollections.observableArrayList();
PieChart pieChart = new PieChart(pieChartData);
Button btBack = new Button("Back");
pieChart.setTitle("Test");
VBox container = new VBox(20);
container.getChildren().addAll(pieChart,btBack);
container.setAlignment(Pos.CENTER);
BorderPane pane = new BorderPane();
pane.setCenter(container);
pie =new Scene(pane,800,600);
//begin scene
VBox container2 = new VBox(20);
Button btPie = new Button("pie");
container2.getChildren().add(btPie);
BorderPane pane2 = new BorderPane();
container2.setAlignment(Pos.CENTER);
pane2.setCenter(container2);
begin=new Scene(pane2,50,50);
//handler
btPie.setOnAction(e->{
pieChartData.clear();
for(int i=0;i<5;++i)
pieChartData.add(new PieChart.Data(""+i, i));
stage.setScene(pie);
});
btBack.setOnAction(e->stage.setScene(begin));
stage.setScene(begin);
stage.show();
} catch (Exception e) {
e.printStackTrace(); // exception handling: print the error message on the console
}
}
public static void main(String[] args) {
launch(args);
}
}
With the above code, it first shows the stage with a button "pie". Clicking the button shows a pie chart with a button "back". The back button is used to go back to the initial screen.
The problem in this code is that after showing the pie chart for the second time, the pie chart's labels suddenly become crammed.
It can be seen with
1. click pie
2. click back
3. click pie -> problem shown
I can see that there is a problem, but I can't really see the reason. Furthermore, this problem only arise in java9; it works well in java8.
Can anyone find me the reason please?
The suggestion by JKostikiadis in the comment:
... you can fix the bug by adding container.layout(); after the for loop and before the stage.setScene(pie); in order to force the VBox to layout its children
helped me.
I need remove my javafx app from the taskbar. I tried StageStyle.UTILITY. This is works but I need both UNDECORATED and UTILITY stage styles or another solvings.
Thank you for your replies.
Sorry you've been waiting so long for some sort of an answer on this, the following is mainly for people who come to this in the future hoping to discover a way of achieving this.
Let me start of by saying I wouldn't consider the following a solution but more of a workaround.
Assigning more than one initStyle to a stage is not possible however hiding the application from the task-bar and assigning an initStyle other than utility to the stage that is shown is.
To achieve this one must create two stages, the stage they want the user to see, and an another stage that will be considered the parent of the main stage and will be of initStyle.UTILITY this will prevent the icon from showing in the task-bar.
Below you can see the hello world example from oracles documentation modified to allow for an undecorated window with no icon (Note if one wanted to achieve a transparent/decorated window they could do so by changing the style of mainStage).
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class MultipleStageStyles extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.initStyle(StageStyle.UTILITY);
primaryStage.setOpacity(0);
primaryStage.setHeight(0);
primaryStage.setWidth(0);
primaryStage.show();
Stage mainStage = new Stage();
mainStage.initOwner(primaryStage);
mainStage.initStyle(StageStyle.UNDECORATED);
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
mainStage.setScene(new Scene(root, 300, 250));
mainStage.show();
}
}