we are trying to replace JXBrowser with JCEF in our application. We are using JCEF in such a way that we will create only one instance of cefBrowser and the same browser instance will be used to load different urls. The URLs will be loaded in different swing modals, tabs etc. But, only one cefBrowser instance will be created. We have few scenarios where the browser UI needs to be shown when the URL is loaded completely. We are trying to use the browser as shown in the following sample program.
- Code: Select all
package test;
import org.cef.CefApp;
import org.cef.CefApp.CefAppState;
import org.cef.CefApp.CefVersion;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.OS;
import org.cef.browser.CefBrowser;
import org.cef.handler.CefAppHandlerAdapter;
import org.cef.handler.CefDisplayHandlerAdapter;
import org.cef.handler.CefLifeSpanHandlerAdapter;
import org.cef.handler.CefLoadHandlerAdapter;
import java.awt.*;
/**
* @author Chandan Talukdar
*/
public class JCEFBrowser {
private static final String[] COMMAND_LINE_ARGS ={};
private CefClient cefClient ;
private boolean browserCreated;
private CefBrowser cefBrowser;
private static JCEFBrowser jcefBrowser;
static JCEFBrowser getBrowserInstance() {
if(jcefBrowser == null) {
jcefBrowser = new JCEFBrowser();
}
return jcefBrowser;
}
JCEFBrowser() {
initializeCefClient();
createBrowser("", true); //create immediately
}
private void initializeCefClient() {
cefClient = getCefApp().createClient();
// The different life span phases can be captured with LifeSpanHandler
cefClient.addLifeSpanHandler(new CefLifeSpanHandlerAdapter() {
@Override
public void onAfterCreated(CefBrowser browser) {
// Browser is created and ready to load a URL
System.out.println("Browser Created: " + browser.getIdentifier());
browserCreated = true;
}
@Override
public void onAfterParentChanged(CefBrowser browser) {
System.out.println("Browser onAfterParentChanged: " + browser.getIdentifier());
}
@Override
public boolean doClose(CefBrowser browser) {
boolean result = browser.doClose();
return result;
}
@Override
public void onBeforeClose(CefBrowser browser) {
browserCreated = false;
cefBrowser = null;
}
});
cefClient.addLoadHandler(new CefLoadHandlerAdapter() {
@Override
public void onLoadingStateChange(CefBrowser browser, boolean isLoading,
boolean canGoBack, boolean canGoForward) {
if (!isLoading) {
System.out.println("Browser loaded: " + browser.getIdentifier());
}
}
});
cefClient.addDisplayHandler(new CefDisplayHandlerAdapter() {
@Override
public boolean onConsoleMessage(CefBrowser browser, CefSettings.LogSeverity level,
String message, String source, int line) {
return true;
}
});
}
private CefApp getCefApp() {
if (CefApp.getState() != CefApp.CefAppState.INITIALIZED) {
CefSettings settings = new CefSettings();
settings.windowless_rendering_enabled = OS.isLinux();
CefApp cefApp = CefApp.getInstance(COMMAND_LINE_ARGS, settings);
CefVersion version = cefApp.getVersion();
System.out.println("Using CEF version:\n" + version);
CefApp.addAppHandler(new CefAppHandlerAdapter(COMMAND_LINE_ARGS) {
@Override
public void stateHasChanged(CefAppState cefAppState) {
if (cefAppState == CefAppState.TERMINATED) {
System.out.println("State is TERMINATED");
System.exit(0);
}
}
});
return cefApp;
} else {
return CefApp.getInstance();
}
}
private void createBrowser(String url, boolean createImmediately) {
cefBrowser = cefClient.createBrowser(url, OS.isLinux(), false);
if(createImmediately) {
cefBrowser.createImmediately();
}
}
Component getComponent() {
return cefBrowser.getUIComponent();
}
void loadURLAndWait(String url) {
cefBrowser.loadURL(url);
// We want to wait here till URL is loaded completely.
//Need to implement this as a blocking API.
//if we wait here then the processing itself is block as we are inside an event dispatcher thread
}
}
We are calling this code from a modal window in following way:
- Code: Select all
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* @author Chandan Talukdar
*/
class JCEFModal extends JFrame {
JCEFModal( String title) {
setName(title);
Component component = createUIComponents();
add(component);
setSize(800, 600);
setVisible(true);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
dispose();
}
});
}
private Component createUIComponents() {
JCEFBrowser jcefBrowser = JCEFBrowser.getBrowserInstance();
String htmlUrl = "www.google.com";
jcefBrowser.loadURLAndWait(htmlUrl);
jcefBrowser.getComponent().setVisible(true);
return jcefBrowser.getComponent();
}
}
- Code: Select all
package test;
import org.cef.CefApp;
import javax.swing.*;
import java.awt.event.*;
/**
* @author Chandan Talukdar
*/
public class JCefExample extends JFrame {
private JCefExample(String title) {
setTitle(title);
setName(title);
JButton button = new JButton("click");
button.addActionListener(
e -> new JCEFModal("JCEFExampleModal")
);
button.setBounds(165, 135, 115, 55);
add(button);
setSize(500, 400);
setLayout(null);
setVisible(true);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
CefApp.getInstance().dispose();
dispose();
}
});
}
public static void main(String[] args) {
new JCefExample("JCEF Example");
}
}
In class JCEFBrowser we are trying to create the cef browser from JCEFBrowser constructor. Due to this we are facing the following issues.
1. We are creating browser with createImmediately so that the browser is created immediately and doesn't wait for a view to be attached. when we call loadURLAndWait from the modal, the browser is not crated at the time when loadUrl is called and hence loadUrl fails for the first time.
2. Also we cannot wait for the browser to be created under JCEFBrowser.createBrowser() as the call is made from an Event dispatcher thread and a wait will block the whole thread.
3. We also want to wait till the url is loaded completely on the browser in the method JCEFBrowser.loadURLAndWait()
Basically we want to make the JCEFBrowser.loadURLAndWait() a synchronous call. Any suggestion will be much appreciated.
We are using Using:
JCEF Version = 81.2.24.251
CEF Version = 81.2.24
Chromium Version = 81.0.4044.113
2. Java version used is 1.8.0_201-b09 and OS is Windows 7 x64 bit
Thanks
Chandan