I am writing a code for a simple web browser for my school project. Currently I want to have the code to be able to visit the site entered in the url when pressed the enter key. All of my buttons work (back, forward, refresh, etc) but I cant seem to get the keyboard event handlers working.
The error that I am currently faced with in the event handler is that its not getting the code for the enter key. I already looked at many different sources like this one Trying to get the char code of ENTER key but they havent been much help to solve my issue.
Here is the code I'm working on:
package application;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebHistory;
import javafx.scene.web.WebView;
public class Main extends Application {
private BorderPane root;
private WebView webView;
private WebEngine webEngine;
private HBox addressBar;
private HBox statusBar;
private Text domain;
private WebHistory history;
private final String homePage = "https://google.ca";
//------------------------------------------------------
private void setupAddressBar() {
addressBar = new HBox();
Button home = new Button("Home");
Button back = new Button("<--");
Button forward = new Button("-->");
Button refresh = new Button("Refresh");
TextField url = new TextField();
addressBar.getChildren().addAll(home,back,forward,refresh,url);
class HomeButton implements EventHandler<ActionEvent>{
#Override
public void handle(ActionEvent e) {
homePage();
}
}
class BackButton implements EventHandler<ActionEvent>{
#Override
public void handle(ActionEvent e) {
back();
}
}
class ForwardButton implements EventHandler<ActionEvent>{
#Override
public void handle(ActionEvent e) {
forward();
}
}
class RefreshButton implements EventHandler<ActionEvent>{
#Override
public void handle(ActionEvent e) {
refreshPage();
}
}
class KeyboardPressedHandler implements EventHandler<KeyEvent>{
#Override
public void handle(KeyEvent event) {
KeyCode key = event.getCode();
if(key == Keycode.ENTER ) {
loadPage();
}
}
}
HomeButton homeButton = new HomeButton();
home.setOnAction(homeButton);
BackButton backButton = new BackButton();
back.setOnAction(backButton);
ForwardButton forwardButton = new ForwardButton();
forward.setOnAction(forwardButton);
RefreshButton refreshButton = new RefreshButton();
refresh.setOnAction(refreshButton);
KeyboardPressedHandler pressedHandler = new KeyboardPressedHandler();
url.setOnKeyReleased(pressedHandler);
}
//----------------------------------------------------
private void setupStatusBar() {
statusBar = new HBox();
domain = new Text("google.ca");
Text separator = new Text("|");
Text copyright = new Text("JavaFX -- All Rights Reserved.");
statusBar.getChildren().addAll(domain, separator, copyright);
}
//-------------------------------------------------
public void setupWebView() {
webView = new WebView();
webEngine = webView.getEngine();
webEngine.load(homePage);
}
public void initialize(URL arg0, ResourceBundle arg1) {
webEngine = webView.getEngine();
loadPage();
}
public void loadPage() {
webEngine.load("http://" + domain.getText());
}
public void homePage() {
webEngine.load("http://google.ca");
}
public void refreshPage() {
webEngine.reload();
}
public void forward() {
history = webEngine.getHistory();
ObservableList<WebHistory.Entry> entries = history.getEntries();
history.go(1);
domain.setText(entries.get(history.getCurrentIndex()).getUrl());
}
public void back() {
history = webEngine.getHistory();
ObservableList<WebHistory.Entry> entries = history.getEntries();
history.go(-1);
domain.setText(entries.get(history.getCurrentIndex()).getUrl());
}
public void start(Stage stage) {
root = new BorderPane();
//---------------------------------
this.setupAddressBar();
this.setupWebView();
this.setupStatusBar();
//----------------------------------
root.setTop(addressBar);
root.setBottom(statusBar);
root.setCenter(webView);
//----------------------------------
Scene scene = new Scene(root);
stage.setScene(scene);
//stage.getFullScreen(true);
stage.setWidth(1200);
stage.setHeight(1000);
stage.setResizable(false);
stage.setTitle("JavaFX Browser");
stage.show();
;
}
public static void main(String[] args) {
launch(args);
}
}
Related
I am having trouble figuring out how to dynamically create nodes in JavaFX, I am trying to make an interface for a messaging program, and I would like for each message to be contained in its own node. I will not know how many messages will be sent, so I need to create new nodes as needed.
This is what I have so far I want to make it so I can add multiple MessageNode objects and have them display
package stackkoverflow.stackoverflow;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class MessageControler {
#FXML
private Label sender;
#FXML
private Label message;
private MessageNode messagenode;
public MessageControler(MessageNode messagenode){
this.messagenode = messagenode;
}
#FXML
private void initialize(){
sender.textProperty().bind(messagenode.senderProperty());
message.textProperty().bind(messagenode.messageProperty());
}
}
package stackkoverflow.stackoverflow;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class MessageNode {
private StringProperty sender = new SimpleStringProperty();
private StringProperty message = new SimpleStringProperty();
public MessageNode(String sender, String message){
this.sender.set(sender);
this.message.set(message);
}
public String getSender(){
return sender.get();
}
public String getMessage(){
return message.get();
}
public void setSender(String sender) {
this.sender.set(sender);
}
public void setMessage(String message) {
this.message.set(message);
}
public StringProperty senderProperty(){
return sender;
}
public StringProperty messageProperty(){
return message;
}
}
package stackkoverflow.stackoverflow;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class test extends Application {
#Override
public void start(Stage primaryStage) {
MessageNode messageNodeTest = new MessageNode("user","hello world");
MessageNode messageNodeTest1 = new MessageNode("user","hello world");
MessageNode messageNodeTest2 = new MessageNode("user","hello world");
MessageNode messageNodeTest3 = new MessageNode("user","hello world");
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Display.fxml"));
MessageControler controller = new MessageControler(messageNodeTest);
loader.setController(controller);
primaryStage.setScene(new Scene(loader.load()));
primaryStage.show();
}catch (IOException ie){
ie.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
You can load the FXML and display each instance in a ListCell, adding the MessageNodes to a ListView<MessageNode>.
First, change your MessageController class so the MessageNode (note: I would rename this class Message, since it's data and not scene graph nodes) can be changed. This is important, because you only want to load the FXML once for each cell, not once for every item:
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class MessageController {
#FXML
private Label sender;
#FXML
private Label message;
private MessageNode messageNode ;
public void setMessageNode(MessageNode messageNode){
this.messageNode = messageNode ;
sender.textProperty().unbind();
message.textProperty().unbind();
if (messageNode == null) {
sender.setText("");
message.setText("");
} else {
sender.textProperty().bind(messageNode.senderProperty());
message.textProperty().bind(messageNode.messageProperty());
}
}
}
Now you can do this:
// injected by FXML or just created in code, as needed:
ListView<MessageNode> listView ;
// ...
listView.setCellFactory(lv -> new ListCell<>() {
private Node graphic ;
private MessageController controller ;
{
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Display.fxml"));
graphic = loader.load();
controller = loader.getController();
} catch (Exception exc) {
exc.printStackTrace();
}
}
#Override
protected void updateItem(MessageNode message, boolean empty) {
super.updateItem(message, empty);
controller.setMessageNode(message);
if (empty || message == null) {
setGraphic(null);
} else {
setGraphic(graphic);
}
}
});
And of course do
listView.getItems().add(new MessageNode(...));
any time you need.
I am new in Java FX. I expect to close my JavaFX application if the user is inactive for a period of time. In other words App is closed automatically if there are no any mouse event or Key event in for duration It's likely Sleep Mode of Window
I did try the code from Auto close JavaFX application due to innactivity. However My Program doesn't work
I get an example from https://www.callicoder.com/javafx-fxml-form-gui-tutorial/ .
And I edited on RegistrationFormApplication Class
public class RegistrationFormApplication extends Application {
private Timeline timer;
Parent root ;
#Override
public void start(Stage primaryStage) throws Exception{
timer = new Timeline(new KeyFrame(Duration.seconds(3600), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
root = null;
try {
root = FXMLLoader.load(getClass().getResource("/example/registration_form.fxml"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
primaryStage.setTitle("Registration Form FXML Application");
primaryStage.setScene(new Scene(root, 800, 500));
primaryStage.show();
}
}));
timer.setCycleCount(Timeline.INDEFINITE);
timer.play();
root.addEventFilter(MouseEvent.ANY, new EventHandler<Event>() {
#Override
public void handle(Event event) {
timer.playFromStart();
}
});
Thanks for help
Get RxJavaFx and run the code. After 4 seconds of inactivity (lack of any events) it will close the app.
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.InputEvent;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class CloseAfterApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(new TextField());
PublishSubject<InputEvent> sceneEventPublishable = PublishSubject.create();
PublishSubject<WindowEvent> windowEventPublishable = PublishSubject.create();
scene.addEventFilter(InputEvent.ANY, sceneEventPublishable::onNext);
stage.addEventFilter(WindowEvent.ANY, windowEventPublishable::onNext);
Observable.merge(sceneEventPublishable, windowEventPublishable)
.switchMap(event -> Observable.just(event).delay(4, TimeUnit.SECONDS, Schedulers.single()))
.subscribe(event -> Platform.exit());
stage.setScene(scene);
stage.show();
}
}
Update:
I want to have the media player static but it does not work if i make is static.
Please note that the reason i want mediaPlayer static is that i want to access it from other classes.(the line is commented.)
This is my code:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import java.net.URL;
public class Main extends Application {
static boolean isSoundOn = false;
static double soundVolume = .5;
MediaPlayer mediaPlayer = new MediaPlayer(new Media(Main.class.getResource("song.mp3").toString()));
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
mediaPlayer.play();
primaryStage.setTitle("duet by what");
// primaryStage.setFullScreen(true);
//Group gamePaused = new Group();
//Scene _gamePaused = new Scene(gamePaused, 1200, 700);
//Group gameOver = new Group();
//Scene _gameOver = new Scene(gameOver, 1200, 700);
//Group game = new Group();
//Scene _game = new Scene(game, 1200, 700);
GUI gui = new GUI();
primaryStage.setScene(gui.getMainMenu().getScene());
primaryStage.show();
}
}
class GUI {
private MainMenu mainMenu = new MainMenu();
public class MainMenu {
private Scene scene;
private MainMenu() {
VBox vBox = new VBox();
scene = new Scene(vBox, 400, 500);
scene.getStylesheets().add("stylesheet.css");
Label info = new Label(
"welcome the the what version\n" +
"of the well known Duet game!\n\n" +
"press \"I wanna play!\" to begin the game.\n\n" +
"please note that you can change\n" +
"the sound settings.");
info.setId("info");
vBox.getChildren().add(info);
Button startGame = new Button("i wanna play right now!");
startGame.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("game started!");
}
});
vBox.getChildren().add(startGame);
Label highScore = new Label("__highScore should be added here__");
highScore.setId("highScore");
vBox.getChildren().add(highScore);
Button quitGame = new Button("get me out of this game!");
quitGame.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("game quitted!");
}
});
vBox.getChildren().add(quitGame);
CheckBox soundOn = new CheckBox("soundOn?");
Tooltip tooltip = new Tooltip("if this box is checked, music will be played!");
tooltip.setFont(new Font("Arial", 16));
soundOn.setTooltip(tooltip);
soundOn.selectedProperty().addListener(new ChangeListener<Boolean>() {
public void changed(ObservableValue<? extends Boolean> ov,
Boolean old_val, Boolean new_val) {
Main.isSoundOn = soundOn.isSelected();
System.out.println(Main.isSoundOn);
}
});
vBox.getChildren().add(soundOn);
HBox changeVolumeWrapper = new HBox();
changeVolumeWrapper.setId("hBox");
Label sliderLabel = new Label("sound volume: ");
changeVolumeWrapper.getChildren().add(sliderLabel);
Slider soundVolume = new Slider(0, 1, .5);
soundVolume.valueProperty().addListener(new ChangeListener<Number>() {
public void changed(ObservableValue<? extends Number> ov,
Number old_val, Number new_val) {
Main.soundVolume = new_val.doubleValue();
//Main.mediaPlayer.setVolume(Main.soundVolume); here is why i need media player static.
System.out.printf("%.2f\n", Main.soundVolume);
}
});
changeVolumeWrapper.getChildren().add(soundVolume);
vBox.getChildren().add(changeVolumeWrapper);
}
public Scene getScene() {
return scene;
}
}
public MainMenu getMainMenu() {
return mainMenu;
}
}
Any other fixes to my code will be appreciated.
By the way, these are the errors i get:
Exception in thread "Thread-0" java.lang.IllegalStateException:
Toolkit not initialized at
com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
at
com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
at javafx.application.Platform.runLater(Platform.java:83) at
javafx.scene.media.Media$_MetadataListener.onMetadata(Media.java:541)
at
com.sun.media.jfxmediaimpl.MetadataParserImpl.done(MetadataParserImpl.java:120)
at
com.sun.media.jfxmediaimpl.platform.java.ID3MetadataParser.parse(ID3MetadataParser.java:237)
at
com.sun.media.jfxmediaimpl.MetadataParserImpl.run(MetadataParserImpl.java:103)
Exception in thread "main" java.lang.ExceptionInInitializerError at
java.lang.Class.forName0(Native Method) at
java.lang.Class.forName(Class.java:264) at
com.intellij.rt.execution.application.AppMain.main(AppMain.java:122)
Caused by: java.lang.IllegalStateException: Toolkit not initialized
at
com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
at
com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
at javafx.application.Platform.runLater(Platform.java:83) at
javafx.scene.media.MediaPlayer.init(MediaPlayer.java:515) at
javafx.scene.media.MediaPlayer.(MediaPlayer.java:414) at
Main.(Main.java:22) ... 3 more
Calling getClass() without an object for context is interpreted the same as any other instance method: this.getClass().
In a static context, you can reference the class with ClassName.class; i.e. you can do
static URL resource = Main.class.getResource("a.mp3");
However, it is not at all clear in this scenario why you would want these variables to be static; only one instance of an Application subclass should ever be created per JVM instance, and these are inherently properties of that instance.
In the specific example in your (updated) question, I would define a separate class encapsulating the MediaPlayer and the other properties you currently make static. Note that MediaPlayer itself defines a volume property and a muted property. So you could do:
public class SoundPlayer {
private final MediaPlayer mediaPlayer ;
public SoundPlayer(URL url) {
this.mediaPlayer = new MediaPlayer(new Media(url));
}
public void play() {
mediaPlayer.play();
}
public double getVolume() {
return mediaPlayer.getVolume();
}
public void setVolume(double volume) {
mediaPlayer.setVolume(volume);
}
public boolean isSoundOn() {
return ! mediaPlayer.isMuted();
}
public void setSoundOn(boolean soundOn) {
mediaPlayer.setMuted(! soundOn);
}
}
Now your Main class can be:
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
SoundPlayer soundPlayer = new SoundPlayer(getClass().getResource("song.mp3"));
soundPlayer.play();
primaryStage.setTitle("duet by Aran Mohyeddin");
GUI gui = new GUI(soundPlayer);
primaryStage.setScene(gui.getMainMenu().getScene());
primaryStage.show();
}
}
and update your GUI and MainMenu classes to have a reference to a SoundPlayer:
public class MainMenu {
private Scene scene;
private final SoundPlayer soundPlayer ;
private MainMenu(SoundPlayer soundPlayer) {
this.soundPlayer = soundPlayer ;
// existing code omitted...
CheckBox soundOn = new CheckBox("soundOn?");
Tooltip tooltip = new Tooltip("if this box is checked, music will be played!");
tooltip.setFont(new Font("Arial", 16));
soundOn.setTooltip(tooltip);
soundOn.selectedProperty().addListener(new ChangeListener<Boolean>() {
public void changed(ObservableValue<? extends Boolean> ov,
Boolean old_val, Boolean new_val) {
soundPlayer.setSoundOn(new_val);
}
});
// ...
Slider soundVolume = new Slider(0, 1, .5);
soundVolume.valueProperty().addListener(new ChangeListener<Number>() {
public void changed(ObservableValue<? extends Number> ov,
Number old_val, Number new_val) {
soundPlayer.setVolumn(new_val.doubleValue());
System.out.printf("%.2f\n", Main.soundVolume);
}
});
changeVolumeWrapper.getChildren().add(soundVolume);
vBox.getChildren().add(changeVolumeWrapper);
}
public Scene getScene() {
return scene;
}
}
public MainMenu getMainMenu() {
return mainMenu;
}
}
Also note that if you expose the actual property objects from SoundPlayer, for example:
public class SoundPlayer {
private final MediaPlayer mediaPlayer ;
// ...
public DoubleProperty volumeProperty() {
return mediaPlayer.volumeProperty();
}
// ...
}
then you can simplify some of your code:
Slider soundVolume = new Slider(0, 1, .5);
// instead of the listener, just do:
soundPlayer.volumeProperty().bindBidirectional(soundVolume.valueProperty());
(Converting the mutedProperty to a soundOnProperty is a little less elegant.)
I am making a highly interactive TabPane for viewing contact lists in JavaFX 8. For this I have made my own subclass of Tab, EditableTab, which has functionality for changing the name of the tab by double clicking on the name in the overview. When the user clicks the + sign to create a new contact list, I want the program to create a new tab, select it, then focus the name and select all the text - it is natural to name the contact list at once (similar to when you create a new file in windows).
My problem: This seems to be very unstable. Most of the times, it seems some kind of animation/transition problem arises, and the tab name ends up empty. Here is a screenshot of what usually, but not always, happens when the + button is clicked:
And here is what I want:
Here is the code for my EditableTab:
public class EditableTab extends Tab {
private Label lbl;
private TextField txtField;
public EditableTab(String text, Node content) {
super();
setContent(content);
lbl = new Label(text);
txtField = new TextField(text);
txtField.setStyle("-fx-background-color: transparent");
setGraphic(lbl);
setupInteractivity();
}
public TextField getTextField() {
return txtField;
}
private void setupInteractivity() {
lbl.setOnMouseClicked((mouseEvent) -> {
if (mouseEvent.getClickCount() == 2) {
showTextField();
}
});
txtField.setOnAction(event -> setGraphic(lbl));
txtField.focusedProperty().addListener(
(observable, oldValue, newValue) -> {
if (! newValue) {
lbl.setText(txtField.getText());
setGraphic(lbl);
}
});
}
public void showTextField() {
txtField.setPrefWidth(lbl.getWidth());
txtField.setText(lbl.getText());
setGraphic(txtField);
txtField.selectAll();
txtField.requestFocus();
}
}
And here is the code where the functionality is implemented:
private void addNewContactlist() {
Contactlist newList = new Contactlist();
newList.setName("New contact list");
contactlistApp.getContactlistData().add(newList);
ListView<Person> lv = new ListView<Person>(newList.getContacts());
setupListView(lv);
int position = tabPane.getTabs().size() - 1;
EditableTab tab = createEditableTab("New contact list", lv);
tabPane.getTabs().add(position, tab);
tabPane.getSelectionModel().select(tab);
tab.showTextField();
}
I suspect that the problem comes from some animation/transition timings, but that is really just a guess. I tried wrapping the showTextField() call in a Platform.runLater() with no luck.
Here is a small test app to replicate the issue:
public class TestApp extends Application {
TabPane tabPane = new TabPane();
#Override
public void start(Stage primaryStage) throws Exception {
Tab addNewContactlistTab = new Tab();
addNewContactlistTab.setClosable(false);
Label lbl = new Label("\u2795");
lbl.setOnMouseClicked(mouseEvent -> {
if (tabPane.getTabs().size() == 1) {
addNewTab();
}
});
addNewContactlistTab.setGraphic(lbl);
tabPane.getTabs().add(addNewContactlistTab);
addNewContactlistTab.selectedProperty().addListener(
(observable, oldValue, newValue) -> {
if (newValue && tabPane.getTabs().size() != 1) {
addNewTab();
}
});
Scene scene = new Scene(tabPane);
primaryStage.setScene(scene);
primaryStage.setWidth(600);
primaryStage.setHeight(400);
primaryStage.show();
}
private void addNewTab() {
int insertionIndex = tabPane.getTabs().size() - 1;
ListView<String> lv = new ListView<String>();
EditableTab tab = new EditableTab("Unnamed", lv);
tabPane.getTabs().add(insertionIndex, tab);
tabPane.getSelectionModel().select(tab);
tab.showTextField();
}
public static void main(String[] args) {
launch();
}
}
Here is my code for the RenamableTab class:
import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TextField;
public class RenamableTab extends Tab {
private final Label label;
private final TextField textField;
public RenamableTab() {
this("New Tab", null);
}
public RenamableTab(String text) {
this(text, null);
}
public RenamableTab(String text, Node content) {
super();
label = new Label(text);
textField = new TextField(text);
setContent(content);
textField.setStyle("-fx-background-color: transparent");
setGraphic(label);
label.setOnMouseClicked((mouseEvent) -> {
if (mouseEvent.getClickCount() == 2) {
rename();
}
});
textField.setOnAction(event -> setGraphic(label));
textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
label.setText(textField.getText());
setGraphic(label);
}
});
}
public TextField getTextField() {
return textField;
}
public void rename() {
//textField.setPrefWidth(label.getWidth());
//textField.setText(label.getText());
setGraphic(textField);
new Thread() {
#Override
public void run() {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Platform.runLater(new Runnable() {
#Override
public void run() {
textField.selectAll();
textField.requestFocus();
}
});
}
}.start();
}
}
And here is my code for the FancyTabPane:
import javafx.event.EventHandler;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.MouseEvent;
public class FancyTabPane extends TabPane {
public FancyTabPane() {
Tab newTabTab = new Tab();
newTabTab.setClosable(false);
Label addLabel = new Label("\u2795");
addLabel.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent paramT) {
System.out.println("mouse click");
addTab();
}
});
/*
* getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
* #Override
* public void changed(ObservableValue<? extends Tab> paramObservableValue, Tab paramT1, Tab
* paramT2) {
* System.out.println("model");
* if (paramT1 == newTabTab) {
* System.out.println("tab");
* addTab();
* }
* }
* });
*/
newTabTab.setGraphic(addLabel);
getTabs().add(newTabTab);
}
public void addTab() {
RenamableTab newTab = new RenamableTab();
getTabs().add(getTabs().size() - 1, newTab);
getSelectionModel().select(newTab);
newTab.rename();
}
}
I am having issued with the new tab button when another tab is selected, not sure how you overcame that.
I want to use thread I can use in simple program, but I can't use threads in fxml controller
Simple program:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javafxapplication3;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* #web http://java-buddy.blogspot.com/
*/
public class JavaFX_TimerTask extends Application {
final int MAX = 100;
Thread myTaskThread;
Thread myRunnableThread;
Timer myTimer;
MyTask myTask;
MyRunnable myRunnable;
MyTimerTask myTimerTask;
#Override
public void start(Stage primaryStage) {
myTask = new MyTask();
ProgressBar progressBarTask = new ProgressBar();
progressBarTask.setProgress(0);
progressBarTask.progressProperty().bind(myTask.progressProperty());
ProgressBar progressBarRunnable = new ProgressBar();
progressBarRunnable.setProgress(0);
myRunnable = new MyRunnable(progressBarRunnable);
ProgressBar progressBarTimerTask = new ProgressBar();
progressBarTimerTask.setProgress(0);
myTimerTask = new MyTimerTask(progressBarTimerTask);
Button btnStart = new Button("Start Task");
btnStart.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
myTaskThread = new Thread(myTask);
myTaskThread.start();
myRunnableThread = new Thread(myRunnable);
myRunnableThread.start();
myTimer = new Timer();
myTimer.scheduleAtFixedRate(myTimerTask, 80, 100);
}
});
VBox vBox = new VBox();
vBox.setPadding(new Insets(5, 5, 5, 5));
vBox.setSpacing(5);
vBox.getChildren().addAll(
new Label("Run in Thread(Task)"),
progressBarTask,
new Label("Run in Thread(Runnable)"),
progressBarRunnable,
new Label("Run in Timer and TimerTask"),
progressBarTimerTask,
btnStart);
StackPane root = new StackPane();
root.getChildren().add(vBox);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("java-buddy.blogspot.com");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
class MyTask extends Task<Void>{
#Override
protected Void call() throws Exception {
for (int i = 1; i <= MAX; i++) {
updateProgress(i, MAX);
Thread.sleep(100);
}
return null;
}
}
class MyRunnable implements Runnable{
ProgressBar bar;
public MyRunnable(ProgressBar b) {
bar = b;
}
#Override
public void run() {
for (int i = 1; i <= MAX; i++) {
final double update_i = i;
//Not work if update JavaFX UI here!
//bar.setProgress(i/MAX);
//Update JavaFX UI with runLater() in UI thread
Platform.runLater(new Runnable(){
#Override
public void run() {
bar.setProgress(update_i/MAX);
}
});
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(JavaFX_TimerTask.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
class MyTimerTask extends TimerTask{
ProgressBar bar;
double count;
public MyTimerTask(ProgressBar b) {
bar = b;
count = 0;
}
#Override
public void run() {
bar.setProgress(count++/MAX);
if(count >= MAX){
myTimer.cancel();
}
}
}
}
Now, I want to use thread in a fxml controller:
public class DashboardController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
}
}
When I use thread, in initialize it doesn't show me any output.
How can I use thread?
Thank you.
JavaFx already runs threads -
JavaFx thread for GUI
Launch thread for background services.
If you need to make something like progress bar in which you want to run something over javafx thread then i would suggest use Services instead of thread as it can be used again and again while threads can't be.
Service<Void> ser = new Service<Void>() {
#Override protected Task createTask() {
return new Task<Void>() {
#Override protected Void call() throws InterruptedException {
// You code you want to execute in service backgroundgoes here
return null;
}
};
}
};
ser.setOnSucceeded((WorkerStateEvent event) -> {
// Anything which you want to update on javafx thread (GUI) after completion of background process.
});
ser.start();
You can use the service again and again with any variation like loop/recursion/switch -
ser.restart(); // Restart the service
ser.reset(); // Stops the service
Is your Controller initialized?
Do you set it (in the fxml/FXMLoader)?
If it your Controller is loaded this should work.
public class DashboardController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
myTask = new MyTask();
myTaskThread = new Thread(myTask);
myTaskThread.start();
}
}