JavaFX WebView does not render visual content on a Dialog<T> - java

The following code shows a weird behavior in JDK 9.0.1 (Windows):
Dialog Snippet
Dialog<Void> dialog = new Dialog<>();
WebView webView = new WebView();
dialog.getDialogPane().setContent(webView);
webView.getEngine().load("http://docs.oracle.com/javafx/");
dialog.show();
The WebView actually loads, but it does not render the web content to the GUI.
Proof Snippet
I had the following code (I edited it for simplicity sake)
private void loadSite(String url) throws IOException {
CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
URI uri = URI.create(url);
Map<String, List<String>> headers = new HashMap<>();
CookieHandler.getDefault().put(uri, headers);
webEngine.getLoadWorker().stateProperty()
.addListener((observable, oldValue, newValue) -> {
System.out.println(newValue);
if (newValue == Worker.State.SUCCEEDED) {
System.out.println(cookieManager.getCookieStore().getCookies());
}
});
webEngine.load(url);
}
This snippet is used to print cookies from a fully loaded page. The worker reaches State.SUCCEEDED and the cookies get printed out, but the WebView doesn't render the web page.
Working Snippet
I tried the following snippet and it worked, the WebView actually renders the web page to the GUI:
Stage stage = new Stage();
final WebView webView = new WebView();
webView.getEngine().load("http://docs.oracle.com/javafx/");
stage.setScene(new Scene(webView));
stage.show();
The Dialog Snippet works with JDK 8 but not JDK 9.
Side by side comparison
Stage Snippet left, Dialog Snippet Right
Actual Question
Am I doing something wrong? why is this happening? I read some of the JDK 9 changes, but I didn't see anything relatable.
Thanks in advance for any colaboration.

