Mac OSX - Drag and drop in Swing appl running on applet - macos

I'm having some issues making my swing application to work in Mac OSX. This swing application should run on an applet inside the browser.
Please note that this problem is exclusive to mac osx and only when the applet run on the browser
The problem I see is that the drop events are not properly delivered to the components inside the Applet.
The following example contains a label and a input field. If you drag from the label to the input field, the label text should be copy into the input field.
package com.example;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
public class DND extends JApplet {
/**
*
*/
private static final long serialVersionUID = 1L;
JTextField txtField;
JLabel lbl;
private void doStart() {
this.setLayout(new FlowLayout(FlowLayout.CENTER));
txtField = new JTextField(20);
lbl = new JLabel("Drag this text to the input field");
lbl.setPreferredSize(new Dimension(250, 100));
lbl.setBackground(Color.lightGray);
lbl.setBorder(BorderFactory.createLineBorder(Color.black));
lbl.setTransferHandler(new TransferHandler("text"));
MouseListener ml = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
JComponent jc = (JComponent) e.getSource();
TransferHandler th = jc.getTransferHandler();
th.exportAsDrag(jc, e, TransferHandler.COPY);
}
};
lbl.addMouseListener(ml);
add(txtField);
add(lbl);
setBackground(Color.lightGray);
setVisible(true);
}
#Override
public void start() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
doStart();
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
With this code you have to generate a .jar file which will be used in the following html so you can run the applet in the browser:
<html>
<head>
<title>Menu test Applet</title>
</head>
<body>
<applet id="AppletID" height="800" width="600"
code="com.example.DND"
archive="*jar_file*.jar">
</applet>
</div>
</body>
</html>
If you pop the applet out of the browser using cmd+shift everything works as expected.
System specs:
Firefox 16.0.2
Mac OS X 10.7.5
JRE version 1.6.0_37-b06 (with plugin 1.6.0_37 but this problem also happens in 1.6.0_31)
Anyone have any idea what am I doing wrong?

Related

Javafx - open login.microsoftonline.com page in webview component

