I'm creating a large program to track finances. Because of this, I've cleaned up my code by positioning elements in other classes, then using aggregation to implement them in my main program. The only problem is I've started to work on interaction and handling button presses, but I can't register any button presses normally. Here's clean sample code to highlight the problem.
Main Execution Class
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.Group;
import javafx.application.Application;
import javafx.scene.layout.Pane;
import javafx.event.ActionEvent;
public class testingButton extends Application{
private buttonClass add;
#Override
public void start(Stage stage){
add = new buttonClass();
Pane root = new Pane();
root.getChildren().addAll(add.getB());
Scene scene = new Scene(root, 150,150);
stage.setTitle("Testing Visual elements");
stage.setScene(scene);
stage.show();
}
public void processButtonPress(ActionEvent event){
if(event.getSource() == add.getB()){
System.out.println("testing");
}
}
public static void main(String[] args){
launch(args);
}
}
Aggregate button class
import javafx.scene.control.Button;
public class buttonClass{
private Button b;
public buttonClass(){
b = new Button("Button");
b.setLayoutX(50);
b.setLayoutY(50);
}
public Button getB(){
return b;
}
}
How can I get the button press to register? Any help is appreciated. Thanks!
Here is the code you need...
you need to apply an actionevent to the button not try to get a button from actionevent
public class JavaApplication3 extends Application {
ButtonClass add;
#Override
public void start(Stage stage) {
add = new ButtonClass();
Pane root = new Pane();
root.getChildren().add(add);
Scene scene = new Scene(root, 150, 150);
stage.setTitle("Testing Visual elements");
stage.setScene(scene);
stage.show();
add.setOnAction((javafx.event.ActionEvent event) -> {
System.out.println("Button pressed");
});
}
public static void main(String[] args) {
launch(args);
}
and the button class
public class ButtonClass extends Button {
private Button b;
public ButtonClass() {
b = new Button("Button");
b.setLayoutX(50);
b.setLayoutY(50);
}
Related
The following are the changes I made in fxml
Changes in the java file , here my code :
private ProgressIndicator pi;
void handlebuildButtonAction(ActionEvent event) throws IOException, GeneralSecurityException {
if ((entServer.isSelected()==true || compasServer.isSelected()==true)) {
if(!fileList.isEmpty()){
ProgressIndicator pi = new ProgressIndicator();
pi.setProgress(10);
}
}
The progress indicator is not updated when I run the application. I'm not sure how to sync the changes to UI. Assist me on this. Thanks in advance.
output
For example: if you set 0.1 - progress will be 10%, 0.2 - 20% and so on, so when you set the progress => 1 you will always have "done".
Here, this an example with a button, when you click the button, your progress indicator will be updated(one click + 10%):
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.*;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
public class Test extends Application {
private ProgressIndicator pi;
private double counter = 0;
public void start(Stage stage)
{
ProgressIndicator pi = new ProgressIndicator();
Button button = new Button("Press");
TilePane root = new TilePane();
// action event
EventHandler<ActionEvent> event = new EventHandler<ActionEvent>() {
public void handle(ActionEvent e)
{
counter += 0.1;
pi.setProgress(counter);
}
};
button.setOnAction(event);
root.getChildren().add(button);
root.getChildren().add(pi);
// create a scene
Scene scene = new Scene(root, 200, 200);
// set the scene
stage.setScene(scene);
stage.show();
}
public static void main(String args[])
{
// launch the application
launch(args);
}
}
Just change this code for your case:
EventHandler<ActionEvent> event = new EventHandler<ActionEvent>() {
public void handle(ActionEvent e)
{
if ((entServer.isSelected()==true || compasServer.isSelected()==true)) {
if (!fileList.isEmpty()) {
counter += 0.1;
pi.setProgress(counter);
}
}
}
};
Hope that helps you!
I want to immediately after increasing the value of i appear in the label
Example:
-in i=0 show 0
-in i=1 show 01
-in i=2 show 012
Can You Help me
import javafx.application.Application;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Example extends Application{
#Override
public void start (Stage primaryStage) {
Pane pane=new Pane();
Label label=new Label();
Button bt=new Button("Start");
pane.getChildren().addAll(bt,label);
bt.setOnAction(e->{
for (int i=0;i<10000000;i++) label.setText(label.getText()+i);
});
Scene scene = new Scene(pane,1000,500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The problem is that you update the label's value while you are on the user interface's thread. JavaFX works with a model where the updates are done at each 'tick' (60 fps). All the updates done are only visible once your eventhander's code has finished.
Additionally, given that this is a long running task it will result in an unresponsive user interface.
You should use a Worker to do the long running task. See the tutorial on asynchronous processing. Note that it will not guarantee that you will see all values as the worker can be quicker than the user interface updates and the system will coalesce these updates.
You can use Timeline to accomplish this task.
import java.util.concurrent.atomic.AtomicLong;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* #author blj0011
*/
public class JavaFXApplication177 extends Application
{
#Override
public void start(Stage primaryStage)
{
AtomicLong i = new AtomicLong();
Label label = new Label();
Button btn = new Button();
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(.5), (ActionEvent event) -> {//This controls how fast this should run. This example happens every half of a second
label.setText(label.getText() + Long.toString(i.getAndIncrement()));
}));
timeline.setCycleCount(10000000);//This controls the amount of time this should run
timeline.setOnFinished(event -> {//This tells what to do once cycle count is reached
btn.setDisable(false);
});
btn.setText("Start");
btn.setOnAction((ActionEvent event) -> {
btn.setDisable(true);
timeline.play();
});
StackPane stackPane = new StackPane(label);
VBox root = new VBox(stackPane, new StackPane(btn));
VBox.setVgrow(stackPane, Priority.ALWAYS);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Test5 extends Application {
private String text = "";
private int i;
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
StackPane pane = new StackPane();
Label lblText = new Label("");
pane.getChildren().add(lblText);
new Thread(new Runnable() {
#Override
public void run() {
try {
for (i=0;i<10000;i++) {
Platform.runLater(new Runnable() { // Run from JavaFX GUI
#Override
public void run() {
lblText.setText(lblText.getText()+i);
}
});
Thread.sleep(200);
}
}
catch (InterruptedException ex) {
}
}
}).start();
Scene scene = new Scene(pane, 200, 50);
primaryStage.setTitle("FlashText"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
}
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
//Your First Task #1
//Here UI won't be interrupted
Platform.runLater(new Runnable() {
#Override
public void run() {
//Your Second Task After Completion Of First One #2
}
});
return null;
}
};
}
};
service.start();
}
#1. The task that you want to perform in the background ex. loading the data has to be placed here. It's working great for me.
#2. Once the background task is finished this thread will be executed so Ui and background thread will run separately and smoothly.
I know it's too late for this answer but I just wanted to share what I did this might help!
I first noticed this by having a huge memory leak caused by resizing javafx.scene.control.Pagination.
I created a sample app to show the behavior. Every click on any button causes more memory to be consumed. I suppose that the correct way to deal with this is to remove any listeners on the ToggleButtons before clearing them but PaginationSkin isn't doing that.
Have I missed something or is this a real bug in the Pagination code?
Are there any workarounds?
The same behavior is seen it both 8u40 and 8u45. I haven't tried any older versions yet.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ToggleGroupLeak extends Application {
private HBox hbox;
private ToggleGroup toggleGroup;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
toggleGroup = new ToggleGroup();
hbox = new HBox();
redo();
root.getChildren().add(hbox);
primaryStage.setScene(new Scene(root, 700, 100));
primaryStage.show();
}
private void redo() {
hbox.getChildren().clear();
toggleGroup.getToggles().clear();
for (int i = 0; i < 20; i++) {
addButton(i);
}
}
private void addButton(final int i) {
ToggleButton btn = new ToggleButton("" + i);
btn.setToggleGroup(toggleGroup);
btn.setOnAction(e -> redo());
hbox.getChildren().add(btn);
}
}
Concretely, usage of Pagination in an AnchorPane seems to cause the same leak by resizing the control.
FXML
<Pagination fx:id="pagination" visible="true" AnchorPane.topAnchor="3.0" AnchorPane.leftAnchor="12.0" AnchorPane.rightAnchor="130.0"/>
Java
#FXML
protected Pagination pagination;
// Init method run once
pagination.setMaxPageIndicatorCount(100);
pagination.currentPageIndexProperty().addListener((observable, oldPageIndex, newPageIndex) -> {
if (!oldPageIndex.equals(newPageIndex)) {
if (searchParams.getPage() == newPageIndex.intValue()) {
return;
}
searchParams.setPage(newPageIndex.intValue());
// Code that inits the new page
}
});
EDIT: Added pagination specific code
I would like to create a simple JavaFx class that shows the user a translucent rectangle (say an arbitrary 50% transparency) covering the users screen. It should simply allow me to get the Point of a mouse click event. This sounds trivial, but when I create transparent windows they always seem to be transparent to mouse events rather than just my requirement of semi-transparent visibility. The mouse event is never triggered.
I've used setMouseTransparent(false) on the rectangle and the root pane, but this makes no difference. I'd be really grateful if somebody could indicate any errors/misconceptions.
Here's the trivial test class I have created:
public class ClickScreen implements MouseListener {
private ClickScreenListener listener;
private Stage window;
private Point point;
public ClickScreen(ClickScreenListener listener) {
// Get screen size
Rectangle2D r = Screen.getPrimary().getBounds();
// Something to put stuff in
StackPane root = new StackPane();
// Translucent rectangle on the pane
Rectangle rectangle = new Rectangle(r.getWidth(), r.getHeight());
rectangle.setFill(Color.rgb(183, 183, 183, 0.5));
root.getChildren().add(rectangle);
Scene scene = new Scene(root, r.getWidth(), r.getHeight());
scene.setFill(null);
window = new Stage();
window.initStyle(StageStyle.TRANSPARENT);
window.setTitle("Click drop location");
window.setScene(scene);
this.listener = listener;
}
public Point getLocation(){
return point;
}
#Override
public void mouseClicked(MouseEvent e) {
point = e.getLocationOnScreen();
listener.screenClicked(point);
}
}
Edit:
A simpler example of the transparency issue I am experiencing is from this Hello World! example. When I mouse over the button, it's about 50:50 chance of clicking the button or just clicking "through" and giving focus to the underlying window (which is usually eclipse in my case). Would love you thoughts on this.
public class HelloWorld extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
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);
Scene scene = new Scene(root, 300, 250);
scene.setFill(null);
primaryStage.setScene(scene);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.show();
}
}
Check your Imports
You are using some kind of weird setup where you are mixing AWT/Swing classes and JavaFX classes, which really isn't advised (and doesn't work at all in the combination and manner you have used). Just be careful in your JavaFX programs not to import any java.awt.* or javax.swing.* classes unless you really know what you are doing in mixing code for two different toolkits.
Sample Solution
Here is a sample solution which imports only JavaFX classes and utilizes JavaFX events, but otherwise tries to stick to the coding/callback style of the sample code in your question. (The sample could be further simplified through use of Java 8 lambdas).
import javafx.application.Application;
import javafx.event.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.*;
public class ClickListenerSample
extends Application
implements ClickScreenListener {
private Label clickFeedbackLabel = new Label("");
#Override public void start(Stage stage) {
Button listen = new Button("listen");
listen.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
new ClickScreen(ClickListenerSample.this);
}
});
VBox layout = new VBox(10);
layout.getChildren().setAll(
listen,
clickFeedbackLabel
);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout, 100, 80));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
#Override public void screenClicked(Point2D point) {
clickFeedbackLabel.setText(point.getX() + ", " + point.getY());
}
}
interface ClickScreenListener {
void screenClicked(Point2D point);
}
class ClickScreen {
private ClickScreenListener listener;
private Stage window;
private Point2D point;
public ClickScreen(ClickScreenListener listener) {
// Get screen size
Rectangle2D r = Screen.getPrimary().getBounds();
// Something to put stuff in
StackPane root = new StackPane();
root.setStyle("-fx-background-color: null;");
// Translucent rectangle on the pane
Rectangle rectangle = new Rectangle(r.getWidth(), r.getHeight());
rectangle.setFill(Color.rgb(183, 183, 183, 0.5));
root.getChildren().add(rectangle);
Scene scene = new Scene(root, r.getWidth(), r.getHeight());
scene.setFill(null);
window = new Stage();
window.initStyle(StageStyle.TRANSPARENT);
window.setTitle("Click drop location");
window.setScene(scene);
scene.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
point = new Point2D(event.getScreenX(), event.getScreenY());
listener.screenClicked(point);
window.hide();
}
});
window.show();
this.listener = listener;
}
public Point2D getLocation(){
return point;
}
}
Please have a look at my first JavaFX application code
package helloworld;
import javafx.application.*;
import javafx.stage.*;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
public class HelloWorld2 extends Application
{
#Override
public void start(Stage stage)
{
stage.setTitle("Hello World");
Button btn = new Button();
btn.setText("Hello");
btn.setOnAction(new Action());
StackPane pane = new StackPane();
pane.getChildren().add(btn);
stage.setScene(new Scene(pane, 300,250));
stage.show();
}
private class Action implements EventHandler
{
#Override
public void handle(Event arg0)
{
System.out.println("JavaFX World");
}
}
public static void main(String[]args)
{
launch(args);
}
}
I am getting "Unsafe Operation" warning when I run this. Application runs without any exceptions. I believe unsafe thing is coming because I have to put keyword in some place, but I don't know where. Please help!
You should to specify the type of Event
private class Action implements EventHandler<ActionEvent>
{
#Override
public void handle(ActionEvent arg0)
{
System.out.println("JavaFX World");
}
}