I have created a form with Vaadin Flow (Vaadin version 21) with a save button. This form is then shown in a JavaFX WebView (Version 17.0.1) and now I want to listen to events in the form like save button from JavaFX, so I can update JavaFX parts of the application. I have seen examples like:
How to retrieve components from HTML webview in JavaFX
But they don't work since doc.getElementById("xxx") does not work at all and returns null. If I use the xpath method described there, I do get the button element, but then the adding the listener by calling the
((EventTarget) button).addEventListener("click", e -> doSomeAction(), false);
does not help. When I click the button the Vaadin listener works but the "javafx" listener does not get the event.
So my question is if there is a known solution for this Use Case?
You can invoke Java methods from JavaScript with upcalls. It works by assigning a JavaScript object to a Java one:
JSObject jso = (JSObject)webEngine.executeScript("window");
jso.setMember("java", new JavaObj());
Full example:
public class JavaObj {
public void myMethod() {
...
}
}
webEngine.setJavaScriptEnabled(true); // Obviously...
webEngine.getLoadWorker().stateProperty().addListener((observable, oldState, newState) -> {
if(newState == Worker.State.SUCCEEDED) {
JSObject jso = (JSObject)webEngine.executeScript("window");
jso.setMember("java", new JavaObj());
}
});
((EventTarget) button).addEventListener("click", e -> UI.getCurrent().getPage().executeJs("java.myMethod()"), false);
More about upcalls here.
I'm wondering if what should be done for GWT com.google.gwt.user.client.ui.FileUpload
to upload to server without refresh or forwarding.
I have implemented the Form upload from this Java Doc, however it forwards the browser page to the target server URL.
How can I implement a form upload without forwarding?
Update:
final FormPanel form = new FormPanel();
form.setAction("/upload");
form.setEncoding(FormPanel.ENCODING_MULTIPART);
form.setMethod(FormPanel.METHOD_POST);
VerticalPanel panel = new VerticalPanel();
form.setWidget(panel);
final TextBox tb = new TextBox();
tb.setName("textBoxFormElement");
panel.add(tb);
// Create a FileUpload widget.
FileUpload upload = new FileUpload();
upload.setName("uploadFormElement");
panel.add(upload);
DOM.getElementById("form_panel").appendChild(panel.getElement());
Button submit = new Button("Submit");
panel.add(submit);
DOM.sinkEvents(submit.getElement(), Event.ONCLICK);
DOM.setEventListener(submit.getElement(), new EventListener(){
#Override
public void onBrowserEvent(Event event) {
if (event.getTypeInt() == Event.ONCLICK) {
form.submit();
return;
}
}});
form.addSubmitHandler(new FormPanel.SubmitHandler() {
public void onSubmit(SubmitEvent event) {
if (tb.getText().length() == 0) {
Window.alert("The text box must not be empty");
event.cancel();
}
}
});
form.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
public void onSubmitComplete(SubmitCompleteEvent event) {
Window.alert(event.getResults());
}
});
IMO you are making things more complex than they are.
I don't understand why, if you are using widgets, you are trying to manage the DOM by hand.
1.- Attach your form panel to the root panel using GWT way, otherwise you are going to break widget hierarchy.
RootPanel.get("form_panel").add(panel);
2.- Try not to use sink-events by hand, and use methods already present in widgets:
submit.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
form.submit();
}
});
FormPanel sets its target to a hidden <iframe> so you will never be redirected to another page.
BTW, I'd rather use gwtupload library which simplifies so much uploading code in GWT, and adds a lot of additional features.
I used before gwt-upload library.
You dont need to rediscover America.
Thanks for moxie group
gwt-upload-project page
I initialize UI, adding all the elements to a VerticalPanel and at the end of initialization I check whether user password is expiring or not. If it is expiring I show a DialogBox with warning.
One of the element of this page is a TabPanel with a DataGrid and all the data is taken from server asynchronously. So the problem is that when Password Expiration dialog box appears it is behind DataGrid rows. When I inspect elements in Chrome I see that there're PopupGlassPanel -> DialogBox -> Table (with content). But the picture should be: Table (with content) -> PopupGlassPanel -> DialogBox.
But I cannot do anything with async calls to the server for retrieving data. Is it possible to control such things in order all data is retrieved from server and only after it my Dialo Box is shown?
Initialization method looks like:
public void initUI() {
final VerticalPanel mainPanel = new VerticalPanel();
Panel outer = new VerticalPanel();
DataHolder dataHolder = new DataHolder(); //this class contains DataGrid and makes async calls to server for data
outer.add(dataHolder.getContent());
tabPanel.add(outer, "Important Data", true);
mainPanel.add(tabPanel);
checkPasswordExpiration(getPwdExpiring());
RootPanel.get().add(mainPanel);
}
//...........
private void checkPasswordExpiration(int days) {
//...
//Show dialog box
//...
}
You need to call checkPasswordExpiration() after the async call returns. To do this you should get the async callback (onSuccess()) to fire an event for which you have a handler that will call checkPasswordExpiration(getPwdExpiring()); You can use EventBus to fire the event in and to add a handler.
I am trying to use UISpec4J in order to automate a Java Swing application. After adapter setup:
setAdapter(new MainClassAdapter(Main.class, new String[0]));
I am trying to obtain the main window:
Window mainWindow = getMainWindow();
Instead of a login dialog, I am getting a splash screen with logo of application. All my attempts to call this dialog manually have failed.
How can I get the list of opened dialogs/windows?
It looks like MainClassAdapter is not designed to handle a sequence of windows. However you can implement your own adapter that ignores the splash screen and returns the subsequent window. Here is a sample taken from UISpec4J forums:
setAdapter(new UISpecAdapter() {
public Window getMainWindow() {
final Window[] result = new Window[1];
WindowInterceptor.init(new MainClassTrigger(Main.class, new String[0]))
.processTransientWindow()
.process(new WindowHandler() {
public Trigger process(Window window) throws Exception {
result[0] = window;
return Trigger.DO_NOTHING;
}
})
.run();
return result[0];
}
});
I am developing GWT application and I use
com.google.gwt.user.client.Window.open(pageUrl, "_blank", "");
to open new page. And it opens in a new tab when called, for example, directly after button click.
But I decided to do some validations on server before opening new page and placed the call to the mentioned above method to the
public void onSuccess(Object response) {
}
And it starts to open pages in new window instead of new tab (this is true only for Chrome, other browsers still open it in a new tab).
Can anybody help me?
I built a small example to illustrate the issue:
button.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
Window.open("http://www.google.com/", "_blank", "");
MySampleApplicationServiceAsync serviceAsync = GWT.create(MySampleApplicationService.class);
serviceAsync.getMessage("Hello, Server!", new AsyncCallback() {
public void onFailure(Throwable caught) {
Window.alert("ERROR");
}
public void onSuccess(Object result) {
Window.open("http://www.bing.com/", "_blank", "");
}
}
);
}
});
Firefox(3.6.8) opens both pages in new tabs.
Chrome(6.0) opens "google.com" in new tab and "bing.com" in new window
Opera(10.10) opens in new tabs.
IE(8.0) opens both in new Windows.
I marked igorbel 's answer as the only correct cos I haven't found any proper way to specify the same behaviour in all situations.
I used this code and it works for me in google chrome and mozilla firefox 3.6.8 browsers
If you want to open a page in new window you should write code as
Window.open("www.google.com","_blank","enabled");
If you want to open a page in new tab you should write code as
Window.open("www.google.com","_blank","");
I am not sure you are going to be able to control this the way you want. The problem is that browsers can decide when to open windows and when to open tabs. For example, firefox has the option: "Open new windows in new tabs instead". And don't forget the browsers that don't support tabs (yes, those do still exist).
Since this is such a problematic aspect of the user experience, my recommendation would be to reconsider your design. Is it really that important for you application to differentiate between opening a new tab and opening a new window?
This code works for me:
Before calling the Async method keep a reference to a new window with empty parameters.
At onSuccess() method set the URL of the window.
Button someButton = new Button("test");
SelectionListener<ButtonEvent> listener = new SelectionListener<ButtonEvent>()
{
public void componentSelected(ButtonEvent ce)
{
final JavaScriptObject window = newWindow("", "", "");
someService.doSomething(new AsyncCallback()
{
public void onSuccess(Object o)
{
setWindowTarget(window, "http://www.google.com/");
}
});
}
}
someButton.addSelectionListener(listener);
private static native JavaScriptObject newWindow(String url, String name, String features)/*-{
var window = $wnd.open(url, name, features);
return window;
}-*/;
private static native void setWindowTarget(JavaScriptObject window, String target)/*-{
window.location = target;
}-*/;
Found at:
http://groups.google.com/group/google-web-toolkit/browse_thread/thread/574b3b828271ba17
Interesting thing,
chrome will open page in new tab in case if you put window.open(...) instruction into the body of the click handler implementation.
For example:
Button someButton = new Button("test",
new ClickHandler() {
public void onClick(ClickEvent event) {
Window.open(...);
}
});
And a page will be opened in the separate window in case if I will include any Async. request into the mentioned code:
Button someButton = new Button("test",
new ClickHandler() {
public void onClick(ClickEvent event) {
someService.doSomething(new AsyncCallback() {
void onSuccess(Object o) {
Window.open(...);
}
...
});
}
});
The way Chrome looks at it, calling Window.open() is like trying to open a pop-up window in the user's face. That's frowned upon and will trigger the built-in pop-up blocker. Following a link, according to Chrome, should be the result of a user clicking on a good old anchor tag with an href attribute. But here lies the answer you're looking for: you can show a link to the user and change the link target on the fly. That would qualify as a 'proper' link in Chrome's world.
This code works for me:
public static native String getURL(String url)/*-{
return $wnd.open(url,
'target=_blank')
}-*/;