I have similar issue with rendering content into a JfxPanel and it is rendering blank but HTML content can be printed in my java console. (I'm using JxBrowser but they are very similar)
I solved the issue by making the webEngine rendering Mode from Heavy Weight to Light Weight.
Essentially Swing/JavaFx components are light weight for the most part, if we stack a heavy weight component inside a light weight component it will have rendering problems.
Hope this helps!

I have got exactly the same issue. When I show the WebView in another context (e.g. in a TabView (within a Tab)) the HTML-file is shown properly. But when I use
dialog.getDialogPane().setContent(webView);
it is not. My code is pretty much the same as the Dialog Snippet above (except the location of the HTML-file) and I cannot figure out the problem.
Not even simple HTML with just one headline is displayed.

Related

WebDriverException when clicking the OK button on a Anyline dialog

So all I want to do is clicking on dialog that only pops up on the iOS Simulator (iOS 14.5, Appium Java-Client 7.3.0).
The dialog comes from Anyline because of course I have no camera on the simulator.
If there is any way to hide this dialog it would solve my problem too, I tried this with capabilities but it doesn't worked.
cap.setCapability("autoAcceptAlerts", false);
cap.setCapability("autoDismissAlerts", false);
Selecting the dialog is no problem, i can check that the Dialog is here:
#iOSXCUITFindBy(accessibility = "Anyline SDK cutout UI")
public IOSElement anylineDialog;
This is how it looks like:
So the next step would be to just click the ok button it worked at the beginning but now I can't even select it in the Appium Inspector anymore. Before I just used this:
#iOSXCUITFindBy(accessibility = "OK")
public IOSElement okButton;
I don't know why it doens't work anymore, but I can still select it with the help of TestProject.
I tested a lot of different selectors but it doesn't worked. (the one with accessibility = "OK" is also recommended in this tool)
I always get this exception and I don't know how to fix it, try catch also doesn't work:
org.openqa.selenium.WebDriverException: An unknown server-side error occurred while processing the command. Original error: *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
I tried out the stuff on this page and I also get the OK button as the only button as this code snippet shows.
HashMap<String, String> args = new HashMap<>();
args.put("action", "getButtons");
List<String> buttons = (List<String>)driver.executeScript("mobile: alert", args);
Also from the same site, I tried this with the same result.
args.put("action", "accept");
args.put("buttonLabel", "OK");
driver.executeScript("mobile: alert", args);
Maybe this is to specific but if someone has an idea how I could solve it, I would be very thankful.
The iOS bug you mentioned has been fixed in Appium 1.22.1 and 2.0.0-beta. Be sure you are running one of those versions and you should be fine.

JavaFX resizing webview problem on 2 monitors

I'm new to javaFX and I'm using the webview. Everything works fine on my small monitor and I can see all the content of the webview. But when I drag my application to my bigger monitor (1920 x 1080) resolution. I can only see a part of the webview.
This is how the WebView looks like on my bigger monitor:
As you can see i can not see all the content of the webview on my bigger monitor.
I than tried resizing the webview like this so I can see all the content on my bigger monitor:
double height = Screen.getPrimary().getBounds().getHeight();
double width = Screen.getPrimary().getBounds().getWidth();
StackPane root = new StackPane();
//Create WebView
WebView view = new WebView();
view.setMinWidth(width);
view.setMinHeight(height);
The problem now is that the webview height and width is to big for my smaller screen.
I'm displaying my webview in a tab of a tabpane like this:
tabPane.getTabs().add(tab1);
tab1.setContent(view);
How can I make it so that the webview size will adjust to the current screen the stage currently is?
Any kind of help is appreciated
First of all - I highly recommend you to work with SceneBuilder (Drag & Drop user interface design): https://gluonhq.com/products/scene-builder/
SceneBuilder stores the view in a FXML file, and you can use it as follows:
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
I also recommend you to work with IntelliJ:
https://www.jetbrains.com/help/idea/javafx.html
If you do so, you can set the value of pref width/height property to USE_COMPUTED_SIZE over the SceneBuilder GUI, that would solve your problem.
Another (ugly) solution without SceneBuilder would be:
setMinWidth(getWidth());
setMinHeight(getHeight());

JavaFX WebEngine Executing Javascript Sequentially To Do Actions on the Website

I want to use JavaFX WebEngine in such a way that I can execute Javascript code in order to fill one form and click submit button on the website I opened. I was using ChromeDriver but I didn't like certain aspects of it, WebView fits better for my needs, but as far as I researched, the only way to make sure a page is loaded is to add a state listener to WebEngine and when it's SUCCEEDED, make operations on webpage. However, when I execute Javascript and submit a form, a new webpage opens so it's SUCCEEDED for the second time (first time, opens webpage that contains the form) and it executes the same form-filling code in listener. I want to execute other Javascript code after submitting the form but I couldn't find a good way to do that. In ChromeDriver, I could simply wait for certain amount of time, but with WebView case, because it executes in UI thread, I can't do that. Thanks.
I'm not sure if that's what you mean. SUCCEEDED is just a information about state of engine, to be more accurate you should check other parameters, for instance: If you want to handle different pages inside one listener, you can use location-based (currently loaded url) verification.
WebEngine engine = webView.getEngine();
engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != State.SUCCEEDED) {
return;
}
String location = engine.getLocation();
if (location.contains("page1")) {
// Do something
return;
}
if (location.contains("page2")) {
// Do something
return;
}
System.out.println("Unhandled location: " + location);
});

How to get html of fully loaded page (with javascript) as input in java?

I need to parse page, everything is ok except some elements on page are loaded dynamically. I used jsoup for static elements, then when I realized that I really need dynamic elements I tried javafx. I read a lot of answeres on stackoverflow and there were many recommendations to use javafx WebEngine. So I ended with this code.
#Override
public void start(Stage primaryStage) {
WebView webview = new WebView();
final WebEngine webengine = webview.getEngine();
webengine.getLoadWorker().stateProperty().addListener(
new ChangeListener<State>() {
public void changed(ObservableValue ov, State oldState, State newState) {
if (newState == Worker.State.SUCCEEDED) {
Document doc = webengine.getDocument();
//Serialize DOM
OutputFormat format = new OutputFormat (doc);
// as a String
StringWriter stringOut = new StringWriter ();
XMLSerializer serial = new XMLSerializer (stringOut, format);
try {
serial.serialize(doc);
} catch (IOException e) {
e.printStackTrace();
}
// Display the XML
System.out.println(stringOut.toString());
}
}
});
webengine.load("http://detail.tmall.com/item.htm?spm=a220o.1000855.0.0.PZSbaQ&id=19378327658");
primaryStage.setScene(new Scene(webview, 800, 800));
primaryStage.show();
}
I made string from org.w3c.dom.Document and printed it. But it was useless too. primaryStage.show() showed me fully loaded page (with element I need rendered on page), but there was no element I need in html code (in output).
This is the third day I'm working on that issue, of course lack of experience is my main problem, nevertheless I have to say: I'm stuck. This is my first java project after reading java complete reference. I make it to get some real-world experience (and for fun). I want to make parser of chinese "ebay".
Here is the problem and my test cases:
http://detail.tmall.com/item.htm?spm=a220o.1000855.0.0.PZSbaQ&id=19378327658
need to get dynamically loaded discount "129.00"
http://item.taobao.com/item.htm?spm=a230r.1.14.67.MNq30d&id=22794120348
need "15.20"
As you can see, if you view this pages with browser at first you see original price and after a second or so - discount.
Is it even possible to get this dynamic discounts from html page? Other elements I need to parse are static. What to try next: another library to render html with javascript or maybe smth else? I really need some advice, don't want to give up.
DOM model returned after Worker.State.SUCCEEDED shoulb be already processed by javascript.
Your code worked for me with tested with FX 7u40 and 8.0 dev. I see next output in the log:
<DIV id="J_PromoBox"><EM class="tb-promo-price-type">夏季新品</EM><EM class="tm-yen">¥</EM>
<STRONG class="J_CurPrice">129.00</STRONG></DIV>
which is dynamically loaded box with data (129.00) you looked for.
You may want to upgrade your JDK to 7u40 or revisit your log parsing algorithm.
It sounds like you want the rendered DOM from a dynamic page after the Javascript on the page has finished modifying the original HTML. This would not be easy to do in Java as you would need to implement browser-like functionality with an embedded Javascript engine. If you only care about reading a web page from Java, you might want to look into Selenium since it takes control of a browser and allows you to pull the rendered HTML into Java.
This answer might also help:
Render JavaScript and HTML in (any) Java Program (Access rendered DOM Tree)?

