I have an anchorPane which is a child of a ScrollPane. Now I have a Button which scales the anchorPane. This means the button create a zoom effect. But when the anchorPane has another dimension the scrollPane doesn’t realize the changed size of anchorPane and the scrollbars do not become bigger or smaller. Here is my code:
public class View implements Observer{
private Model model;
private Stage stage;
private Button plus;
private Button minus;
Affine affine = new Affine();
ScrollPane scrollPane;
public View (Model model, Stage stage) {
model.addObserver(this);
this.model = model;
this.stage = stage;
this.plus = new Button("+");
this.minus = new Button("-");
HBox hBox = new HBox(2);
VBox vBox = new VBox();
AnchorPane anchorPane = new AnchorPane();
SVGPath svgTest = new SVGPath();
svgTest.setContent(model.getShapes());
anchorPane.getChildren().add(svgTest);
anchorPane.getTransforms().add(affine);
scrollPane = new ScrollPane(anchorPane);
scrollPane.setFitToHeight(true);
scrollPane.setFitToWidth(true);
scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
hBox.getChildren().add(plus);
hBox.getChildren().add(minus);
SplitPane root = new SplitPane(scrollPane);
root.setOrientation(Orientation.VERTICAL);
root.setDividerPositions(0.85);
scrollPane.setVvalue( 1.0d );
root.getItems().add(hBox);
Scene scene = new Scene(root, 1000, 1000);
stage.setScene(scene);
stage.setTitle("myStage");
stage.show();
}
public Stage getStage() {
return stage;
}
public Button getZoomPlusButton() {
return plus;
}
public Button getZoomMinusButton() {
return minus;
}
public void zoomPlus() {
affine.append(new Scale(1.1, 1.1));
}
public void zoomMinus() {
affine.append(new Scale(0.9, 0.9));
}
#Override
public void update(Observable o, Object arg) {
}
}
How can I fix my problem?
Thank you in advance.
The documentation has
ScrollPane layout calculations are based on the layoutBounds rather than the boundsInParent (visual bounds) of the scroll node. If an application wants the scrolling to be based on the visual bounds of the node (for scaled content etc.), they need to wrap the scroll node in a Group.
So all you need is to wrap the scroll pane content in a Group:
scrollPane = new ScrollPane(new Group(anchorPane));
Related
I want to create simple TextArea with RIGHT_TO_LEFT nodeOrientation. It's done.
But when I resize main container(window) promptText in rightTextArea doesn't move with a right textArea border. The same with a cursor.
public class RightToLeft extends Application {
#Override public void start(final Stage primaryStage) throws Exception {
final VBox vbox = new VBox(10);
vbox.setPadding(new Insets(10));
TextArea textArea = new TextArea();
textArea.setPromptText("hello world");
TextArea rightTextArea = new TextArea();
rightTextArea.setPromptText("Hello world");
rightTextArea.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
TextField textField = new TextField();
textField.setPromptText("Text field prompt");
textField.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
vbox.getChildren().addAll(textArea, rightTextArea, textField);
primaryStage.setScene(new Scene(vbox));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you have any ideas, please, share :-) Thanks
So, I'm trying to switch scenes in JavaFX but I can't seem to get it to work when I hard coded it I was able to get it working by using lambda expressions.
public class Main extends Application {
Stage window;
Scene scene1;
Scene scene2;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
Label label = new Label("Welcome to the first scene");
Button bttn1 = new Button("Go to second scene");
bttn1.setOnAction(e -> window.setScene(scene2));
//Scene 1
VBox layout1 = new VBox(20);
layout1.getChildren().addAll(label, bttn1);
scene1 = new Scene(layout1, 400, 400);
//Scene 2
Button bttn2 = new Button("Go to first scene");
bttn2.setOnAction(e -> window.setScene(scene1));
StackPane layout2 = new StackPane();
layout2.getChildren().add(bttn2);
scene2 = new Scene(layout2, 400, 500);
window.setScene(scene1);
window.setTitle("Test");
window.show();
}
However the project involves a few different GUIs and I would prefer to design the GUI's in FXML Scene Builder than to hardcode them the FX way. However when I have tried to do the FXML way it hasn't worked an error is always appearing when I press the button.
Error message
This is the document controller code.
public class FXMLDocumentController implements Initializable {
#FXML
private Button button1;
#FXML
private Button button2;
#FXML
private void handleButtonAction(ActionEvent event) throws IOException {
Stage stage;
Parent root;
if(event.getSource() == button1){
stage=(Stage)button1.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("FXML2.fxml"));
}
else{
stage=(Stage)button2.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
}
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
The error you posted says the code is trying to load a button as an anchor pane. Check too see if you have an anchorpane with the fx:I'd of button1.
I would like to make a small java fx app that has just textarea and one button on a stage and that when you type some strings in textarea and press submit it shows on the stage small table with results how many each Word had occurrences.
so my questions is: does map is the best solution for finding the occurrences even though I do not know what will be the key for finding occurrences and how to connect string from text area, to map.
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Word counting");
TextArea txt=new TextArea();
txt.setMaxSize(450, 200);
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
primaryStage.hide();
ShowResults.drugiProzor();
}
});
BorderPane root = new BorderPane();
root.setTop(txt);
HBox hbox=new HBox();
hbox.setPadding(new Insets(20,20,100,180));
hbox.getChildren().add(btn);
root.setBottom(hbox);
Scene scene = new Scene(root, 450, 300);
primaryStage.setTitle("Word counting!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
and the second class is again gui class with table view
public class ShowResults {
static Stage secondaryStage;
public static void drugiProzor() {
secondaryStage=new Stage();
TableView table=new TableView();
TableColumn column1=new TableColumn("Word");
column1.setMinWidth(200);
TableColumn column2=new TableColumn("Number of occurencies");
column2.setMinWidth(200);
table.getColumns().addAll(column1,column2);
StackPane pane=new StackPane();
pane.getChildren().add(table);
Scene scene = new Scene(pane, 450, 300);
secondaryStage.setScene(scene);
secondaryStage.setTitle("Counting words");
secondaryStage.show();
}
}
and third class shoyld be the class where the magic happends something like this:
public class Logic {
public void logic()
}
}
You can just do something like
public Map<String, Long> countWordOccurences(String text) {
return Pattern.compile("\\s+") // regular expression matching 1 or more whitespace
.splitAsStream(text) // split at regular expression and stream words between
// group by the words themselves and count each group:
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}
Check the Javadocs to see what each step is doing: Pattern, Collectors.groupingBy(), Function, etc.
If you want to count in a case-insensitive way, you can replace Function.identity() with String::toLowerCase
.collect(Collectors.groupingBy(String::toLowerCase, Collectors.counting()));
and if you want to ignore punctuation, you can add
map(s -> s.replaceAll("[^a-zA-Z]",""))
to the pipeline.
Here is my code, I'm trying to load a splash screen image with transparent background before my main stage starts. They come almost at the same time, but the big problem is I get a grey rectangle before anything else: .
Here is the code:
public class Menu extends Application {
private Pane splashLayout;
private Stage mainStage;
private ImageView splash;
// Creating a static root to pass to ScreenControl
private static BorderPane root = new BorderPane();
public void start(Stage splashStage) throws IOException {
final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.splash = new ImageView(new Image(getClass().getResource("/splash.png").toString()));
splashStage.initStyle(StageStyle.TRANSPARENT);
showSplash(splashStage, screenSize);
// Constructing our scene using the static root
root.setCenter(new ScrollPane);
Scene scene = new Scene(root, screenSize.getWidth(), screenSize.getHeight());
showMainStage(scene);
if (splashStage.isShowing()) {
mainStage.setIconified(false);
splashStage.toFront();
FadeTransition fadeSplash = new FadeTransition(Duration.seconds(1.5), splashLayout);
fadeSplash.setDelay(Duration.seconds(3.5));
fadeSplash.setFromValue(1.0);
fadeSplash.setToValue(0.0);
fadeSplash.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
splashStage.hide();
}
});
fadeSplash.play();
}
}
private void showMainStage(Scene scene) {
mainStage = new Stage(StageStyle.DECORATED);
mainStage.setTitle("book-depot");
mainStage.getIcons().add(new Image(getClass().getResourceAsStream("/icon.png")));
mainStage.setScene(scene);
mainStage.show();
}
private void showSplash(Stage splashStage, Dimension screenSize) {
splashLayout = new StackPane();
splashLayout.setStyle("-fx-background-color: transparent;");
splashLayout.getChildren().add(splash);
Scene splashScene = new Scene(splashLayout, 690, 590);
splashScene.setFill(Color.TRANSPARENT);
splashStage.setScene(splashScene);
splashStage.show();
}
public void mainGui(String[] args) {
launch(args);
}
}
Am I doing something wrong or I really can't get a transparent background?
This is what it looks like when also the other stage loads up, but I'd like it to work like that even before the main stage loads, or at least I'd want to remove the grey rectangle you can see in the other screenshot
The grey background is your "mainStage" since you are showing splash and main stages at the same time. At the beginning while showing the splash stage you can just init (not show) the main stage and show it later when the animation finishes:
public class ModifiedMenu extends Application
{
private Pane splashLayout;
private Stage mainStage;
private ImageView splash;
// Creating a static root to pass to ScreenControl
private static BorderPane root = new BorderPane();
public void start(Stage splashStage) throws IOException {
final Dimension2D screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.splash = new ImageView(new Image(getClass().getResource("/splash.png").toString()));
splashStage.initStyle(StageStyle.TRANSPARENT);
showSplash(splashStage, screenSize);
// Constructing our scene using the static root
root.setCenter(new ScrollPane());
Scene scene = new Scene(root, screenSize.getWidth(), screenSize.getHeight());
initMainStage(scene);
if (splashStage.isShowing()) {
splashStage.toFront();
FadeTransition fadeSplash = new FadeTransition(Duration.seconds(1.5), splashLayout);
fadeSplash.setDelay(Duration.seconds(3.5));
fadeSplash.setFromValue(1.0);
fadeSplash.setToValue(0.0);
fadeSplash.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
splashStage.hide();
mainStage.show();
}
});
fadeSplash.play();
}
}
private void initMainStage(Scene scene) {
mainStage = new Stage(StageStyle.DECORATED);
mainStage.setTitle("book-depot");
mainStage.getIcons().add(new Image(getClass().getResourceAsStream("/icon.png")));
mainStage.setScene(scene);
}
private void showSplash(Stage splashStage, Dimension2D screenSize) {
splashLayout = new StackPane();
splashLayout.setStyle("-fx-background-color: transparent;");
splashLayout.getChildren().add(splash);
Scene splashScene = new Scene(splashLayout, 690, 590);
splashScene.setFill(Color.TRANSPARENT);
splashStage.setScene(splashScene);
splashStage.show();
}
public void mainGui(String[] args) {
launch(args);
}
}
When a parent component has transparent mouse enabled all child controls are no longer able to receive mouse events. Is it possible exclude a child from this rule.
public class TransparentMouseTest extends Application
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage stage)
{
Pane root = new StackPane();
root.getChildren().add(new TextField());
Pane p = new StackPane();
p.setMouseTransparent(true);
p.setStyle("-fx-background-color:#F001;");
p.getChildren().add(new Button("Button should be able \nto receive mouse events."));
root.getChildren().add(p);
Scene scene = new Scene(root, 400, 300);
stage.setScene(scene);
stage.show();
}
}