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);
});
Related
I have a Webview component inside a JavaFX Program (using FXML) and I want to open it to an external html which is supposed to be a loading screen. (it is necessary due to other background tasks getting perfomed like checking for the existence of a file every 5 seconds)
Then after 5 seconds It is supposed to open the real html file (in this example : "google.com") and should open it.
The problem I've run into is that when i put a delay right after the first engine.load(""); and then after the delay another engine.load(""); with the proper website it will wait that time and then just open the second website without ever opening the first.
So Using a delay without an additional Thread made the Program only open after that time has passed and only opened the second WebEngine.
Using a Thread worked when i put in Thread.sleep(5000); and after that only System.out.println("Hello World!"); but if I put anything related to JavaFX it gives the error that it cannot update the UI outside of Main Thread
I haven't found an option to update the WebEngine Method to load a different website since i am unable to access it outside of my loading Method and Updating it from a different Thread is not allowed.
Using Platform.runLater() has given me nothing but errors because the WebEngine is either not recognized as the same Engine and gives the error that it cannot find the object or it gives the error that JavaFX cant update UI Elements outside of its own Thread.
#FXML
private void initialize() throws InterruptedException {
WebEngine engine = webView.getEngine();
String url = "";
try {
url = getClass().getResource("/index.html").toExternalForm();
} catch (Exception e) {
}
loadSub(url, engine);
}
boolean test = false;
private void loadSub(String website, WebEngine engine) {
engine.load(website); // load loading Screen
//wait 5 seconds
engine.load("Google.com"); //load appropiate website
}
In my project I use simple JavaFX browser, that works in background and do some stuff without displaying it.
More precisely it submitted some form to one online page.
So, I ran into a problem: when this page doesn't available, I can't figure it out from my Java code, it looks like form wasn't submitted and clicks on Submit button do nothing, but in Chrome for example I see that the page isn't available.
So, is there an option to check from Java code if page is available?
Thanks in advance and sorry for bad English.
So, I found an answer.
There is Worker class in JavaFX that associates with WebEngine and it has a field with State type.
State is enum that has 6 options:
READY
SCHEDULED
RUNNING
SUCCEEDED
CANCELLED
FAILED
So State.FAILED can be used for handling errors.
For example, something like that (we'll assume we have WebEngine instance):
webEngine.getLoadWorker().stateProperty().addListener((observable, oldState, newState) -> {
if (newState == Worker.State.FAILED) {
doOnError();
return;
}
doOnSuccess();
});
webEndgine.load("example.com");
So, every time state is changed ObservableValue#changed will be called with new State value as one of parameteres and if state become FAILED we do some error processing.
I have some page that should have dynamic count of check boxes, and inputs depends on data received from database
now I do like this:
make rpc call on component load (getting data for inputs)
onSuccess add inputs dynamically on the form
result: form displayed without content(because it makes call async), only after resizing, it displays content properly
(probably I can fire resize event or redraw with my self, don't know how.. )
question: I am new in GWT, What is the best way to do this task? (Now i am using gwt-ext http://gwt-ext.com/, but I think it's no matter )
update: to refresh panel it's possible to call doLayout();
I'm not familiar with gwt-ext but in "vanilla" gwt you have two options:
Refresh your widget (that should show the result) in the onSuccess method
Proceed with the rest of your code not until the result returned.
To get a bit more precise i would need more of your code.
I had a similar challenge, the content of my widget was loading for a few seconds. I display a ""Loading, please wait ..."" label until the widget is loaded:
final VerticalPanel mainPanel = new VerticalPanel();
initWidget(mainPanel);
mainPanel.add(new Label("Loading, please wait ..."));
mainPanel.add(new myCustomWidget()); // this constructor uses RPC to get content
Timer t = new Timer()
{
public void run()
{
if (!mainPanel.getWidget(1).isVisible()) {
// do nothing
} else {
// remove label "Loading, please wait ..."
mainPanel.remove(0);
// stop timer
cancel();
}
}
};
// repeat every 30 miliseconds until myCustomWidget is visible
t.scheduleRepeating(30);
I am creating a web page with several tabs. To implement that I am using wicket AjaxTabbedPanel and several AbstractTab. In each tab I have tables with data and I am using a javascript script to make the tables sortable.
public TabbedPage() {
List<ITab> tabs = new ArrayList<ITab>();
tabs.add(new AbstractTab(new Model<String>("first tab")) {
public Panel getPanel(String panelId) {
return new TablePanel(panelId);
}
});
tabs.add(new AbstractTab(new Model<String>("second tab")) {
public Panel getPanel(String panelId) {
return new TablePanel(panelId);
}
});
add(new AjaxTabbedPanel("tabs", tabs));
}
When I load the page the table in the tab selected by default is sortable. However, as soon as I click any of the links to jump to other tabs (including the one of the tab already selected), none of the tables in any of the tabs allows me sort them (including the one that was previously working - the table in the default tab). If I refresh the page I can sort the table (of the tab selected in the moment of the refresh), but as soon as I click in any of links to switch tabs, the tables stop having the sortable capability again. Any ideas of why is this happening?
EDIT:
I just found that if I replace the AjaxTabbedPanel by TabbedPanel I don't have this problem. Although I'm still not sure why is that. Can anyone enlighten me?
add(new TabbedPanel("tabs", tabs));
Sorting the table by JavaScript is most likely a function called with a specific DOM-Id and seems to be executed 'onLoad'. it then accesses the currently displayed table and does it's work.
Changing the content of your Panel by Ajax doesn't trigger 'onLoad' so the function isn't executed again. TabbedPanel reloads the page and therefore executed your script.
Selecting a previous sortable table with AjaxTabbedPanel doesn't work because of the dynamically generated DOM-Ids.
Your solution is to add a AjaxCallDecorator to the links from AjaxTabbedPanel or to include the script or at least the function call to your tabbed panels.
At least this it what comes to mind without seeing any sources...
EDIT:
You might want to look at The Wicket Wiki. There's a description on how to call js after clicking an AjaxLink. That's exactly what should solve your problem.
Summary: Just add
link.add(new AttributeAppender("onclick", new Model("myTableSortingScript();"), ";"));
to the links generated by AjaxTabbedPanel.
In Wicket 6.0 you can run JavaScript on a component basis: Just override renderHead(IHeaderResponse response) for your component:
#Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(new OnLoadHeaderItem("initalizeMe(\"" + getMarkupId() + "\");"));
}
initializeMe(mycomponentId) is executed every time the component is loaded by the AjaxTabbedPanel. This also works with the standard TabbedPanel.
No real idea since I'm not sure what the code is doing but I had a similar problem with my Panel Manager. Basically if you dynamically load HTML into a panel (a div or another element) using "innerhtml" script in the content will not be executed.
To get around this I scan the loaded content for "script" tags and append them using the DOM methods - this does run the script and makes it available. My "load" method is:
// Load Content
Panel.load = function(Content) {
// "null" the old (to clear it)
Panel.innerHTML = null;
// Load the content
Panel.innerHTML = Content;
// Load Scripts
var AllScripts = Panel.getElementsByTagName("script");
var AllScriptsCnt = AllScripts.length;
for (var Cnt = 0; Cnt < AllScriptsCnt; Cnt++){
var CurScript = document.createElement('script');
CurScript.type = "text/javascript";
CurScript.text = AllScripts[Cnt].text;
Panel.appendChild(CurScript);
};
};
Again, not sure if this is the issue, but it sounds pretty much on target from my experience.
I'm trying to load a URL into a JEditorPane or JTextPane but the URL is a dynamically generated PHP page. I then want to process the output from the PHP page in my Java application. The PHP page will always output at least one String that I can use to check that it's generated correctly.
If I try and process the page straight after setting the page using
JEditorPane.setPage(URL);
if( outputTracker.getText().contains("desktop_process") )
it returns a blank HTML page, even if I specify a text/plain content type for the JEditorPane:
System.out.println(outputTracker.getText() );
I assume this is because the PHP page hasn't finished loading as the method below will return the correct output every time.
At the moment I'm setting the page and then starting a Swing Timer and checking every 200ms if the page contains the correctly generated String:
private void getPageBtnActionPerformed(java.awt.event.ActionEvent evt) {
outputTracker.setPage("URL_GOES_HERE?variables=x&y=a");
check_response_timer.start();
}
ActionListener checkAction = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if( outputTracker.getText().contains("desktop_process") ) {
System.out.println("Checking results...");
check_response_timer.stop();
process_response();
} else {
num_checks++;
System.out.println("Checking results...");
if( num_checks == 10 ) {
check_response_timer.stop();
checkLater = true;
responseLbl.setText("Connection timeout. Please click reconnect to check again.");
num_checks = 0;
}
}
}
};
private Timer check_response_timer = new Timer(200,checkAction);
This works fine.
At current server loads and the current complexity of the PHP pages being loaded the loop stops after the first iteration but it just seems a little inefficient and I don't want to have to keep checking if the page is going to take several seconds to load during heavy server loads or on more complex PHP pages.
I'm wondering if there's a better way to check that the page has finished loading.
I was wondering if I could use the JEditorPane.read(inputStream) method or set the page in a Swing Background Worker thread and then process the output of the PHP page when the worker's done() is called.
And is there a better way of loading the PHP output, reading it straight into a string from the dynamically generated output without the use of an editor pane as the editorpane isn't visible anyway?
Hope this is clear enough.
Thanks.
You can add a PropertyChangeListener to the editor pane:
editorPane.addPropertyChangeListener("page", ...);
However, this will only tell you when the main page is loaded. It won't tell you when images or other related files have finised loading.