Im writing a small program that involves a timer but for some reason I cant get the TimerTask to update the value of my Label.setText
public class Main extends Application {
Label TimerLabel;
/* Create a Button named button */
Button button;
/* Create three Radiobuttons named Radio1,Radio2,Radio3 */
RadioButton Radio1, Radio2, Radio3;
Timer QuestionTimer = new Timer();
TimerTask QuestionTick = new TimerTask() {
#Override
public void run() {
TimerLabel.setText(String.valueOf(Integer.valueOf(TimerLabel.getText())+1));
}
};
public static void main(String[] args) {
launch(args);
}
/*UI Part*/
#Override
public void start(Stage primaryStage) throws Exception {
/*Window(Stage) Title is set to "Try 1"*/
primaryStage.setTitle("Try 1");
/*Button properties*/
button = new Button();
button.setText("Click Me");
//Radio Button
Radio1 = new RadioButton();
Radio1.setText("Click Me 1");
Radio1.setOnAction(e->{
System.out.println("Radio Button Clicked");
});
Radio2 = new RadioButton();
Radio2.setText("Click Me 2");
Radio2.setOnAction(e->{
System.out.println("Radio Button 2 Clicked");
});
Radio3 = new RadioButton();
Radio3.setText("Click Me 3");
Radio3.setOnAction(e->{
System.out.println("Radio Button 3 Clicked");
});
TimerLabel = new Label();
TimerLabel.setText("0");
/*Here my layout is defined */
Pane Buttonlayout = new Pane();
button.setLayoutX(200);
button.setLayoutY(200);
Radio1.setLayoutX(15);
Radio1.setLayoutY(20);
Radio2.setLayoutX(15);
Radio2.setLayoutY(40);
Radio3.setLayoutX(15);
Radio3.setLayoutY(60);
TimerLabel.setLayoutX(100);
TimerLabel.setLayoutY(20);
Buttonlayout.getChildren().add(button);
Buttonlayout.getChildren().add(Radio1);
Buttonlayout.getChildren().add(Radio2);
Buttonlayout.getChildren().add(Radio3);
Buttonlayout.getChildren().add(TimerLabel);
/*Here we define the scene (aka everything inside the stage (inside the window))*/
Scene scene1 = new Scene(Buttonlayout,300,250);
primaryStage.setScene(scene1);
primaryStage.show();
QuestionTimer.scheduleAtFixedRate(QuestionTick,1000,1000);
}
}
So thats my code, I know most of it seems stupid but I first wanted to start programming on the timer and well it didnt work. Any kind of help would be appreciated
From the code it appears you are utilizing the java.util.Timer class. The documentation states Implementation note: All constructors start a timer thread. The the JavaFX UI should not be updated from another thread, which is what you are doing with the timer.
Rather than updating the UI directly use the Platform.runLater(Runnable) to schedule the UI tasks on the main JavaFX thread.
javafx.application.Platform.runLater(new Runnable() {
#Override
public void run() {
TimerLabel.setText(String.valueOf(Integer.valueOf(TimerLabel.getText())+1));
}
}
And please, do yourself a favor and get rid of the method chaining. It will make it easier to debug when Integer.valueOf throws an Exception.
String timer_label = TimerLabel.getText();
Integer timer_int = Integer.valueOf(timer_label);
String timer_text = String.valueOf(timer_int + 1);
TimerLabel.setText(timer_text);
Related
I want to make a notification window with animated text. A notification would be sent by a button click and the animation would start playing. My problem is that when I click the button again before the previous animation is done, two animations get executed at once. How do I make each method call of "sendMessage()" wait for the other to finish? If it has any significance there are multiple nodes that call the sendMessage() method in my program unlike in my MRE, so I want some kind of Queue with messages. Here is my MRE:
public class AnimationTest extends Application {
private final Label messageLabel = new Label();
#Override
public void start(Stage stage) throws IOException {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
Scene scene = new Scene(vBox, 320, 240);
vBox.getChildren().add(messageLabel);
Button button = new Button();
button.setOnAction(event -> sendMessage("Some animated text."));
vBox.getChildren().add(button);
stage.setScene(scene);
stage.show();
}
private void sendMessage(String message) {
final IntegerProperty i = new SimpleIntegerProperty(0);
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(
Duration.millis(40),
event -> {
if (i.get() > message.length()) {
timeline.stop();
} else {
messageLabel.setText(message.substring(0, i.get()));
i.set(i.get() + 1);
}
});
timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}
public static void main(String[] args) {
launch();
}
}
For the specific example you posted, the easiest approach is to disable the button immediately prior to starting the animation, and enable it again when the animation stops. Here is one way to do this:
public class AnimationTest extends Application {
private final Label messageLabel = new Label();
#Override
public void start(Stage stage) {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
Scene scene = new Scene(vBox, 320, 240);
vBox.getChildren().add(messageLabel);
Button button = new Button();
button.setOnAction(event -> {
Animation animation = sendMessage("Some animated text.");
button.disableProperty().bind(Bindings.equal(animation.statusProperty(), Animation.Status.RUNNING));
});
vBox.getChildren().add(button);
stage.setScene(scene);
stage.show();
}
private Animation sendMessage(String message) {
final IntegerProperty i = new SimpleIntegerProperty(0);
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(
Duration.millis(40),
event -> {
if (i.get() > message.length()) {
timeline.stop();
} else {
messageLabel.setText(message.substring(0, i.get()));
i.set(i.get() + 1);
}
});
timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
return timeline ;
}
public static void main(String[] args) {
launch();
}
}
If you want to allow these messages to accumulate in a queue, and a new animation to start when the old one finishes, you need to keep a queue of the messages and a reference to a current animation that's running (if there is one). You can poll the queue from an AnimationTimer and start a new animation when a new message appears, if there is no current animation running.
I'd recommend thinking about whether this is the approach you want to take; there's no guarantee here that your messages will not appear more quickly than they can be animated, in which case the queue will grow indefinitely. However, this is an implementation if you can otherwise assure that this is not the case:
public class AnimationTest extends Application {
private final Label messageLabel = new Label();
private final Queue<String> messages = new LinkedList<>();
private Animation currentAnimation = null ;
#Override
public void start(Stage stage) {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
Scene scene = new Scene(vBox, 320, 240);
vBox.getChildren().add(messageLabel);
Button button = new Button();
button.setOnAction(event -> messages.add("Some animated text."));
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long l) {
if (currentAnimation == null || currentAnimation.getStatus() == Animation.Status.STOPPED) {
String message = messages.poll();
if (message != null) {
currentAnimation = sendMessage(message);
currentAnimation.play();
}
}
}
};
timer.start();
vBox.getChildren().add(button);
stage.setScene(scene);
stage.show();
}
private Animation sendMessage(String message) {
final IntegerProperty i = new SimpleIntegerProperty(0);
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(
Duration.millis(40),
event -> {
if (i.get() > message.length()) {
timeline.stop();
} else {
messageLabel.setText(message.substring(0, i.get()));
i.set(i.get() + 1);
}
});
timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Animation.INDEFINITE);
return timeline ;
}
public static void main(String[] args) {
launch();
}
}
Note there are no threading considerations here. The handle() method is invoked on the FX Application Thread, so the only requirement is that the messages are placed in the queue on the same thread. This happens in this example because the button's event handler is invoked on that thread. If your messages are coming from a background thread, you should ensure they are added to the queue on the FX Application Thread, either by using Platform.runLater(...) or (preferably) by using the JavaFX Concurrency API (i.e. by retrieving the messages in a Task or Service and adding them to the queue in an onSucceeded handler).
Set a boolean (best do it atomic, because multithreading and stuff...) at animation start & end.
Disable the Button when boolean is in animation phase.
I'm currently trying to create a Splash Screen for my program since it takes some time to start up.
The problem is that it takes a while to create the GUI (creating dialogues, updating tables etc.). And I can't move the GUI creation to a background thread (like the "Task" class), since I'll get an "Not on FXApplication Thread" exception.
I tried using:
Platform.runLater(new Runnable() {
public void run() {
//create GUI
}
}
And the "call" method of a Task:
public class InitWorker extends Task<Void> {
private Model model;
private ViewJFX view;
public InitWorker(Model model) {
this.model = model;
}
#Override
protected Void call() throws Exception {
View view = new View();
Collection collection = new Collection();
//do stuff
}
}
When I wrote the program in Swing I could just display and update the Splash Screen on the EventDispatchThread, without any real concurreny. The code looked like this:
public void build() {
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Menus");
menuCreator = new MenuCreatorOld (model, this);
menuCreator.createMenu();
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE, "Creating Toolbar");
toolBar = menuCreator.createToolBar();
createWesternPanelToolBar();
shoppingPanel = new ShoppingListOld(model, this, collectionController, shoppingController, controller);
centerTabbedPane = new JTabbedPane();
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Collection");
collectionPanel = new CollectionOld(model, collectionController, this, controller);
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Wish List");
wishPanel = new WishListOld(model, this, collectionController, wishController, controller);
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Folders Table");
//and so on
}
public static void updateProgressBar(int progressValue, String text) {
System.out.println("Loading Bar Value:"+progressValue);
progressBar.setValue(progressValue);
loadingLabel.setText(text);
progressBar.setString(text);
}
Is there any way to create the GUI in the background while displaying a Splash Screen with a loading bar?
Edit:
I had a look at my code and was able to decrease the startup time by 5 seconds. Most of the dialogs pull data from the database when they are created. So I moved the creation of the dialogs into their getter methods. That resulted in an improvement of 3 seconds. But I would still like to know if there is in a way to create the GUI on a background thread.
Edit:
As suggested, I also tried using "RunLater" in a "Task".
This way I can create the GUI and display the SplashScreen, but I can't update the progress bar and progress label, since the GUI creation blocks the JavaFX application thread. The progress bar and label are only updated, after the GUI has been fully created.
Here's an example you guys can run (I removed the splash screen and only kept the progress bar and progress label):
public class InitWorker extends Task<Void> {
private static ProgressBar progressBar;
private static Label progressLabel;
private static double PROGRESS_MAX = 5;
private double loadingValue;
public InitWorker() {
loadingValue = 0;
}
#Override
protected void succeeded() {
System.out.println("Succeeded");
}
#Override
protected void failed() {
System.out.println("Failed");
}
#Override
protected Void call() throws Exception {
System.out.println("RUNNING");
Platform.runLater(new Runnable() {
public void run() {
displaySplashScreen();
for(int i=0; i<10; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
updateProgressBar(loadingValue++, "Label "+i);
Stage stage = new Stage();
Label label = new Label("Label " + i);
VBox panel = new VBox();
panel.getChildren().add(label);
Scene scene = new Scene(panel);
stage.setScene(scene);
stage.centerOnScreen();
stage.show();
}
// updateProgressBar(1, "Initializing...");
}});
return null;
}
public void updateProgressBar(double loadingValue, String text) {
progressBar.setProgress(loadingValue / PROGRESS_MAX);
progressLabel.setText(text);
}
public static void displaySplashScreen() {
Stage progressBarStage = new Stage();
progressBar = new ProgressBar();
Scene progressBarScene = new Scene(progressBar);
progressBarStage.setScene(progressBarScene);
Stage progressLabelStage = new Stage();
progressLabel = new Label("Loading...");
progressLabel.setPadding(new Insets(5));
progressLabel.setStyle("-fx-background-color: red");
Scene progressLabelScene = new Scene(progressLabel);
progressLabelStage.setScene(progressLabelScene);
double progressBarWidth = 500;
double progressBarHeight = 75;
//muss angezeigt werden, um sie abhängig von Größe zu positionieren
progressBarStage.show();
progressLabelStage.show();
//
progressBarStage.setWidth(progressBarWidth);
progressBarStage.setHeight(progressBarHeight);
progressBarStage.centerOnScreen();
progressBarStage.centerOnScreen();
progressLabelStage.setY(progressLabelStage.getY() + 25);
}
}
See Task documentation titled "A Task Which Modifies The Scene Graph", which provides an example:
final Group group = new Group();
Task<Void> task = new Task<Void>() {
#Override protected Void call() throws Exception {
for (int i=0; i<100; i++) {
if (isCancelled()) break;
final Rectangle r = new Rectangle(10, 10);
r.setX(10 * i);
Platform.runLater(new Runnable() {
#Override public void run() {
group.getChildren().add(r);
}
});
}
return null;
}
};
The above example add the rectangles to the scene graph via a 100 runLater calls. A more efficient way to do this would be to add the rectangles to a group not attached to the active scene graph, then only add the group to the active scene graph in the runLater call. For example:
final Group groupInSceneGraph = new Group();
Task<Void> task = new Task<Void>() {
#Override protected Void call() throws Exception {
final Group localGroup = new Group();
for (int i=0; i<100; i++) {
if (isCancelled()) break;
final Rectangle r = new Rectangle(10, 10);
r.setX(10 * i);
localGroup.getChildren().add(r);
}
Platform.runLater(new Runnable() {
#Override public void run() {
groupInSceneGraph.add(localGroup);
}
});
return null;
}
};
You can create and modify most scene graph objects off of the JavaFX application thread (including loading FXML), as long as the objects aren't attached to the active scene graph. By active scene graph I mean a scene graph which is currently attached as a scene to a displayed stage. (A complicated control such as a WebView may be an exception to this rule and may require creation on the JavaFX application thread).
You must only attach the scene graph objects created off of the JavaFX application thread to the active scene graph on the JavaFX application thread (for example using Platform.runLater()). And, you must work with them on the JavaFX application thread as long they continue to be attached to the active scene graph.
I have having trouble getting my program to take the user input from textField and displaying it in textArea. The program I'm making is a Stack/Queue program. It has a textField that a user inputs a number into. Then there is a button that takes the input and displays it in the textArea as a Stack(FILO).
Edit 1:
I am able to move the user input into the textArea now but, whenever I add a second input it just replaces the old input with the new instead of showing the list. I am supposed to use a toString method to show the whole list? Where do I need to put the toString method if I need it?
TLDR, How do I take input from textField and display it in textArea?
This is my main class.
TextField text = new TextField();
TextArea textArea = new TextArea("Text Area");
public class StackQueue extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Stack myStack = new Stack();
Button btAdd = new Button("Add");
Button btDel = new Button("Delete");
Button btClear = new Button("Clear");
BorderPane bpane = new BorderPane();
text.setPrefWidth(50);
text.setAlignment(Pos.CENTER_LEFT);
text.setText("Label");
text.clear();
textArea.setPrefColumnCount(1);
textArea.setPrefRowCount(10);
textArea.clear();
HBox hBox = new HBox();
hBox.getChildren().addAll(btAdd, btDel, btClear);
bpane.setTop(hBox);
bpane.setCenter(text);
bpane.setBottom(textArea);
Scene scene = new Scene(bpane, 500, 250);
stage.setTitle("Stack Example");
stage.setScene(scene);
stage.show();
EventHandler<ActionEvent> addEvent = event -> add();
EventHandler<ActionEvent> delEvent = event -> del();
btAdd.setOnAction(addEvent);
btDel.setOnAction(delEvent);
public void add()
{
textArea.setText(text.getText(x));
}
public void del()
{
}
}
public static void main(String[] args)
{
launch(args);
}
}
This is the Stack class.
public class Stack<E>
{
public String status = "String";
public ArrayList<E> arrayList;
public Stack()
{
arrayList = new ArrayList(10);
}
public void add(String x)
{
arrayList.add(0, (E) x);
}
//public String del
{
}
public void Clear()
{
}
}
You have included add() and del() function inside the start() function. You need to move them outside of start() function and inside of your StackQueue class.
After doing that the variables text and textArea should be created outside of start() function because the method add() and del() are trying to get the value of text and textArea variables.
Finally, you should implement the logic to handle addition and deletion of elements inside add() and del() methods.
Paste the following code in StackQueue.java file. I didn't implement the deletion functionality and you need to tweak the add() method too. I hope now you will be able to solve it.
I added a string which will get the old value of text field and append that old value when further addition is done along with the new value
public class StackQueue extends Application {
TextField text = new TextField();
TextArea textArea = new TextArea();
String oldText;
#Override
public void start(Stage stage) throws Exception
{
Stack myStack = new Stack();
Button btAdd = new Button("Add");
Button btDel = new Button("Delete");
Button btClear = new Button("Clear");
BorderPane bpane = new BorderPane();
text.setPrefWidth(50);
text.setAlignment(Pos.CENTER_LEFT);
text.setText("Label");
text.clear();
textArea= new TextArea("Text Area");
textArea.setPrefColumnCount(1);
textArea.setPrefRowCount(10);
textArea.clear();
oldText = text.getText();
HBox hBox = new HBox();
hBox.getChildren().addAll(btAdd, btDel, btClear);
bpane.setTop(hBox);
bpane.setCenter(text);
bpane.setBottom(textArea);
Scene scene = new Scene(bpane, 500, 250);
stage.setTitle("Stack Example");
stage.setScene(scene);
stage.show();
EventHandler<ActionEvent> delEvent = event -> del();
btAdd.setOnAction( e -> {
textArea.setText(oldText + text.getText());
oldText = oldText + text.getText() +"\n";
});
btDel.setOnAction(delEvent);
}
public void del()
{
}
public static void main(String[] args)
{
launch(args);
}
}
I am building an alarm and it consists of two parts
an animated button created in javafx class and the engine which is created normally
what I need is whenever user press the animated button that closes the button and fire up the engine then after the engine is closed there will be some time then animated button appears again and so on
so I used ::
notify_me.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
new engine();
Platform.exit();
}
});
and in order to repeat this process I used
Timer t = new Timer(0,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
while(true){
javafx.launch(javafx.class);
//some extra code goes here including sleep for
//some time and check for engine window state
}
}
});
t.start();
but I am facing two problems:
some extra code isn`t implemented until platform is exited,
launch() cannot be called more than once
so how can I achieve that without using threads ?? thanks
You probably won't get around using Threads. I'd recommend not shutting down the fx application thread however. Just close all windows and show (some of) them again after the delay:
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Hide me 5 sec");
// prevent automatic exit of application when last window is closed
Platform.setImplicitExit(false);
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
// timer should be a daemon (-> not prevent jvm shutdown)
Timer timer = new Timer(true);
btn.setOnAction((ActionEvent event) -> {
timer.schedule(new TimerTask() {
#Override
public void run() {
// make window reappear (needs to happen on the application thread)
Platform.runLater(primaryStage::show);
}
}, 5000l);
// hide window
primaryStage.close();
});
// allow exiting the application by clicking the X
primaryStage.setOnCloseRequest(evt -> Platform.exit());
primaryStage.show();
}
I am crazy about the feature of JavaFX, in Swing, I could do,
#Override
public void onPluginRegistered(final GamePlugin plugin) {
JRadioButtonMenuItem gameMenuItem = new JRadioButtonMenuItem(plugin.getGameName());
gameMenuItem.setSelected(false);
gameMenuItem.addActionListener(event -> {
if (core.getPlayers().isEmpty()) {
// Can't start a game with no players.
showErrorDialog(frame, ERROR_NO_PLAYERS_TITLE, ERROR_NO_PLAYERS_MSG);
gameGroup.clearSelection();
} else {
core.startNewGame(plugin);
}
});
gameGroup.add(gameMenuItem);
newGameMenu.add(gameMenuItem);
}
if I want to add a radio item whenever a plugin has registered.
However in JavaFX, it seems, you can't declare any global item of JavaFX, because once the start() is called, it starts a new constructor and everything you've done before is nothing (there is no variable share to me).
Here is my Javafx code.
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 500, 500);
scene.getStylesheets().add("./Buttons.css");
Region spacer = new Region();
spacer.setMinWidth(10);
primaryStage.setScene(scene);
primaryStage.show();
TabPane tabPane = new TabPane();
Tab tabData = new Tab("Get your data");
tabPane.getTabs().add(tabData);
Tab tabDisplay = new Tab("Visualize your data");
tabPane.getTabs().add(tabDisplay);
pluginGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>(){
#Override
public void changed(ObservableValue<? extends Toggle> ov,
Toggle old_toggle, Toggle new_toggle) {
if (pluginGroup.getSelectedToggle() != null) {
RadioButton chk = (RadioButton) new_toggle.getToggleGroup().getSelectedToggle();
chk.getText();
}
}
});
root.setCenter(tabPane);
FlowPane inputPanel = new FlowPane();
TextField source = new TextField ();
Button confirmButton = new Button("Get Your Resource!");
confirmButton.getStyleClass().add("GREEN");
inputPanel.getChildren().addAll(new Label("Input your source:"),
spacer, source, confirmButton);
root.setBottom(inputPanel);
RadioButton defaultBtn = new RadioButton("No data plugin are registered");
FlowPane pane = new FlowPane();
pane.getChildren().addAll(new Label("Select your data source"), spacer);
if (radioButtonBox != null) {
pane.getChildren().add(radioButtonBox);
}
tabData.setContent(pane);
}
#Override
public void onPluginRegistered(DataPlugin plugin) {
RadioButton button = new RadioButton(plugin.getName());
button.setToggleGroup(pluginGroup);
radioButtonBox.getChildren().add(button);
}
public void caller(String[] args) {
launch(args);
}
I want to initialize the javafx program from,
public static void main(String[] args) throws Exception {
DataFramework core = new ConcreteDataFramework();
GuiFramework gui = new GuiFramework(core);
core.addGuiListener(gui);
gui.caller(args);
core.registerPlugin(new CsvData());
}
It is weird that I can't add any radio button to the existing radioButtonBox every time I call onPluginRegistered(DataPlugin plugin) (The new radiobutton does not show up)
You should consider the start() method as the replacement for the main method. If your application needs access to some kind of service or model, create it in the start() (or init()) method. I would actually recommend making the Application subclass (which is inherently not reusable) as minimal as possible - it should just do the startup work - and factoring the remaining GUI code into a separate class. (If you use FXML, the FXML file can define the UI, and the Application subclass is then already pretty minimal: it just loads and displays the FXML.)
You haven't really provided enough context to make it clear what's going on here, but I'm guessing GuiFramework is the Application subclass you've shown part of, and DataFramework is an interface of some kind. I also assume GuiFramework is implementing some interface that defines the onPluginRegistered method.
So I would do:
public class GuiFramework implements PluginAware {
private final BorderPane root ;
private final DataFramework dataFramework ;
public GuiFramework(DataFramework dataFramework) {
this.dataframework = dataFramework ;
this.root = new BorderPane();
TabPane tabPane = new TabPane();
Tab tabData = new Tab("Get your data");
tabPane.getTabs().add(tabData);
// etc etc (remaining code from your start() method)
}
public Parent getView() {
return root ;
}
#Override
public void onPluginRegistered(DataPlugin plugin) {
RadioButton button = new RadioButton(plugin.getName());
button.setToggleGroup(pluginGroup);
radioButtonBox.getChildren().add(button);
}
}
and define a Main class for starting the application:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
DataFramework core = new ConcreteDataFramework();
GuiFramework gui = new GuiFramework(core);
core.addGuiListener(gui);
Scene scene = new Scene(gui.getView(), 500, 500);
scene.getStylesheets().add("./Buttons.css");
primaryStage.setScene(scene);
primaryStage.show();
core.registerPlugin(new CsvData());
}
// for environments not supporting JavaFX launch automatically:
public static void main(String[] args) {
launch(args);
}
}