Getting webpage opened in another tab from hyperlink of current webpage in webview of javafx browser - javafx

I have developed a very simplified but fully functional JavaFX web browser for illustrating what I want to ask. Here follows the source code.
public class OpenInNewTab extends Application {
#Override
public void start(Stage primaryStage)
{
TabPane tabPane = new TabPane();
WebView webView = new WebView();
Tab tab = new Tab("Home Tab");
tab.setContent(webView);
tabPane.getTabs().add(tab);
webView.getEngine().load("https://www.google.co.in/?gws_rd=ssl#q=javafx");
BorderPane root = new BorderPane();
root.setTop(tabPane);
Scene scene = new Scene(root, 600, 339);
primaryStage.setTitle("Basic browser");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
} }
This browser loads a web page from this link. I want that when I click on any of the search results, the clicked hyperlink should open in new tab adjacent to the existing "Home tab".
After searching on the internet extensively, I reached nowhere.
Please help me with relevant code. Thanks.

First of all, you need to find a way to handle all outgoing click events on the displayed page. I've made a helper method to achieve that. It creates an event listener for each link, clicking on which will open a new tab.
private void handleUrls(Document doc) {
NodeList links = doc.getElementsByTagName("a");
for (int i = 0; i < links.getLength(); i++) {
EventTarget eventTarget = (EventTarget) links.item(i);
String link = links.item(i).toString();
eventTarget.addEventListener("click", e -> {
WebView webView = new WebView();
alterWebView(webView);
Tab tab = new Tab(link);
tab.setContent(webView);
tab.setClosable(true);
webView.getEngine().load(link);
tabPane.getTabs().add(tab);
e.preventDefault();
}, false);
}
}
You may want to set a better name for your tab... I've used a link as a makeshift solution, but it's long and messy.
webView.getEngine().load(link);
The alterWebView referenced above is another helper function. It's responsible for tracking the loading progress. Once the Worker does nothing, it will add listeners to all urls.
private void alterWebView(WebView webView) {
WebEngine engine = webView.getEngine();
Worker worker = engine.getLoadWorker();
worker.stateProperty().addListener((oldVal, newVal, o) -> {
if (newVal.equals(State.RUNNING)) {
handleUrls(engine.getDocument());
}
});
}
So basically, the logic behind the code above is as follows:
We track our WebEngine's State until the page is fully loaded and then we add event listeners to every url.
These listeners, when invoked, will create a new WebView, handle it accordingly, and add it to the TabPane inside a new Tab.
And here's the complete, working example based on your code:
public class JavaFXTest extends Application {
private TabPane tabPane;
#Override
public void start(Stage primaryStage) {
tabPane = new TabPane();
WebView webView = new WebView();
alterWebView(webView);
Tab tab = new Tab("Home Tab");
tab.setContent(webView);
tab.setClosable(true);
tabPane.getTabs().add(tab);
webView.getEngine().load("https://www.google.co.in/?gws_rd=ssl#q=javafx");
BorderPane root = new BorderPane();
root.setTop(tabPane);
Scene scene = new Scene(root, 600, 339);
primaryStage.setTitle("Basic browser");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private void alterWebView(WebView webView) {
WebEngine engine = webView.getEngine();
Worker worker = engine.getLoadWorker();
worker.stateProperty().addListener((oldVal, newVal, o) -> {
if (newVal.equals(State.RUNNING)) {
handleUrls(engine.getDocument());
}
});
}
private void handleUrls(Document doc) {
NodeList links = doc.getElementsByTagName("a");
for (int i = 0; i < links.getLength(); i++) {
EventTarget eventTarget = (EventTarget) links.item(i);
String link = links.item(i).toString();
eventTarget.addEventListener("click", e -> {
WebView webView = new WebView();
alterWebView(webView);
Tab tab = new Tab(link);
tab.setContent(webView);
tab.setClosable(true);
webView.getEngine().load(link);
tabPane.getTabs().add(tab);
e.preventDefault();
}, false);
}
}
}

Related

Can you set icon to a Javafx Alert box? [duplicate]

I might be missing something very obvious, but I can't find out how to set the Icon for a Dialog component (ProgressDialog to be more precise). I know how to do that for a Stage:
this.primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("/icon/Logo.png")));
But I don't find anything for the Dialog family. And somehow, setting the Stage Icon does not influence the Dialog Icon.
Thanks
There's an excellent tutorial here by Marco Jakob, where you can find not only how to use dialogs, but also how to solve your problem.
Both for the new dialogs (in JDK8u40 early versions or with openjfx-dialogs with JDK 8u25), or for those in ControlsFX, in order to set the icon of your dialog, you can use this solution:
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
stage.getIcons().add(
new Image(this.getClass().getResource("<image>.png").toString()));
This code snippet shows how to use a ProgressDialog, from ControlsFX, and set an icon for the dialog:
#Override
public void start(Stage primaryStage) {
Service<Void> service = new Service<Void>() {
#Override protected Task<Void> createTask() {
return new Task<Void>() {
#Override protected Void call() throws InterruptedException {
updateMessage("Message . . .");
updateProgress(0, 10);
for (int i = 0; i < 10; i++) {
Thread.sleep(300);
updateProgress(i + 1, 10);
updateMessage("Progress " + (i + 1) + " of 10");
}
updateMessage("End task");
return null;
}
};
}
};
Button btn = new Button("Start Service");
btn.setOnAction(e -> {
ProgressDialog dialog = new ProgressDialog(service);
dialog.setTitle("Progress Dialog");
dialog.setHeaderText("Header message");
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
stage.getIcons().add(new Image(this.getClass().getResource("<image>.png").toString()));
service.start();
});
Scene scene = new Scene(new StackPane(btn), 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
Just Do like this:
Alert(AlertType.ERROR, "Erreur de connexion! Verifiez vos Identifiants",FINISH); //Cancel..
setTitle("XNotes FX Erreur");
stage = (Stage) alert.getDialogPane().getScene().getWindow();
stage.getIcons().add(new Image("indiza/XnotesErrorIdz.png")); // To add an icon
showAndWait();
Here is the result
**My friends, is it computer science that we do? : No, we do crafts
**
You can easily use the icon of your application for the alert-icon by setting your application-window as owner of the alert box:
#FXML
Button buShow;
...
Alert alert = new Alert(AlertType.INFORMATION, "Nice Box.", ButtonType.CLOSE);
alert.initOwner(buShow.getScene().getWindow()); // Alert uses the Windows Icon
alert.show();
This is a method that I include in my JavaFX projects, simply calling this method and passing the Alert as a parameter will set both the title bar icon and the header graphic.
public class Msg {
public void showInfo(String title, String header, String message) {
Alert alertShowInfo = new Alert(Alert.AlertType.INFORMATION);
addDialogIconTo(alertShowInfo); //add icon and header graphic
alertShowInfo.setTitle(title);
alertShowInfo.setHeaderText(header);
alertShowInfo.setContentText(message);
alertShowInfo.showAndWait();
}
//this adds images to Alert
public void addDialogIconTo(Alert alert) {
// Add custom Image to Dialog's title bar
final Image APPLICATION_ICON = new Image("icon.png");
Stage dialogStage = (Stage) alert.getDialogPane().getScene().getWindow();
dialogStage.getIcons().add(APPLICATION_ICON);
// Add custom ImageView to Dialog's header pane.
final ImageView DIALOG_HEADER_ICON = new ImageView("icon.png");
DIALOG_HEADER_ICON.setFitHeight(48); // Set size to API recommendation.
DIALOG_HEADER_ICON.setFitWidth(48);
alert.getDialogPane().setGraphic(DIALOG_HEADER_ICON);
}
}
Then, in whatever class I wish to use the Alert, it will already have the customized icon and header graphic.
public static void main(String[] args){
Msg msg = new Msg();
// Alert will now include custom icon and header graphic.
msg.showInfo("Sucess!", "Program succeeded", "Now exiting program");
}
Just similar to any dialog, instead this is inside a button handler.
Alert alert = new Alert(
AlertType.WARNING,
"Alert message here.",
ButtonType.OK
);
alert.initOwner(((Button)event.getSource()).getScene().getWindow());
alert.setTitle("Alert window title");
alert.showAndWait();

Allow clicks to go through application GUI

I have a JavaFx application that loads a transparent stage with some text on it.
I want any click on the application to be completely ignored and the background application (if any) to receive that click.
My code at this stage is as follows:
public void start(final Stage primaryStage) {
primaryStage.setAlwaysOnTop(true);
final StackPane layout = new StackPane();
final Text mainText = new Text();
layout.getChildren().add(mainText);
mainText.setText("|||||||||||||||||||||||||||");
final Scene mainScene = new Scene(layout);
mainScene.setFill(null);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(mainScene);
primaryStage.show();
layout.setMouseTransparent(true);
mainText.setMouseTransparent(true);
}
I was not able to achieve the requirement. setMouseTransparent() just prevented the text from triggering events, it still captured the mouse clicks.
Is it possible to achieve this in JavaFx ? Even if it is a per-OS solution.
A way of doing this action in Windows is through user32.dll and Java Native Access (JNA). We used GetWindowLong to get the current configuration of the window and SetWindowLong to update the bit field that is controlling the ability of the window be transparent to the mouse.
Following is a working example that demonstrates this functionality:
#Override
public void start(final Stage primaryStage) {
primaryStage.setAlwaysOnTop(true);
final StackPane layout = new StackPane();
final Text mainText = new Text();
layout.getChildren().add(mainText);
mainText.setText("|||||||||||||||||||||||||||");
final Scene mainScene = new Scene(layout);
mainScene.setFill(null);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(mainScene);
primaryStage.setTitle(sTitle);
primaryStage.show();
sUser32.EnumWindows(
(hWnd, data) -> {
final byte[] windowText = new byte[512];
sUser32.GetWindowTextA(hWnd, windowText, 512);
final String wText = Native.toString(windowText);
if (!wText.isEmpty() && wText.equals(sTitle)) {
final int initialStyle = com.sun.jna.platform.win32.User32.INSTANCE.GetWindowLong(hWnd, WinUser.GWL_EXSTYLE);
com.sun.jna.platform.win32.User32.INSTANCE.SetWindowLong(hWnd, WinUser.GWL_EXSTYLE, initialStyle | WinUser.WS_EX_TRANSPARENT );
return false;
}
return true;
}, null);
}

JavaFX disable button

I'm writing a program in netbeans with javaFX
The view has several buttons in it with some bad buttons(like bombs is minesweeper), I'm trying to freeze the program when a bad button is pushed but i don't find how to do it
thanks!
There are various solutions to your problem. 2 among them are simply ignoring the action event or disabling the buttons like this:
public class ButtonAction extends Application {
final BooleanProperty buttonActionProperty = new SimpleBooleanProperty();
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
FlowPane root = new FlowPane();
CheckBox checkBox = new CheckBox( "Enabled");
checkBox.setSelected(true);
// solution 1: check if action is allowed and process it or not
buttonActionProperty.bind( checkBox.selectedProperty());
Button button = new Button( "Click Me");
button.setOnAction(e -> {
if( buttonActionProperty.get()) {
System.out.println( "Allowed, processing action");
} else {
System.out.println( "Not allowed, no action");
}
});
// solution 2: remove comments to activate the code
// button.disableProperty().bind(buttonActionProperty.not());
root.getChildren().addAll(checkBox, button);
primaryStage.setScene(new Scene(root, 600, 200));
primaryStage.show();
}
}
Add a ROOT typed event filter that consumes all kind of events (mouse, keyboard etc.)
btnThatHasHiddenMine.setOnAction(( ActionEvent event ) ->
{
System.out.println("Ohh no! You just stepped over the mine!");
getGameboardPane().addEventFilter( EventType.ROOT, Event::consume );
});
Add the filter to your GameboardPane only, since we don't want to freeze other part of the app.