I have problem with opening login.microsoftonline.com page in webview component from javafx. I have simply code that should open this page without any trouble:
WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
var url = "https://login.microsoftonline.com/";
webEngine.load(url);
VBox root = new VBox();
root.getChildren().add(webView);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
webEngine.getLoadWorker().stateProperty().addListener((obs, oldValue, newValue) -> {
System.out.println(webEngine.getLocation());
});
When I try to execute this code on machine with windows operating system I receive blank page:
When I execute the same code on macbook, site is opening:
I'm using java 10 and really no idea what's wrong. Does anybody have the same issue? Any idea how to solve this problem? maybe there is other component instead of webview that I can use to do my stuff?
This is not the solution to your problem but may lead you in the right direction. It seems that the site body is loaded using script. That script depends on other scripts I am guessing. It appears none of the other scripts are loading.
import com.sun.javafx.webkit.WebConsoleListener;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
*
* #author blj0011
*/
public class JavaFXApplication281 extends Application
{
#Override
public void start(Stage primaryStage)
{
try {
TrustManager trm = new X509TrustManager()
{
#Override
public X509Certificate[] getAcceptedIssuers()
{
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType)
{
}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType)
{
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{trm}, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
WebConsoleListener.setDefaultListener(new WebConsoleListener()
{
#Override
public void messageAdded(WebView webView, String message, int lineNumber, String sourceId)
{
System.out.println("Console: [" + sourceId + ":" + lineNumber + "] " + message);
}
});
webEngine.setJavaScriptEnabled(true);
String url = "https://login.microsoftonline.com/";//"https://login.microsoftonline.com/jsdisabled";//
webEngine.load(url);
webEngine.getLoadWorker().stateProperty().addListener((obs, oldValue, newValue) -> {
System.out.println(newValue);
String html = (String) webEngine.executeScript("document.documentElement.outerHTML");
System.out.println(html);
});
webEngine.setOnError((event) -> {
System.out.println(event.getMessage());
});
// webEngine.getLoadWorker().exceptionProperty().addListener((obs, oldExc, newExc) -> {
// if (newExc != null) {
// newExc.printStackTrace();
// }
// });
StackPane root = new StackPane();
root.getChildren().add(webView);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
catch (KeyManagementException ex) {
ex.printStackTrace();
}
catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
Output:
Console: [null:0] Cannot load stylesheet https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/converged.v2.login.min_jumzhgrnvlj7lwxqltrteq2.css. Failed integrity metadata check.
Console: [https://login.microsoftonline.com/common/oauth2/authorize?client_id=4345a7b9-9a63-4910-a426-35363201d503&response_mode=form_post&response_type=code+id_token&scope=openid+profile&state=OpenIdConnect.AuthenticationProperties%3d5xhL9s5iN_65agH7ctGnRfQlJHUHgSrEvD4vkaO323RyB1klBHD6Qh5qidm6GuaIHM8_GaSANKH6y1ohWHalX4QU_YyqGJqXV8wphi2TVMAAY3yyXQk3GB-yqWm0j3oh&nonce=636748812038183968.MmMxNjY2YjEtNDIwZS00ZDhhLWI3YmItMWRhMWM5ZmRmMzk4MjJkMGExMDItZDAxZi00MTZmLWIxYjctOTNmZWU2YjgzZDRi&redirect_uri=https%3a%2f%2fwww.office.com%2f&ui_locales=en-US&mkt=en-US:30] Cannot load stylesheet https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/converged.v2.login.min_jumzhgrnvlj7lwxqltrteq2.css. Failed integrity metadata check.
Console: [https://login.microsoftonline.com/common/oauth2/authorize?client_id=4345a7b9-9a63-4910-a426-35363201d503&response_mode=form_post&response_type=code+id_token&scope=openid+profile&state=OpenIdConnect.AuthenticationProperties%3d5xhL9s5iN_65agH7ctGnRfQlJHUHgSrEvD4vkaO323RyB1klBHD6Qh5qidm6GuaIHM8_GaSANKH6y1ohWHalX4QU_YyqGJqXV8wphi2TVMAAY3yyXQk3GB-yqWm0j3oh&nonce=636748812038183968.MmMxNjY2YjEtNDIwZS00ZDhhLWI3YmItMWRhMWM5ZmRmMzk4MjJkMGExMDItZDAxZi00MTZmLWIxYjctOTNmZWU2YjgzZDRi&redirect_uri=https%3a%2f%2fwww.office.com%2f&ui_locales=en-US&mkt=en-US:30] Cannot load stylesheet https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/converged.v2.login.min_jumzhgrnvlj7lwxqltrteq2.css. Failed integrity metadata check.
Console: [https://login.microsoftonline.com/common/oauth2/authorize?client_id=4345a7b9-9a63-4910-a426-35363201d503&response_mode=form_post&response_type=code+id_token&scope=openid+profile&state=OpenIdConnect.AuthenticationProperties%3d5xhL9s5iN_65agH7ctGnRfQlJHUHgSrEvD4vkaO323RyB1klBHD6Qh5qidm6GuaIHM8_GaSANKH6y1ohWHalX4QU_YyqGJqXV8wphi2TVMAAY3yyXQk3GB-yqWm0j3oh&nonce=636748812038183968.MmMxNjY2YjEtNDIwZS00ZDhhLWI3YmItMWRhMWM5ZmRmMzk4MjJkMGExMDItZDAxZi00MTZmLWIxYjctOTNmZWU2YjgzZDRi&redirect_uri=https%3a%2f%2fwww.office.com%2f&ui_locales=en-US&mkt=en-US:30] Failed to load external resource ['https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/converged.v2.login.min_jumzhgrnvlj7lwxqltrteq2.css']
Console: [null:0] Cannot load script https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/oldconvergedlogin_pcore.min_lwozjqawrstmtzsn2yunha2.js. Failed integrity metadata check.
Console: [null:0] Cannot load script https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/convergedloginpaginatedstrings-en.min_uzcugprrg6vz0z16am4meq2.js. Failed integrity metadata check.
Console: [null:0] Cannot load script https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/oldconvergedlogin_pcore.min_lwozjqawrstmtzsn2yunha2.js. Failed integrity metadata check.
Console: [null:0] Cannot load script https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/convergedloginpaginatedstrings-en.min_uzcugprrg6vz0z16am4meq2.js. Failed integrity metadata check.
Console: [null:0] Cannot load script https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/oldconvergedlogin_pcore.min_lwozjqawrstmtzsn2yunha2.js. Failed integrity metadata check.
Console: [https://login.microsoftonline.com/common/oauth2/authorize?client_id=4345a7b9-9a63-4910-a426-35363201d503&response_mode=form_post&response_type=code+id_token&scope=openid+profile&state=OpenIdConnect.AuthenticationProperties%3d5xhL9s5iN_65agH7ctGnRfQlJHUHgSrEvD4vkaO323RyB1klBHD6Qh5qidm6GuaIHM8_GaSANKH6y1ohWHalX4QU_YyqGJqXV8wphi2TVMAAY3yyXQk3GB-yqWm0j3oh&nonce=636748812038183968.MmMxNjY2YjEtNDIwZS00ZDhhLWI3YmItMWRhMWM5ZmRmMzk4MjJkMGExMDItZDAxZi00MTZmLWIxYjctOTNmZWU2YjgzZDRi&redirect_uri=https%3a%2f%2fwww.office.com%2f&ui_locales=en-US&mkt=en-US:30] Failed to load external resource ['https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/oldconvergedlogin_pcore.min_lwozjqawrstmtzsn2yunha2.js']
Console: [null:0] Cannot load script https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/convergedloginpaginatedstrings-en.min_uzcugprrg6vz0z16am4meq2.js. Failed integrity metadata check.
Console: [https://login.microsoftonline.com/common/oauth2/authorize?client_id=4345a7b9-9a63-4910-a426-35363201d503&response_mode=form_post&response_type=code+id_token&scope=openid+profile&state=OpenIdConnect.AuthenticationProperties%3d5xhL9s5iN_65agH7ctGnRfQlJHUHgSrEvD4vkaO323RyB1klBHD6Qh5qidm6GuaIHM8_GaSANKH6y1ohWHalX4QU_YyqGJqXV8wphi2TVMAAY3yyXQk3GB-yqWm0j3oh&nonce=636748812038183968.MmMxNjY2YjEtNDIwZS00ZDhhLWI3YmItMWRhMWM5ZmRmMzk4MjJkMGExMDItZDAxZi00MTZmLWIxYjctOTNmZWU2YjgzZDRi&redirect_uri=https%3a%2f%2fwww.office.com%2f&ui_locales=en-US&mkt=en-US:30] Failed to load external resource ['https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8233.17/content/cdnbundles/convergedloginpaginatedstrings-en.min_uzcugprrg6vz0z16am4meq2.js']
The above will also show you the HTML that was loaded. It is too long to add.
Some code from here to help troubleshoot the problem.
I do not have Java 10. I used Java 8.
I found out that web view is using webkit engine for mac os/ linux os and IE engine for windows machines. WebView on mac os is working fine but there is problem on windows machines. When I was investigating this issue I find out that there is problem in this IE engine. I have access to few machines with different version of IE 11 installed on. On machines with update version 11.0.85 I wasn't able to open this site, but when I tried on machine with update version 11.0.90 the problem doesn't exist anymore. So if someone is using Windows OS please try to update IE version maybe it will solve problem.
Had the same issue and I think I found the critical point: external script/link integrity fails.
This is not a platform browser issue, JavaFX (OpenJFK) relies on an embedded webkit engine.
The regression happened between version 40 and version 172 on windows JDK 8.
It's working fine with Oracle JDK 9.0.4
It's not working with Oracle JDK 11
More details at:
https://github.com/mguessan/davmail/issues/12
Issue similar to: Javafx - open login.microsoftonline.com page in webview component
=> Updated answer: implemented to override Microsoft form content and disable integrity check. This is not a fix of the webkit bug, just a workaround
try {
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
#Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("https".equals(protocol)) {
return new sun.net.www.protocol.https.Handler() {
#Override
protected URLConnection openConnection(URL url, Proxy proxy) throws IOException {
System.out.println("openConnection " + url);
if (url.toExternalForm().endsWith("/common/handlers/watson")) {
System.out.println("Failed: form calls watson");
}
final HttpsURLConnectionImpl httpsURLConnection = (HttpsURLConnectionImpl) super.openConnection(url, proxy);
if ("login.microsoftonline.com".equals(url.getHost())
&& "/common/oauth2/authorize".equals(url.getPath())) {
return new URLConnection(url) {
#Override
public void connect() throws IOException {
httpsURLConnection.connect();
}
public InputStream getInputStream() throws IOException {
byte[] content = readFully(httpsURLConnection.getInputStream());
String contentAsString = new String(content, "UTF-8");
System.out.println(contentAsString);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(contentAsString.replaceAll("integrity", "integrity.disabled").getBytes("UTF-8"));
return new ByteArrayInputStream(baos.toByteArray());
}
public OutputStream getOutputStream() throws IOException {
return httpsURLConnection.getOutputStream();
}
};
} else {
return httpsURLConnection;
}
}
};
}
return null;
}
});
} catch (Throwable t) {
System.out.println("Unable to register custom protocol handler");
}

SWT Dialog does not display correctly

When opening a new dialog, while its loading, you click couple of times on parent shell, apparently the new dialog does not display correctly.
Please see the example below:
Examples
https://i.stack.imgur.com/ZovxE.png (eclipse IDE example)
https://i.stack.imgur.com/5zVar.png
https://i.stack.imgur.com/u86b9.png
https://i.stack.imgur.com/FGaAr.png
Initially I encountered the problem in december 2014, and back then also reported by vaious in house devlopers which were using different development systems and then same problem has been reported by our several customers.
This behavior can be reproduced using following environment:
Windows Version: 7 Pro 64 Bit - 6.1.7601
Java Version: RE 1.8.0_121_b13
SWT Versions
3.8.2
4.6.2
4.7M6
I20170319-2000
I could only reproduce the problem on Windows 7 with the windows basic theme/design/style (not with classic or aero).
On windows 10 its not reproducible.
reproduce
code to reproduce
package test;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class Main {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = createShell(display);
createButton(shell);
shell.open();
eventLoop(display, shell);
display.dispose();
}
private static Shell createShell(Display display) {
final Shell shell = new Shell(display);
shell.setLayout(new RowLayout());
shell.setSize(500, 200);
return shell;
}
private static void createButton(final Shell shell) {
final Button openDialog = new Button(shell, SWT.PUSH);
openDialog.setText("Click here to open Dialog ...");
openDialog.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
TestDialog inputDialog = new TestDialog(shell);
inputDialog.open();
}
});
}
private static void eventLoop(Display display, final Shell shell) {
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
class TestDialog extends Dialog {
public TestDialog(Shell parent) {
super(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MIN | SWT.MAX | SWT.RESIZE);
setText("Dialog");
}
public void open() {
Shell shell = new Shell(getParent(), getStyle());
shell.setText(getText());
createContents(shell);
shell.pack();
initializeBounds(shell);
shell.open();
eventLoop(shell);
}
private void createContents(final Shell shell) {
shell.setLayout(new GridLayout(2, true));
Label label = new Label(shell, SWT.NONE);
label.setText("Some Label text ...");
final Text text = new Text(shell, SWT.BORDER);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
text.setLayoutData(data);
createCloseButton(shell);
/* time for the user to create the misbehavior */
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void createCloseButton(final Shell shell) {
Button closeButton = new Button(shell, SWT.PUSH);
closeButton.setText("Close");
GridData data = new GridData(GridData.FILL_HORIZONTAL);
closeButton.setLayoutData(data);
closeButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
shell.close();
}
});
shell.setDefaultButton(closeButton);
}
private void initializeBounds(Shell shell) {
Rectangle bounds = shell.getBounds();
Rectangle parentBounds = getParent().getBounds();
bounds.x = parentBounds.x;
bounds.y = parentBounds.y;
shell.setBounds(bounds);
}
private void eventLoop(Shell shell) {
Display display = getParent().getDisplay();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
steps to reproduce
Start the application
it should look like: https://i.stack.imgur.com/dMJ9e.png
Click on the button.
Keep continuously clicking on right bottom corner of the parent shell (avoid hitting the new opening dialog), till mouse cursor changes to wait icon and parent shell changes its color.
it should look as following: https://i.stack.imgur.com/c1Ikp.png
Wait until the new dialog appears.
it looks likes as following: https://i.stack.imgur.com/kTDgQ.png (incorrectly displayed)
instead: https://i.stack.imgur.com/cHVjn.png (correctly displayed)
steps to reproduce done in video
https://youtu.be/7ukhloCPf0k
When you mouse hover some of the UI elements (the originally not correctly drawn), you can notice some of them to be get painted (e.g. table rows).
https://i.stack.imgur.com/kkMKn.png (before opening the dialog)
https://i.stack.imgur.com/ZXIKc.png (after opening the dialog)
https://i.stack.imgur.com/25M7S.jpg (after mouse over)
Even calling Shell.update() or Shell.redraw() after the Dialog opened does not fix it.
In Windows Performance Options -> Visual Effects -> disable "Use visual styles on windows and buttons" is the only option I found which provides a workaround,
which seems to be the same as changing the design/theme/style to classic.
https://www.sevenforums.com/tutorials/1908-visual-effects-settings-change.html (How to Change Windows Visual Effects)
In the end, I have following questions:
Is it a SWT or Windows problem?
Is there any related topic in bug entries for Windows or in Eclipse Bugzilla?
Is there someone else who experienced the same problem? please share the experience.
Is there any settings in SWT or Windows which could affect its look n feel and fix the problem?
In the end, I have following questions: Is it a SWT or Windows problem?
Neither. As others have mentioned, you certainly should not tie up the UI thread with any long-running task. That work belongs in a background thread.
In regards to using a background thread, there are several ways you could go about this depending on how you want your Dialog to behave.
One option would be to kick off the background thread and then open the dialog when the task is done. I personally don't care for this because while the task is running, a user may think that nothing is happening.
Another option would be to open the dialog but display a "Loading" message, or something to that effect to give meaningful feedback and let a user know that the application isn't frozen (like how it looks/responds in your example).
The strategy would be to:
Create the dialog
Start the long task on a background thread and register a callback
Open the dialog with a "Loading" message
When the task is complete, the dialog will be updated from the callback
If you search around a bit on using Executors, you should find some far better examples and detail on how to use them.
Here's a brief example to illustrate what that might look like:
(Note: There are definitely a few issues with this code, but for the sake of brevity and illustrating the point I opted for a slightly naive solution. Also there are Java 8-esque ways that would be a bit shorter, but again, this illustrates the idea behind using a background thread; the same concepts apply)
Given a Callable (or Runnable if you don't need a return value),
public class LongTask implements Callable<String> {
#Override
public String call() throws Exception {
Thread.sleep(15000);
return "Hello, World!";
}
}
You can use the Executors class to create a thread pool, and then an ExecutorService to submit the Callable for execution. Then, using Futures.addCallback(), you can register a callback which will execute one of two methods depending on whether the task was successful or failed.
final ExecutorService threadPool = Executors.newFixedThreadPool(1);
final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(threadPool);
final ListenableFuture<String> future = executorService.submit(new LongTask());
Futures.addCallback(future, new FutureCallback(){...});
In this case I used the Google Guava implementation ListeningExecutorService which makes things a bit cleaner and simpler, in my opinion. But again, you may not even need this if you opt for a more "Java 8" approach.
As for the callback, when the task is successful, we update the Dialog with the results. If it fails, we can update it with something to indicate failure:
public static class DialogCallback implements FutureCallback<String> {
private final MyDialog dialog;
public DialogCallback(final MyDialog dialog) {
this.dialog = dialog;
}
#Override
public void onSuccess(final String result) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus(result);
}
});
}
#Override
public void onFailure(final Throwable t) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus("Failure");
}
});
}
}
In this case I opted for the Callable to return a String, thus the FutureCallback should be parameterized with String. You may want to use some other class that you created, which will work just as well.
Notice that we use the Display.asyncExec() method to ensure that the code which updates the UI runs on the UI thread, because the callback may execute on the background thread.
Like I said, there are still a few issues here, including what happens when you click the cancel button before the task completes, etc. But hopefully this helps illustrate an approach for handling long-running background tasks without blocking the UI thread.
Full example code:
public class DialogTaskExample {
private final Display display;
private final Shell shell;
private final ListeningExecutorService executorService;
public DialogTaskExample() {
display = new Display();
shell = new Shell(display);
shell.setLayout(new GridLayout());
executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
final Button button = new Button(shell, SWT.PUSH);
button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
button.setText("Start");
button.addSelectionListener(new SelectionAdapter() {
#SuppressWarnings("synthetic-access")
#Override
public void widgetSelected(final SelectionEvent e) {
final MyDialog dialog = new MyDialog(shell);
dialog.setBlockOnOpen(false);
dialog.open();
dialog.setStatus("Doing stuff...");
final ListenableFuture<String> future = executorService.submit(new LongTask());
Futures.addCallback(future, new DialogCallback(dialog));
}
});
}
public void run() {
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
executorService.shutdown();
display.dispose();
}
public static void main(final String... args) {
new DialogTaskExample().run();
}
public static class DialogCallback implements FutureCallback<String> {
private final MyDialog dialog;
public DialogCallback(final MyDialog dialog) {
this.dialog = dialog;
}
#Override
public void onSuccess(final String result) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus(result);
}
});
}
#Override
public void onFailure(final Throwable t) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus("Failure");
}
});
}
}
public static class LongTask implements Callable<String> {
/**
* {#inheritDoc}
*/
#Override
public String call() throws Exception {
Thread.sleep(15000);
return "Hello, World!";
}
}
public static class MyDialog extends Dialog {
private Composite baseComposite;
private Label label;
/**
* #param parentShell
*/
protected MyDialog(final Shell parentShell) {
super(parentShell);
}
/**
* {#inheritDoc}
*/
#Override
protected Control createDialogArea(final Composite parent) {
baseComposite = (Composite) super.createDialogArea(parent);
label = new Label(baseComposite, SWT.NONE);
return baseComposite;
}
public void setStatus(final String text) {
label.setText(text);
baseComposite.layout();
}
}
}
The code seems to be straight forward, only that you are making the main Thread sleep for 15secs hence the delay. If not required remove the sleep or reduce the time for sleep to 5secs or so.

