I m trying to print text and some lines that I put into a Group.
Depending on user action possible that it must be on multiple pages.
I tried many things all my Google links to this topic are marked as visited allready...
My problem is the thing with multiple pages .. i would like to do it without any scaling ..
Its also possible that a Group is not the right thing for it ,
but don´t know what would be better.
I hope somebody can help me ..
I added a short example of one way I tried it only prints one page...
public class Main extends Application {
private static Stage primaryStage; // **Declare static Stage**
#Override
public void start(Stage primaryStage) throws Exception{
setPrimaryStage(primaryStage);
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("SK");
primaryStage.setScene(new Scene(root, 1200, 800));
primaryStage.show();
drawStuff();
}
static public Stage getPrimaryStage() {
return Main.primaryStage;
}
private void setPrimaryStage(Stage stage) {
Main.primaryStage = stage;
}
public static void main(String[] args) {
launch(args);
}
Group[] root=new Group[10];
public void drawStuff(){
for(int i=0;i<=1;i++) {
root[i]=new Group();
final Text logo1 = new Text(60, 20, "TEST");
logo1.setFill(Color.BLACK);
logo1.setFont(Font.font(java.awt.Font.SANS_SERIF, FontWeight.BOLD, FontPosture.ITALIC, 18));
root[i].getChildren().add(logo1);
}
print();
}
private void print() {
PrinterJob job = PrinterJob.createPrinterJob();
for(int i=0;i<=1;i++) {
boolean success = job.printPage(root[i]);
if (success) {
job.endJob();
}
}
}
}
I want to set the divider of a SplitPane to a certain default position. This does not work, the divider stays in the middle:
public void start(Stage primaryStage) throws Exception{
SplitPane splitPane = new SplitPane(new Pane(), new Pane());
// Report changes to the divider position
splitPane.getDividers().get(0).positionProperty().addListener(
o -> System.out.println(splitPane.getDividerPositions()[0])
);
// Doesn't work:
splitPane.setDividerPositions(0.8);
// The docs seem to recommend the following (with floats instead of
// doubles, and with one number more than there are dividers, which is
// weird), but it doesn't work either:
//splitPane.setDividerPositions(0.8f, 0.2f);
primaryStage.setScene(new Scene(splitPane));
primaryStage.setMaximized(true);
primaryStage.show();
}
The output:
0.8
0.5
It suggests that something resets it to the middle.
How can I achieve this?
The issue seems to be that the divider position is reset when the SplitPane width is set during when the Stage is maximized. Set the divider positions afterwards by listening to the window's showing property as follows:
primaryStage.showingProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (newValue) {
splitPane.setDividerPositions(0.8);
observable.removeListener(this);
}
}
});
During Stage initialization, window size changes several times until layout is completed. Every change modifies divider positions. If you want to control divider positions, they have to be set after Stage is fully initialized:
private boolean m_stageShowing = false;
#Override
public void start(Stage primaryStage) throws Exception {
SplitPane splitPane = new SplitPane(new Pane(), new Pane());
ChangeListener<Number> changeListener = new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
splitPane.setDividerPositions(0.8);
if (m_stageShowing) {
observable.removeListener(this);
}
}
};
splitPane.widthProperty().addListener(changeListener);
splitPane.heightProperty().addListener(changeListener);
primaryStage.setScene(new Scene(splitPane));
primaryStage.setMaximized(true);
primaryStage.show();
m_stageShowing = true;
}
I had the same problem and the above solutions where not working reliably for me.
So I created a custom skin for SplitPane:
public class DumbSplitPaneSkin extends SplitPaneSkin {
public DumbSplitPaneSkin(SplitPane splitPane) {
super(splitPane);
}
#Override
protected void layoutChildren(double x, double y, double w, double h) {
double[] dividerPositions = getSkinnable().getDividerPositions();
super.layoutChildren(x, y, w, h);
getSkinnable().setDividerPositions(dividerPositions);
}
}
This skin can be used via css or by overriding SplitPane.createDefaultSkin(). You can also set programatically as splitPane.setSkin(new DumbSplitPaneSkin(splitPane));
As pointed out by others the issue is that the divider position is reset when the Stage is maximized.
You can prevent this by setting ResizableWithParent to false.
Example
Let's say you have a SplitPane with two nested containers inside. Here is the fxml extract:
<SplitPane fx:id="splitPane" dividerPositions="0.25">
<VBox fx:id="leftSplitPaneContainer" />
<FlowPane fx:id="rightSplitPaneContainer"/>
</SplitPane>
And here is the extract from the controller class:
#FXML
private SplitPane splitPane;
#FXML
private VBox leftSplitPaneContainer;
#FXML
private FlowPane rightSplitPaneContainer;
Then you simply can call SplitPane.setResizableWithParent() on both containers to prevent resetting the divider position:
public void initialize(){
SplitPane.setResizableWithParent(leftSplitPaneContainer, false);
SplitPane.setResizableWithParent(rightSplitPaneContainer, false);
}
The divider position will now remain at 0.25 even if you maximize the window.
No complicated listeners or overwriting of SplitPaneSkin involved.
You could just wrap the call setDividerPositions with
Platform.runLater(new Runnable() {
#Override
public void run() {
splitPane.setDividerPositions(0.8);
}
});
This is not 100% reliable solution because run() method is performed in JFX thread at unspecified time but it works properly for simple initialization cases.
Here is my result:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Orientation;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.*;
/**
* SplitPane, Dialogbox example
* #author Pataki István
*/
public class SimpleDocking extends Application {
private double splitPosition = 0;
private SplitPane rootPane = new SplitPane();
private MyDialog dialog;
private BorderPane dockedArea;
#Override
public void start(final Stage stage) throws Exception {
rootPane.setOrientation(Orientation.VERTICAL);
rootPane.setBorder(new Border(new BorderStroke(
Color.GREEN,
BorderStrokeStyle.SOLID,
new CornerRadii(5),
new BorderWidths(3))
));
dockedArea = new BorderPane(new TextArea("Some docked content"));
final FlowPane centerArea = new FlowPane();
final Button undockButton = new Button("Undock");
centerArea.getChildren().add(undockButton);
rootPane.getItems().addAll(centerArea, dockedArea);
stage.setScene(new Scene(rootPane, 300, 300));
stage.show();
dialog = new MyDialog(stage);
undockButton.disableProperty().bind(dialog.showingProperty());
undockButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
handler(stage);
}
});
}
private void handler(Stage stage) {
splitPosition = rootPane.getDividerPositions()[0];
rootPane.getItems().remove(dockedArea);
dialog.setOnHidden(windowEvent -> {
rootPane.getItems().add(dockedArea);
rootPane.setDividerPositions(splitPosition);
});
dialog.setContent(dockedArea);
dialog.show(stage);
}
private class MyDialog extends Popup {
private BorderPane root;
private MyDialog(Window parent) {
root = new BorderPane();
root.setPrefSize(200, 200);
root.setStyle("-fx-border-width: 1; -fx-border-color: gray");
root.setTop(buildTitleBar());
setX(parent.getX() + 50);
setY(parent.getY() + 50);
getContent().add(root);
}
public void setContent(Node content) {
root.setCenter(content);
}
private Node buildTitleBar() {
BorderPane pane = new BorderPane();
pane.setStyle("-fx-background-color: burlywood; -fx-padding: 5");
final Delta dragDelta = new Delta();
pane.setOnMousePressed(mouseEvent -> {
dragDelta.x = getX() - mouseEvent.getScreenX();
dragDelta.y = getY() - mouseEvent.getScreenY();
});
pane.setOnMouseDragged(mouseEvent -> {
setX(mouseEvent.getScreenX() + dragDelta.x);
setY(mouseEvent.getScreenY() + dragDelta.y);
});
Label title = new Label("My Dialog");
title.setStyle("-fx-text-fill: midnightblue;");
pane.setLeft(title);
Button closeButton = new Button("X");
closeButton.setOnAction(actionEvent -> hide());
pane.setRight(closeButton);
return pane;
}
}
private static class Delta {
double x, y;
}
public static void main(String[] args) throws Exception {
launch();
}
}
This is works like you wish.
Since you usually have at least something in splitpane, eg. vbox, just set min and max width and it will automatically set divider.
Platform.runlater(()->splitpane.setDividerPosition(0,0.8));
Absolutely does the trick for me. This sets the first split position of my horizontal splitpane to 80% of the parents width when opening the window.
While runlater() in many cases can lead JavaFX to do a little visible jitter at times, depending on the complexity of your GUI, in my case I haven't seen this happen.
Try
splitPane.setDividerPosition(0, percentage);
The parameters are setDividerPosition(int dividerIndex, double percentage)
I have a JavaFX TreeView/TreeCell that has a button as part of the TreeCell's graphic. I'd like to get the buttons to be right justified such that they appear as a column near the right edge of the scene, regardless of the level of the tree node or text width. I've attempted to add a spacer within the HBox that contains the button, but it doesn't appear to affect anything. Is there a simple way to accomplish what I want, or do I need to resort to something like calculating the space available for the tree cell and setting a preferred size on the HBox? Here's a simplified version of my code:
public class TreeCellAlignment extends Application {
private static class CustomTreeCell extends TreeCell<String> {
private HBox box = new HBox(4);
public CustomTreeCell() {
setContentDisplay(ContentDisplay.RIGHT);
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
box.getChildren().addAll(spacer, new Button("X"));
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? null : item);
setGraphic(empty ? null : box);
}
}
#Override
public void start(Stage primaryStage) {
TreeItem<String> root = new TreeItem<>("root");
root.getChildren().add(new TreeItem<>("child"));
TreeView<String> tree = new TreeView<>(root);
tree.setCellFactory(param -> new CustomTreeCell());
primaryStage.setScene(new Scene(tree, 300, 200));
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
I'm making chat application using JAVAFX. The messages displayed in textArea, but the textArea always in the same size. How can I make the textArea to fit exactly to the amount of text? TNX
The following code does exactly what You wants
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
AnchorPane root = new AnchorPane();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
TextArea ta=new TextArea();
ta.addEventHandler(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
// your algorithm to change height
ta.setPrefHeight(ta.getPrefHeight()+10);
}
});
root.getChildren().add(ta);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
i tried
public void ChangeFocus(Button browse, final FlowPane mFlowPane)
{
browse.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.TAB)
{
System.out.println("TAB pressed");
mFlowPane.requestFocus();
event.consume(); // do nothing
}
}
});
}
in above code i set one ImageView inside Flowpane but when i press TAB button on my browse button i can't get focus on imageview how can i solve it?
FlowPane is not focustraversable by default. Call mFlowPane.setFocusTraversable(true) to make it part of the traverse story
some more detail to solve it. instead of focusing the flowpane you need to set the focus on whats in the flowpane, for example a textfield:
flowPane.setOnMouseClicked(new EventHandler<MouseEvent>()
{
public void handle(MouseEvent mouseEvent)
{
textfield.requestFocus();
}
});