WebEngine not loading URL on button click

I am coding a Tabbed web browser in JAVAFx. The problem i am facing is :-
When I click on Home Button (HomeB) it is not loading the DEFAULT_URL in the current tab. Here is some useful part of my code. Some body please fix it. Thanks
class Browser extends Region{
final BorderPane borderPane;
final TabPane tabPane;
private final HBox toolbarMain;
WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
private String DEFAULT_URL= "http://www.google.com";
final TextField urlField = new TextField(DEFAULT_URL);
//Custom function for creation of New Tabs.
private Tab createAndSelectNewTab(final TabPane tabPane, final String title) {
Tab tab = new Tab(title);
webEngine.locationProperty().addListener(new ChangeListener<String>() {
#Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
urlField.setText(newValue);
}
});
final ObservableList<Tab> tabs = tabPane.getTabs();
tab.closableProperty().bind(Bindings.size(tabs).greaterThan(2));
tabs.add(tabs.size() - 1, tab);
tabPane.getSelectionModel().select(tab);
return tab;
}
//Initialization function of the program.
public Browser() {
borderPane = new BorderPane();
tabPane = new TabPane();
toolbarMain = new HBox();
Button HomeB = new Button();
HomeB.setText("HOME");
tabPane.setSide(Side.TOP);
final Tab newtab = new Tab();
newtab.setText("+");
newtab.setClosable(false); // this will not let the New Tab button(TAB) close
tabPane.getTabs().addAll(newtab); //Addition of New Tab to the tabpane.
createAndSelectNewTab(tabPane, " ");
//Function to add and display new tabs with default URL display.
tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
#Override
public void changed(ObservableValue<? extends Tab> observable,
Tab oldSelectedTab, Tab newSelectedTab) {
if (newSelectedTab == newtab) {
Tab tab = new Tab();
//WebView - to display, browse web pages.
WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
webEngine.load(DEFAULT_URL);
EventHandler<ActionEvent> goAction = new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
webEngine.load(urlField.getText().startsWith("http://")
? urlField.getText()
: "http://" + urlField.getText());
}
};
urlField.setOnAction(goAction);
final VBox vBox = new VBox(5);
vBox.getChildren().setAll(browser);
VBox.setVgrow(browser, Priority.ALWAYS);
tab.setContent(vBox);
final ObservableList<Tab> tabs = tabPane.getTabs();
tab.closableProperty().bind(Bindings.size(tabs).greaterThan(2));
tabs.add(tabs.size() - 1, tab);
tabPane.getSelectionModel().select(tab);
}
}
});
//OnClick handling HomeB
HomeB.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event){
webEngine.load(DEFAULT_URL);
}
});
toolbarMain.getChildren().addAll(HomeB,urlField);
//Placement of elements in borderpane
borderPane.setCenter(tabPane);
borderPane.setTop(toolbarMain);
getChildren().add(borderPane);
}
}
When you click on the HomeB the default URL is loaded into the browser, a global WebView. That works, but you don't see the URL loaded, because you haven't added this browser to any of your tabs.
Assuming you create the first tab for the home button:
tabPane.getTabs().addAll(newtab); // tab 0, then moves to 1
// Here you create a new tab, but put it on the 0 index:
createAndSelectNewTab(tabPane, " ");
// You can add now your global browser to the first tab:
final VBox vBoxIni = new VBox(5);
vBoxIni.getChildren().setAll(browser);
VBox.setVgrow(browser, Priority.ALWAYS);
tabPane.getTabs().get(0).setContent(vBoxIni);
Other option will be using the local webView you have created for each tab, and load the default URL on the active tab:
HomeB.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event){
VBox vBox=(VBox)tabPane.getSelectionModel().getSelectedItem().getContent();
if(vBox!=null){
WebView webView=(WebView)vBox.getChildren().get(0);
webView.getEngine().load(DEFAULT_URL);
}
}
});
Note this won't work on the first tab, since you haven't set any content there.