Swing apllication with embedded JavaFX WebView won't play html5 video only sound

In my Swing application I needed support for rendering html. So I embedded a JavaFX WebView in my Swing application. Now on some html pages I use the new html5 -Tag to play a video. This works perfectly on Windows and Linux. But on MacOS I only hear the sound and see a black video frame and the time track in the bottom.
Here is an SSCCE I got from github. I just changed the url to one that contains a html5 video-tag example. Would be great, if you MacOS users could try it and tell me if the same happens on you computer. And of course any idea to fix this is appreciated.
SSCCE:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import com.sun.javafx.application.PlatformImpl;
/**
* SwingFXWebView
*/
public class JavaFXTest extends JPanel
{
private Stage stage;
private WebView browser;
private JFXPanel jfxPanel;
private JButton swingButton;
private WebEngine webEngine;
private Object geo;
public JavaFXTest()
{
this.initComponents();
}
public static void main(final String... args)
{
// Run this later:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
final JFrame frame = new JFrame();
frame.getContentPane().add(new JavaFXTest());
frame.setMinimumSize(new Dimension(640, 480));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
private void initComponents()
{
this.jfxPanel = new JFXPanel();
this.createScene();
this.setLayout(new BorderLayout());
this.add(this.jfxPanel, BorderLayout.CENTER);
this.swingButton = new JButton();
this.swingButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(final ActionEvent e)
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
JavaFXTest.this.webEngine.reload();
}
});
}
});
this.swingButton.setText("Reload");
this.add(this.swingButton, BorderLayout.SOUTH);
}
/**
* createScene Note: Key is that Scene needs to be created and run on
* "FX user thread" NOT on the AWT-EventQueue Thread
*/
private void createScene()
{
PlatformImpl.startup(new Runnable()
{
#Override
public void run()
{
JavaFXTest.this.stage = new Stage();
JavaFXTest.this.stage.setTitle("Hello Java FX");
JavaFXTest.this.stage.setResizable(true);
final Group root = new Group();
final Scene scene = new Scene(root, 80, 20);
JavaFXTest.this.stage.setScene(scene);
// Set up the embedded browser:
JavaFXTest.this.browser = new WebView();
JavaFXTest.this.webEngine = JavaFXTest.this.browser.getEngine();
JavaFXTest.this.webEngine.load("http://camendesign.com/code/video_for_everybody/test.html");
final ObservableList<Node> children = root.getChildren();
children.add(JavaFXTest.this.browser);
JavaFXTest.this.jfxPanel.setScene(scene);
}
});
}
}
Here is a semi-answer, which might help:
The oracle website states:"At this time, Online Installation and Java Update features are not available for 64-bit architectures"
For me this caused lots of problems, because Java seems up to date, but actually isn't. On some machines I could solve the actual issue by just manually updating the Java 64bit VM. On Mac however, the video still isn't playing, only sound.
The 64bit/32bit issue gets even worse, since a double click on a jar might start it in the 64bit JVM, but via console it is started in 32bit JVM. So if you do a "java -version" in console, the output might be "1.7.0 u45 32-bit", but as soon as you start the jar via double click it is started in an outdated 64bit JVM.
So if you ever run in an JavaFX issue (especially with UnsatisfiedLinkError) and you have a 64bit computer, just install the latest 64bit java and hope that it solves the problem.