Wrapping/decorating GWT FileUpload

GWT FileUpload comes as a widget that produces so that one can upload a file during form submit (at least it's how I understand it :) ) What I want to do is to make it a better-looking and get rid of standard "Browse..." button.
Since I don't have good GWT experience (and no JavaScript), I looked for existing solutions and found quite a good project - gwtupload. It's good, but I realized I'd love to have my own miniature version (and also, I was curious about how it works). So I browsed through code and tried to extract the magic part. I realized that GWT FileInput is used, but it's not shown, and Button clicks are delegated to this FileInput. The code I tried to extract (only the part that delegates the click) after reviewing sources of gwtupload contains this tricky elem.click() JSNI:
class MyUpload extends Composite {
private static native void clickOnInputFile(Element elem) /*-{
elem.click();
}-*/;
public MyUpload() {
final FileUpload upload = new FileUpload();
AbsolutePanel container = new AbsolutePanel();
// container.add(upload);
Button btn = new Button("My Browse..");
btn.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
clickOnInputFile(upload.getElement());
}
});
container.add(btn);
initWidget(container);
}
}
But this seems not to work: clicking on 'My Browse..' results in no effect (just in case I also tried running with un-commented container.add(upload) line) . Could you please help me in understanding what's wrong/missing in this code sample?
Thank you in advance.
P.S. I know that I have to place it on the FormPanel, and I know the rest about how to perform the actual submit/handling in Servlet; the only thing I want to do is this kind of decoration.
Since I have not received any answers, I had to have more investigation of this issue, so I performed a deeper code analysis of gwtupload project in order to understand how GWT FileUpload (which gets transformed into ) can be decorated.
It turned out that element.click() will only work in browsers which support #click() method (IE, Chrome, Safari). Actually, Manuel Carrasco Moñino - project author - mentions it within comments. There's second approach (for Firefox & Opera) that uses hack when FileInput is placed on transparent panel, which however is placed over some decorated button (using absolute positioning); comment by Manuel:
When the user puts his mouse over the button and clicks on it, what really happens is that the user clicks on the transparent file input showing the choose file dialog.
After that, the main work is correctly applying style attributes to elements.
Thus, there are two implementations of custom file upload component, and GWT deferred binding is used to instantiate them depending on Browser.
As for example I mention in my question, there're few fixes ("upload" has to be added to to the container, and it can be set to #setVisible(false)):
class MyUpload extends Composite {
private static native void clickOnInputFile(Element elem) /*-{
elem.click();
}-*/;
public MyUpload() {
final FileUploadWithMouseEvents upload = new FileUploadWithMouseEvents();
AbsolutePanel container = new AbsolutePanel();
container.add(upload);
upload.setVisible(false);
Button btn = new Button("My Browse..");
btn.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
clickOnInputFile(upload.getElement());
}
});
container.add(btn);
initWidget(container);
}
}
This example works fine in IE8.
P.S. Thanks to Manuel for his great library :)

Categories

Resources