How to create a modal window in JavaFX 2.1

I can't figure out how to create a modal window in JavaFX. Basically I have file chooser and I want to ask the user a question when they select a file. I need this information in order to parse the file, so the execution needs to wait for the answer.
I've seen this question but I've not been able to find out how to implement this behavior.
In my opinion this is not good solution, because parent window is all time active.
For example if You want open window as modal after click button...
private void clickShow(ActionEvent event) {
Stage stage = new Stage();
Parent root = FXMLLoader.load(
YourClassController.class.getResource("YourClass.fxml"));
stage.setScene(new Scene(root));
stage.setTitle("My modal window");
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(
((Node)event.getSource()).getScene().getWindow() );
stage.show();
}
Now Your new window is REALY modal - parent is block.
also You can use
Modality.APPLICATION_MODAL
Here is link to a solution I created earlier for modal dialogs in JavaFX 2.1
The solution creates a modal stage on top of the current stage and takes action on the dialog results via event handlers for the dialog controls.
JavaFX 8+
The prior linked solution uses a dated event handler approach to take action after a dialog was dismissed. That approach was valid for pre-JavaFX 2.2 implementations. For JavaFX 8+ there is no need for event handers, instead, use the new Stage showAndWait() method. For example:
Stage dialog = new Stage();
// populate dialog with controls.
...
dialog.initOwner(parentStage);
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.showAndWait();
// process result of dialog operation.
...
Note that, in order for things to work as expected, it is important to initialize the owner of the Stage and to initialize the modality of the Stage to either WINDOW_MODAL or APPLICATION_MODAL.
There are some high quality standard UI dialogs in JavaFX 8 and ControlsFX, if they fit your requirements, I advise using those rather than developing your own. Those in-built JavaFX Dialog and Alert classes also have initOwner and initModality and showAndWait methods, so that you can set the modality for them as you wish (note that, by default, the in-built dialogs are application modal).
You can create application like my sample. This is only single file JavaFX application.
public class JavaFXApplication1 extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Stage stage;
stage = new Stage();
final SwingNode swingNode = new SwingNode();
createSwingContent(swingNode);
StackPane pane = new StackPane();
pane.getChildren().add(swingNode);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle("Swing in JavaFX");
stage.setScene(new Scene(pane, 250, 150));
stage.show();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private void createSwingContent(final SwingNode swingNode) {
SwingUtilities.invokeLater(() -> {
try {
Path currentRelativePath = Paths.get("");
String s = currentRelativePath.toAbsolutePath().toString();
JasperDesign jasperDesign = JRXmlLoader.load(s + "/src/reports/report1.jrxml");
String query = "SELECT * FROM `accounttype`";
JRDesignQuery jrquery = new JRDesignQuery();
jrquery.setText(query);
jasperDesign.setQuery(jrquery);
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
JasperPrint JasperPrint = JasperFillManager.fillReport(jasperReport, null, c);
//JRViewer viewer = new JRViewer(JasperPrint);
swingNode.setContent(new JRViewer(JasperPrint));
} catch (JRException ex) {
Logger.getLogger(AccountTypeController.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

Resources