I just started JavaFx this past week and having a problem trying to get a circle setup in a pane to respond to button event handler. I have buttons setup with names left, right, up, down which when pressed should move the circle inside inside the pane. My problem is I can't get the circle to respond to my event handlers at all. I saw another tutorial that incorporated key presses to move the circle and I'm trying something similar but with buttons instead. Any help in getting me in the right direction would be great thanks.
package movingball;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class MovingBall extends Application{
private CirclePane circlePane = new CirclePane();
#Override
public void start(Stage primaryStage) {
StackPane pane = new StackPane();
Circle circle = new Circle(50);
circle.setStroke(Color.BLACK);
circle.setFill(Color.WHITE);
pane.getChildren().add(circle);
HBox hBox = new HBox();
hBox.setSpacing(10);
hBox.setAlignment(Pos.CENTER);
Button btLeft = new Button("Left");
Button btRight = new Button("Right");
Button btUp = new Button("Up");
Button btDown = new Button("Down");
hBox.getChildren().addAll(btLeft, btRight, btUp, btDown);
btLeft.setOnAction(new LeftHandler());
btRight.setOnAction(new RightHandler());
btUp.setOnAction(new UpHandler());
btDown.setOnAction(new DownHandler());
BorderPane borderPane = new BorderPane();
borderPane.setCenter(pane);
borderPane.setBottom(hBox);
BorderPane.setAlignment(hBox, Pos.CENTER);
// Create a scene and place it in the stage
Scene scene = new Scene(borderPane, 500, 350);
primaryStage.setTitle("Move the Ball"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
class LeftHandler implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
circlePane.left();
}
}
class RightHandler implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
circlePane.right();
}
}
class UpHandler implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
circlePane.up();
}
}
class DownHandler implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
circlePane.down();
}
}
class CirclePane extends StackPane {
private Circle circle = new Circle(50);
public CirclePane() {
getChildren().add(circle);
circle.setStroke(Color.BLACK);
circle.setFill(Color.WHITE);
}
public void left() {
circle.setCenterX(circle.getCenterX() - 10);
}
public void right() {
circle.setCenterX(circle.getCenterX() + 10);
}
public void up() {
circle.setCenterY(circle.getCenterY() - 10);
}
public void down() {
circle.setCenterY(circle.getCenterY() + 10);
}
}
public static void main(String[] args) {
launch(args);
}
}
The first issue is that you're moving the CirclePane, but it isn't part of your scene. Remove the pane and circle you create in the start(...) method, and put the circlePane in the center of the BorderPane instead.
The second issue is that a StackPane will center the circle, adjusting its coordinate system to keep it centered as the circle moves. So make CirclePane a subclass of Pane, instead of StackPane. Alternatively, you can call circle.setManaged(false); to prevent the StackPane from positioning the circle.
Related
This might be a wierd question but is it possible to draw some sort of graphics without a window using javafx?
To clarify I want to write a circle at the bottom left corner of the screen where everything but the circle is the underlying window. So just removing the titlebar is not really enough
Are you looking for a transparent stage - this puts a red circle on the bottom left of the primary monitor. This might help you in the direction you want to go.
public class TransparentStage extends Application {
#Override
public void start(Stage stage) throws Exception {
stage.initStyle(StageStyle.TRANSPARENT);
Circle c = new Circle(30);
c.setFill(Color.RED);
VBox box = new VBox();
box.getChildren().add(c);
final Scene scene = new Scene(box,300, 250);
scene.setFill(null);
stage.setScene(scene);
stage.setX(20);
stage.setY(Screen.getPrimary().getBounds().getHeight() - 100);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Some sort of transparent window like below
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application {
#Override
public void start(Stage stage) {
stage.initStyle(StageStyle.TRANSPARENT);
Text text = new Text("!");
text.setFont(new Font(40));
VBox box = new VBox();
box.getChildren().add(text);
final Scene scene = new Scene(box,300, 250);
scene.setFill(null);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
source : http://www.java2s.com/Code/Java/JavaFX/TRANSPARENTwindow.htm
I have a code that works with button but not with circle.
What I want to do is to perform certain action after user pressed a button on keyboard. This code below works just with button. Just change circle to button (twice) to see it works. Is it not proper code to use for anything else?
Thanks in advance.
Code:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ButtonExample extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane pane = new BorderPane();
Button button = new Button("Press Me!");
//circle
Circle circle = new Circle();
//Setting the position of the circle
circle.setCenterX(300.0f);
circle.setCenterY(135.0f);
//Setting the radius of the circle
circle.setRadius(25.0f);
//Setting the color of the circle
circle.setFill(Color.BROWN);
//Setting the stroke width of the circle
circle.setStrokeWidth(20);
pane.setCenter(circle); // JUST CHANGE HERE (circle) to (button) to make it work
Scene scene = new Scene(pane, 200, 200);
primaryStage.setScene(scene);
primaryStage.show();
circle.setOnKeyPressed(new EventHandler<KeyEvent>() { /////and HERE
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.ENTER) {
System.out.println("Enter Pressed");
}
}
});
}
public static void main(String[] args) {
launch(args);
}
}
I have SplitPane with two AnchorPane (left and right side). There are Label, TextField and Button on each AnchorPane, they are arranged in one line. Label must bind to the left side AnchorPane, Button to the right and TextField must be stretched between them. Left AnchorPane must be bind to left part of SplitPane.
My code works, but when I move divider after some time Buttons jump off the binding with SplitPane.
AnchorPane width bind to SplitPane.Divider, Label, TextField, Button bind to AnchorPane.
Can you help me?
Sorry for my English.
import javafx.application.Application;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.value.ObservableValue;
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.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
stage.setTitle("BackUpManager");
AnchorPane root = new AnchorPane();
Scene scene = new Scene(root, 800,600);
SplitPane splitPane = new SplitPane();
splitPane.setLayoutY(50);
splitPane.prefWidthProperty().bind(root.widthProperty());
splitPane.prefHeightProperty().bind(root.heightProperty().subtract(50));
AnchorPane rRoot = new AnchorPane();
AnchorPane wRoot = new AnchorPane();
splitPane.getItems().addAll(rRoot,wRoot);
rRoot.setMinWidth(200);
rRoot.prefWidthProperty().bind(splitPane.getDividers().get(0).positionProperty());
Button rBrowse = new Button();
rRoot.getChildren().add(rBrowse);
rBrowse.setText("Browse");
DoubleBinding db0 = rRoot.widthProperty().subtract(55);
db0.addListener(new javafx.beans.value.ChangeListener<Number>() {
public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
rBrowse.setLayoutX(db0.getValue());
}});
Label rLabel = new Label("Reserve dir");
rRoot.getChildren().add(rLabel);
rLabel.setLayoutY(3);
TextField rPath = new TextField();
rRoot.getChildren().add(rPath);
rPath.setLayoutX(60);
rPath.prefWidthProperty().bind(rRoot.widthProperty().subtract(115));
wRoot.prefWidthProperty().bind(splitPane.widthProperty().subtract(splitPane.getDividers().get(0).positionProperty()));
wRoot.setMinWidth(200);
Button wBrowse = new Button();
wRoot.getChildren().add(wBrowse);
wBrowse.setText("Browse");
DoubleBinding db1 = wRoot.widthProperty().subtract(55);
db1.addListener(new javafx.beans.value.ChangeListener<Number>() {
public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
wBrowse.setLayoutX(db1.getValue());
}});
Label wLabel = new Label("Working dir");
wRoot.getChildren().add(wLabel);
wLabel.setLayoutY(3);
TextField wPath = new TextField();
wRoot.getChildren().add(wPath);
wPath.setLayoutX(64);
wPath.prefWidthProperty().bind(wRoot.widthProperty().subtract(119));
rBrowse.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle (ActionEvent e) {
System.out.println("Called");
}
});
root.getChildren().addAll(splitPane);
stage.setScene(scene);
stage.show();
}
}
Using JavaFX 2, I have a basic example of a ScrollPane that contains an HBox of Labels. I want to be able to add a Label to the HBox, and simultaneously scroll to the right edge of the ScrollPane so that the newly added Label is visible. My current method uses the setHvalue() to set the scroll position and getHmax() to get the maximum scrolling distance allowed.
The problem is that when I set the scroll position using getHmax(), it is as if the just-added Label is not computed in the ScrollPanel's scroll width. Is there a way that I can update this inner width before trying setHvalue?
Please see this simple example code which exhibits the issue.
In particular, please notice the addChatItem(String item) method, which contains the logic for scrolling to the edge of the ScrollPane.
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class ScrollPaneTest extends Application {
static int defaultFontSize = 30;
ScrollPaneTest scrollPaneTest = this;
ScrollPane chatBoxScrollPane = new ScrollPane();
HBox chatBox = new HBox();
Chatter chatter = new Chatter();
public static void main(String[] args) {
launch(args);//default
}
#Override
public void stop() throws Exception {
super.stop();
System.exit(0);
}
#Override
public void start(Stage primaryStage) {
BorderPane borderPane = new BorderPane();
StackPane chatBoxStackPane = new StackPane();
chatBoxScrollPane.setContent(chatBox);
//chatBoxScrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
chatBoxScrollPane.setMaxHeight(50);
chatBoxStackPane.getChildren().add(chatBoxScrollPane);
borderPane.setCenter(chatBoxStackPane);
Scene scene = new Scene(borderPane, 800, 600);
primaryStage.setScene(scene);
primaryStage.setTitle("Scroll Demo");
primaryStage.show();
new Thread("mainGameControlThread") {
public void run() {
chatter.chatLoop(scrollPaneTest);
}
}.start();
}
public void addChatItem(String chatString) {
Label title = new Label(chatString);
title.setFont(new Font("Verdana", defaultFontSize));
chatBox.getChildren().add(title);
chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax());
}
class Chatter {
public void chatLoop(final ScrollPaneTest test) {
Timer closingCeremonyTimer = new Timer();
closingCeremonyTimer.schedule(new TimerTask() {
public void run() {
Platform.runLater(new Runnable() {
#Override
public void run() {
test.addChatItem("Hello World. ");
}
});
chatLoop(test);
}
}, (long) (0.5*1000));
}
}
}
Here is an image of issue, notice how the ScrollPane has not scrolled to the right edge.
Edit:
I've come up with a workaround but it is very far from ideal. My solution is to start a timer which will use setHvalue() after enough time has passed for the ScrollPane to discover the true width of its content. my addChatItem() method now looks like this:
public void addChatItem(String chatString) {
Label title = new Label(chatString);
title.setFont(new Font("Verdana", defaultFontSize));
chatBox.getChildren().add(title);
Timer closingCeremonyTimer = new Timer();
closingCeremonyTimer.schedule(new TimerTask() {
public void run() {
chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax());
}
}, (long) 50);
}
Unfortunately, the number 50 in that method needs to be greater than the time that it takes the ScrollPane to update its inner content's width, and that seems to be far from guaranteed.
you can bind to Hbox widthproperty chnages .
Sample Code :
//in start method add this code
DoubleProperty wProperty = new SimpleDoubleProperty();
wProperty.bind(chatBox.widthProperty()); // bind to Hbox width chnages
wProperty.addListener(new ChangeListener() {
#Override
public void changed(ObservableValue ov, Object t, Object t1) {
//when ever Hbox width chnages set ScrollPane Hvalue
chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax());
}
}) ;
and
// remove below line from your addChatItem() method
chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax());
Result :yes added numbering for fun ;)
In my case I needed to enclose a HBox called labels inside a ScrollPane called msgs and here is the way I handled autoscroll.
NOTE: The changeListener added to labels HBox is implemented via Lambda syntax(available in JDK8)
labels.heightProperty().addListener((observable, oldVal, newVal) ->{
msgs.setVvalue(((Double) newVal).doubleValue());
});
I want to create a refresh button for my webView that will be on top of the view (even if it hides part of the view), when I place the button on the Grid Pane it pushes the webView down or to the side (depends where I place the button)
How can I place my "refresh" button on top of the webView and not move it aside?
import java.util.List;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class webviewbrowser extends Application {
#Override public void start(Stage primaryStage) throws Exception {
Pane root = new WebViewPane();
primaryStage.setScene(new Scene(root, 1024, 768));
primaryStage.setFullScreen(true);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
/**
* Create a resizable WebView pane
*/
public class WebViewPane extends Pane {
public WebViewPane() {
VBox.setVgrow(this, Priority.ALWAYS);
setMaxWidth(Double.MAX_VALUE);
setMaxHeight(Double.MAX_VALUE);
WebView view = new WebView();
view.setMinSize(500, 400);
view.setPrefSize(500, 400);
final WebEngine eng = view.getEngine();
eng.load("http://google.com");
//final TextField locationField = new TextField("http://www.google.com");
//locationField.setMaxHeight(Double.MAX_VALUE);
Button goButton = new Button("Refresh");
goButton.setDefaultButton(true);
EventHandler<ActionEvent> goAction = new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
eng.reload();
}
};
goButton.setOnAction(goAction);
GridPane grid = new GridPane();
grid.setVgap(0);
grid.setHgap(0);
GridPane.setConstraints(goButton,2,0,2,1, HPos.RIGHT, VPos.BOTTOM, Priority.ALWAYS, Priority.ALWAYS);
GridPane.setConstraints(view, 0, 0, 2, 1, HPos.CENTER, VPos.CENTER, Priority.SOMETIMES, Priority.SOMETIMES);
grid.getColumnConstraints().addAll(
new ColumnConstraints(100, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true),
new ColumnConstraints(40, 40, 40, Priority.NEVER, HPos.CENTER, true)
);
grid.getChildren().addAll(goButton, view);
getChildren().add(grid);
}
#Override protected void layoutChildren() {
List<Node> managed = getManagedChildren();
double width = getWidth();
double height = getHeight();
double top = getInsets().getTop();
double right = getInsets().getRight();
double left = getInsets().getLeft();
double bottom = getInsets().getBottom();
for (int i = 0; i < managed.size(); i++) {
Node child = managed.get(i);
layoutInArea(child, left, top,
width - left - right, height - top - bottom,
0, Insets.EMPTY, true, true, HPos.CENTER, VPos.CENTER);
}
}
}
}
If you want to stack one component on top of another, don't use a GridPane for layout, instead use a parent that allows layout components to be placed on top of one another. For example, a standard Pane, a StackPane, Group or Region. In these stacked style layouts, the components are rendered in order of the child component's position in the parent's child list.
In your sample code you are already extending Pane, so get rid of all of the grid code and just do:
getChildren().addAll(view, goButton);
instead of:
grid.getChildren().addAll(goButton, view);
Modify the layout properties of your goButton to position it within a parent which does not manage the layout position of it's children, e.g. you can call goButton.relocate(xPos, yPos).
You have some custom stuff in the layoutChildren method you override that may mess up the default Pane layout processing logic. Overriding layoutChildren is more of an advanced layout topic and I wouldn't advise it for beginners.
Here is an updated sample you could look at which uses some of the concepts mentioned in this answer.
import javafx.application.Application;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.web.*;
import javafx.stage.Stage;
public class WebViewBrowser extends Application {
#Override public void start(Stage stage) throws Exception {
stage.setScene(new Scene(new WebViewPane("http://google.com")));
stage.setFullScreen(true);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
class WebViewPane extends Pane {
final WebView view = new WebView();
final Button goButton = createGoButton(view.getEngine());
public WebViewPane(String initURL) {
view.getEngine().load(initURL);
getChildren().addAll(
view,
goButton
);
initLayout();
}
private Button createGoButton(final WebEngine eng) {
Button go = new Button("Refresh");
go.setDefaultButton(true);
go.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
eng.reload();
}
});
return go;
}
private void initLayout() {
setMinSize(500, 400);
setPrefSize(1024, 768);
view.prefWidthProperty().bind(widthProperty());
view.prefHeightProperty().bind(heightProperty());
goButton.setLayoutX(10);
goButton.layoutYProperty().bind(
heightProperty().subtract(20).subtract(goButton.heightProperty())
);
}
}