Interoperability problems when using JavaFx combobox within SWT Dialog

JavaFx is supposed to be easily integrated in an SWT application (see here: http://docs.oracle.com/javafx/2/swt_interoperability/jfxpub-swt_interoperability.htm) and both toolkits use the same threading model.
However things get strange, when I open a dialog containing an FxCanvas which contains a JavaFx ComboBox. If I open the combo box popup menu and then close the dialog, the popup menu stays open. If I now move the mouse onto the popup a null pointer exception is thrown within javafx. When doing this within a larger application all JavaFx GUIs remain broken until the application is restarted.
Any ways to work around this?
Example code below: Close the dialog with 'Ok' or the window close button. Exit the application with 'Cancel'
package test;
import javafx.embed.swt.FXCanvas;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class TestFx {
static class MyDialog extends Dialog {
Parent w;
public MyDialog(Shell parent,Parent n) {
super(parent);
this.w = n;
setShellStyle(SWT.RESIZE| SWT.BORDER | SWT.TITLE |SWT.CLOSE );
}
#Override
public void cancelPressed() {
System.exit(0);
}
#Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
container.setLayout(new FillLayout());
FXCanvas fxCanvas = new FXCanvas(container, SWT.NONE);
Scene scene = new Scene(w);
fxCanvas.setScene(scene);
return container;
}
}
private static Parent createScene() {
StackPane pane = new StackPane();
pane.setPadding(new Insets(10));
ComboBox<String> c = new ComboBox<String>();
c.getItems().addAll("Test1","Test2");
pane.getChildren().add(c);
return pane;
}
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
while (true) {
MyDialog d = new MyDialog(shell,createScene());
d.open();
}
}
}
Exception:
java.lang.NullPointerException
at com.sun.javafx.tk.quantum.GlassScene.sceneChanged(GlassScene.java:290)
at com.sun.javafx.tk.quantum.ViewScene.sceneChanged(ViewScene.java:156)
at com.sun.javafx.tk.quantum.PopupScene.sceneChanged(PopupScene.java:30)
at com.sun.javafx.tk.quantum.GlassScene.markDirty(GlassScene.java:157)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2214)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:363)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:460)
at com.sun.javafx.tk.quantum.QuantumToolkit$9.run(QuantumToolkit.java:329)
at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method)
at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2546)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3756)
at org.eclipse.jface.window.Window.runEventLoop(Window.java:825)
at org.eclipse.jface.window.Window.open(Window.java:801)
at test.TestFx.main(TestFx.java:55)
At work we're developing some applications using JavaFX, on top of and old Swing platform and we also have found this issue.
Apparently it is caused by some issues on JFXPanel which is not correctly propagating some window events (focus, iconifying, etc) to the FX framework. The issue affects not only the ComboBox component, but every component that uses a PopupWindow (Menu, Tooltip, etc), specially when using Swing's JInternalFrame.
So, when a Popup is displaying and the window is minimized or closed, the Popup does not hide, causing the FX thread to crash if you try subsequently to interact with it.
The workaround mentioned above works, but only for ComboBox, as Menu and Tooltip does not inherit from the Node class, so didn't work for us :(
I developed another workaround which resolved the problem for all components that display popups, which basically forces all popups to close whenever a JFXPanel loses focus:
private static void initFX(final JFXPanel jfxPanel) {
final TestFxPanel parent = new TestFxPanel();
final Scene scene = new Scene(parent);
jfxPanel.setScene(scene);
jfxPanel.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(final FocusEvent e) {
System.out.println(jfxPanel.getName() + ": FocusLost");
runFocusPatch(scene);
}
});
}
static void runFocusPatch(final Scene scene) {
Platform.runLater(new Runnable() {
#Override
public void run() {
System.out.println("Running patch");
final Iterator<Window> winIter = scene.getWindow().impl_getWindows();
while (winIter.hasNext()) {
final Window t = winIter.next();
if (t instanceof PopupWindow) {
System.out.println("Got a popup");
Platform.runLater(new Runnable() {
#Override
public void run() {
((PopupWindow) t).hide();
}
});
}
}
}
});
}
I confirm that the issue is NOT present in 8.0. Sadly we are not allowed to java 8 in production software as its still in beta stage.
best regards.
I found a workaround when using Java7: Override the close method in Dialog to hide the combo box popups:
#Override
public boolean close() {
Set<Node> nodes = w.lookupAll("#");
for (Node n : nodes)
if (n instanceof ComboBox)
((ComboBox)n).hide();
return super.close();
}
The trouble is discussed here : javafx-jira.kenai.com/browse/RT-30991
Developer has said, that the issue is fixed in JavaFX-8

JApplet/JPanel not receiving KeyListener events!

I cannot get my JPanel within my JApplet to receive keyboard events. I CANNOT FATHOM why!
Note that...
Clicking the panel (with mouse) before typing makes no difference. This is by far the most common advice I see given on the Net.
I have tried using the 'low-level' java.awt.KeyEventDispatcher interface. That makes no different either!
However, if I use Applet instead of JApplet, then the Applet DOES receive keyboard events. But even here, the moment I add a Panel to this Applet (the Panel is really where all my app/painting logic is), I once again stop receiving kb events (in my Panel)!
Now, I cannot simply use Applet (instead of JApplet) because, among other things, its onPaint gets a Graphics (instead of a Graphics2D object). So, #3 is NOT a solution for me.
Things work like a charm in AppletViewer that comes with JDK.
I desperately need someone's help here. Spent last 2-3 days trying all kinds of permutations I don't even recall now.
My platform details:
Firefox 3.5.3
Fedora 11 on x86 (with latest updates/patches)
Java Plugin: tried both of these, made no difference.
3.1 IcedTea Java Web Browser Plugin 1.6 (fedora-29.b16.fc11-i386)
3.2 jdk1.6.0_16/jre/plugin/i386/ns7/libjavaplugin_oji.so
Used the above jdk1.6.0_16 to compile my applet source.
Here's my code. Will greatly appreciate to hear from my fellow programmers... as I'm completely stuck!
Thanks,
/SD
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
class MyAppletKeyListener implements KeyListener, MouseListener {
public void keyPressed(KeyEvent e) {
System.out.println("panel:keyPressed" + e.getKeyChar());
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
System.out.println("panel:keyTyped" + e.getKeyChar());
}
public void mouseClicked(MouseEvent e) {
System.out.println("panel:mouseClicked");
}
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
}
public class TestApplet extends JApplet implements MouseListener {
public void init() {
System.out.println("applet:init");
MyAppletKeyListener listener = new MyAppletKeyListener();
// Panel related
// Note: I'd like this red panel to handle
// all my keyboard and mouse events.
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(new JButton("test"));
panel.add(new JButton("test2"));
panel.setFocusable(true);
panel.requestFocus();
panel.setBackground(new Color(200, 0, 0));
panel.addKeyListener(listener);
panel.addMouseListener(listener);
// applet related
// Note: Added this only for debugging. I do NOT want
// to handle my mouse/kb events in the applet.
addMouseListener(this);
getContentPane().setLayout(new FlowLayout());
getContentPane().add(panel);
}
public void mouseClicked(MouseEvent e) {
System.out.println("applet:mouseClicked");
}
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
}
The HTML:
<html>
<head>
</head>
<body>
<applet id="myApplet" code="TestApplet.class"
width="425"
height="150" >
</applet>
</body>
</html>
I found this on the net, and it solves the issue for me:
As for the fact that KeyListener does
not work for JApplet as it does for
Applet you should use the
KeyEventDispatcher interface.
public class AppletMain extends JApplet implements
java.awt.KeyEventDispatcher
Furthermore you have to set the
KeyboardFocusManager to the Panel
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
Afterwards override the
dispatchKeyEvent function of the
interface:
#Override
public boolean dispatchKeyEvent(KeyEvent e);
This allows you to catch the KeyEvents
as it is done with KeyListener.
I investigated the problem connected to my current project and explored some problems with focusability of JApplet class.
It is because why setFocusable(true);decided the problem.
You also may eventually need to add focus-capture call such as requestFocusInWindow(); to make it work propertly.
I had this problem with the sun-java-6 packages and the openjdk packages in both Ubuntu 9.04 and 10.10 with firefox version 3.6.11 and 3.6.14. I've discovered two workarounds: use Applet rather than JApplet, or implement a MouseListener which calls "requestFocus()" in the mousePressed(..) function.

Resources