I want to write a simple web browser in java and here’s my code!
import javax.swing.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
public class WebBrowser extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
public JPanel
address_panel, window_panel;
public JLabel
address_label;
public JTextField
address_tf;
public JEditorPane
window_pane;
public JScrollPane
window_scroll;
public JButton
address_b;
private Go go = new Go();
public WebBrowser() throws IOException {
// Define address bar
address_label = new JLabel(" address: ", SwingConstants.CENTER);
address_tf = new JTextField("http://www.yahoo.com");
address_tf.addActionListener(go);
address_b = new JButton("Go");
address_b.addActionListener(go);
window_pane = new JEditorPane("http://www.yahoo.com");
window_pane.setContentType("text/html");
window_pane.setEditable(false);
address_panel = new JPanel(new BorderLayout());
window_panel = new JPanel(new BorderLayout());
address_panel.add(address_label, BorderLayout.WEST);
address_panel.add(address_tf, BorderLayout.CENTER);
address_panel.add(address_b, BorderLayout.EAST);
window_scroll = new JScrollPane(window_pane);
window_panel.add(window_scroll);
Container pane = getContentPane();
pane.setLayout(new BorderLayout());
pane.add(address_panel, BorderLayout.NORTH);
pane.add(window_panel, BorderLayout.CENTER);
setTitle("web browser");
setSize(800,600);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public class Go implements ActionListener{
public void actionPerformed(ActionEvent ae){
try {
window_pane.setPage(address_tf.getText());
} catch (MalformedURLException e) { // new URL() failed
window_pane.setText("MalformedURLException: " + e);
} catch (IOException e) { // openConnection() failed
window_pane.setText("IOException: " + e);
}
}
}
public static void main(String args[]) throws IOException {
WebBrowser wb = new WebBrowser();
}
}
It works fine for simple html pages but it cannot load JavaScript part of the code! My problem is what should I add to the code to load the javascripts? Thank you!
Swing's default widgets only have very basic support for HTML4 and CSS, with absolutely no support for JavaScript at all (by default). You could potentially use the built-in Rhino JavaScript engine to execute the code, but that would have to be done manually and would be pretty difficult. HtmlUnit uses this tactic to parse HTML pages and execute the JavaScript, but it has generally poor compatibility and completely lacks a renderer, so you'd have to write that yourself (i.e. no display, you only get access to the page content from code).
There's a few Swing-based browser widgets floating around which embed a Gecko (Firefox) or WebKit (Chrome/Safari) renderer and would thus be able to take advantage of proper JavaScript interpreters, but they're all buggy, expensive, or unmaintained. These would all support JavaScript but they generally use very old versions of the various browser engines and have poor compatibility with modern websites, in addition to lacking cross-platform compatibility.
Eclipse's SWT project includes a browser widget that appears to be actively maintained, but has a dependence on the SWT libraries and would be somewhat more difficult to use in a Swing application, though it may be possible. SWT is an entirely different UI toolkit from AWT/Swing (which you're currently using) and in order to take advantage of its browser widget, you'd have to find a way to embed it in a Swing app, or use only the SWT toolkit.
Overall, SWT's browser is probably your best bet for getting a decent browser in Java, but it may still be troublesome to use. Good luck!
Related
I am currently writing a program that enables the user to drag-and-drop some data from a browser into a java swing application. This works as intended for the mime type "text/plain", but when using a custom mime type in the javascript, the java application does not receive the data anymore.
The javascript side is done as described in this answer:
for (const el of document.querySelectorAll('[draggable="true"]')) {
el.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', e.currentTarget.dataset.content);
});
}
The java application looks like this MRE. The MRE just prints out any received drops.
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.io.IOException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
JTextArea area = new JTextArea();
area.setDropTarget(new DropTarget() {
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
dtde.acceptDrop(TransferHandler.COPY_OR_MOVE);
try {
// For testing
System.out.println(Arrays.toString(dtde.getTransferable().getTransferDataFlavors()));
// Business logic, e.g.
System.out.println(dtde.getTransferable().getTransferData(DataFlavor.stringFlavor));
} catch (UnsupportedFlavorException | IOException e) {
e.printStackTrace();
}
}
});
frame.add(area);
// Only for MRE, never set size like this for actual programs
area.setPreferredSize(new Dimension(200, 100));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
This works as it should with the jsfiddle from the linked answer. However, the data that should be transferred is not just a plain text but actually a json string. Also, the string should only be dropped in my own application and not into any text editor. Therefore I changed the mime type in the javascript to 'text/json'. On the java side, I replaced
System.out.println(dtde.getTransferable().getTransferData(DataFlavor.stringFlavor));
with
System.out.println(dtde.getTransferable().getTransferData(new DataFlavor("text/json;class=java.lang.String")));
Which leads to an UnsupportedFlavorException in that line:
java.awt.datatransfer.UnsupportedFlavorException: text/json
at java.desktop/sun.awt.dnd.SunDropTargetContextPeer.getTransferData(SunDropTargetContextPeer.java:256)
at java.desktop/sun.awt.datatransfer.TransferableProxy.getTransferData(TransferableProxy.java:73)
at java.desktop/java.awt.dnd.DropTargetContext$TransferableProxy.getTransferData(DropTargetContext.java:386)
at Main$1.drop(Main.java:23)
Additionally, the TransferDataFlavors array is empty, suggesting no DataFlavor is available. I considered to overwrite the FlavorMap to ensure the native mime type is mapped to the correct flavor, but debugging the getFlavorsForFormats method in DataTransferer revealed only the following natives are requested (using chrome):
"DragContext", "chromium/x-renderer-taint", "Chromium Web Custom MIME Data Format", and "DragImageBits", so my custom mime type is not even available as native type.
How do I transfer the data correctly from the browser to the java application? Do I need to register my flavor somewhere? Or is this not possible and I need to stick to text/plain?
I can't seem to find anything on this - other than it can't be embedded in a web view.
I currently have an image viewing product which is accessed via an applet and controlled via JavaScript from an HTML page.
I am investigating a client application using JavaFX and it would likely need to access that applet. I attempted to embed it into the WebView and that didn't work. Searching on this site stated that webview doesn't support plug in technology. This is to build an applet with Java FX - but rather to invoke and interact with an existing product.
Therefore I am left wondering if there is another way - using JavaFX 8?
Thanks!
A quick trial with a really simple sample applet, demonstrates that it is possible to embed Swing applets into JavaFX applications (with Java 8).
Sample
Here is the HelloWorld applet from the Oracle getting started with applets documentation:
import javax.swing.*;
public class HelloWorldApplet extends JApplet {
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
JLabel lbl = new JLabel("Hello World");
add(lbl);
}
});
} catch (Exception e) {
System.err.println("createGUI didn't complete successfully");
}
}
}
And here is a JavaFX application which embeds it:
import javafx.application.Application;
import javafx.embed.swing.SwingNode;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
import java.awt.Dimension;
import java.util.concurrent.*;
public class JavaFXSwingAppletHolderApplication extends Application {
private JApplet applet = new HelloWorldApplet();
private Dimension appletSize;
#Override public void init() throws ExecutionException, InterruptedException {
applet.init();
FutureTask<Dimension> sizingTask = new FutureTask<>(() ->
applet.getRootPane().getPreferredSize()
);
SwingUtilities.invokeLater(sizingTask);
appletSize = sizingTask.get();
}
#Override public void start(Stage stage) {
final SwingNode swingNode = new SwingNode();
SwingUtilities.invokeLater(() ->
swingNode.setContent(applet.getRootPane())
);
stage.setScene(
new Scene(
new Group(swingNode),
appletSize.getWidth(), appletSize.getHeight(),
Color.BLACK
)
);
stage.show();
}
#Override public void stop() {
applet.stop();
applet.destroy();
}
public static void main(String[] args) {
launch(args);
}
}
Notes
I'm not sure if the sizingTask is the above code is strictly necessary, I just stuck it in there just in case as I know little about Swing layout, so thought it best to be explicit.
This sample only embeds a basic applet, your applet will be more complex so you will need to validate a similar solution for your particular applet to ensure it works for you.
Recommendation
Most existing applets are quite small - it is probably a better idea to reimplement an applet as a pure JavaFX component implementation rather than try to embed the applet in a JavaFX application.
Also note that the applet API is deprecated as part of Java 9, by JEP 289: Deprecated the Applet API.
To learn Networking in Java, I followed a tutorial to create a new web browser in NetBeans. Here is the code in ReadFile class:
package WebBrowser;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
*
* #author Siddharth Venu
*
*/
public class ReadFile extends JFrame{
private JTextField addressBar;
private JEditorPane display;
//constructor
public ReadFile(){
super("Sid Browser");
addressBar=new JTextField("Enter address");
//lambda expression instead of anonymous class
addressBar.addActionListener((ActionEvent event) -> {
loadData(event.getActionCommand());
});
add(addressBar,BorderLayout.NORTH);
display = new JEditorPane();
display.setEditable(false);
display.addHyperlinkListener((HyperlinkEvent event) -> {
if(event.getEventType()==HyperlinkEvent.EventType.ACTIVATED)
loadData(event.getURL().toString());
});
add(new JScrollPane(display), BorderLayout.CENTER);
setSize(500,300);
setVisible(true);
}
//load the data to display on the screen
private void loadData(String address){
try{
display.setPage(address);
addressBar.setText(address);
}catch(Exception e){
System.out.println(e);
}
}
}
And here is the code in the Main class:
package WebBrowser;
import javax.swing.JFrame;
/**
*
* #author Siddharth Venu
*
*/
public class Main {
public static void main(String[] args){
ReadFile browser=new ReadFile();
browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I then ran the Main class, at beginning, as it is not displaying any data from a website, it is looking good with address bar on the top. But when I enter an URL, say http://google.com, it displays weird output as in the following image.
Why exactly is this happening? The weird blue background and misaligned Google logo.
[Edit] I got to know that the setPage method can only handle HTML, plain text or RTF and not js. But it should at least display the HTML part without the weird blue screen na? PS: The blue screen is appearing in other sites like facebook too.
I've tested your browser. I'm getting the same results on pages with html5, javascript and css like google.com or facebook.com.
But when I use bare to the bones website like this it obviously works. So I must assume that the issue was the lack of support for these technologies in this simple browser.
As for the guy in the video linked he used bare html google webpage which I was unable to find or read out from the video (or made the video some time ago). People in the youtube comment section were addressing your issue as well. They were describing it as a lack of support for html5 in Swing. However some managed to make it work properly in JavaFX.
I have created the following code for a school project, a "password protector", just for fun, really. However, the problem I have is that the icon image does not appear, but instead the default java "coffee cup".
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class UserInterfaceGUI extends JFrame
{
private static final long serialVersionUID = 1;
private JLabel userNameInfo; // ... more unimportant vars.
public UserInterfaceGUI()
{
this.setLayout(new FlowLayout());
userNameInfo = new JLabel("Enter Username:"); // ... more unimportant var. declartions
this.add(userNameInfo); // ... more unimportant ".add"s
event e = new event();
submit.addActionListener(e);
}
public static void main(String[] args)
{
//This icon has a problem \/
ImageIcon img = new ImageIcon("[File Location hidden for privacy]/icon.ico");
UserInterfaceGUI gui = new UserInterfaceGUI();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(400, 140);
gui.setIconImage(img.getImage());
gui.setTitle("Password Protector");
gui.setVisible(true);
}
}
Can someone tell me why this just shows the java coffee cup at the bottom of the screen and on the bar at the top of the window?
There are two likely problems here:
Java is unlikely to support .ico files. The only types that can be relied on are GIF, PNG & JPEG. For all types supported on any specific JRE, use ImageIO.getReaderFileSuffixes() (but seriously, for app. icons stick to the 3 types with guaranteed support).
The code is trying to load an application resource as a file, when it will likely be (or become) an embedded-resource that should be accessed by URL. See the embedded resource info. page for tips on how to form the URL.
I apologize for the long question.
I was browsing a forum the other day and I saw a few pieces of text that were linking to youtube and other sites.
I had to always highlight and then copy and paste or right click "go to" in google chrome browser.
Since I've been playing with Java a little bit, I thought about making my own little program that will give a link to text that has an address . For example if I said "hey, check this video out I saw the other day 'www.youtube.com' " I'd want the youtube part to be clickable.
Could anybody tell me if such a thing is possible and if it is, what libraries would I have to use for this and lastly, how can I find a list of all imports and libraries in java?
Thanks.
Use HTML in JEditorPane and add HyperLinkListener to detect click on URLs.
Than use Desktop API to open default browser with the URL.
Something like:
import java.awt.Desktop;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
public class Test {
public static void main(String[] argv) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JEditorPane jep = new JEditorPane();
jep.setContentType("text/html");//set content as html
jep.setText("Welcome to <a href='http://stackoverflow.com/'>StackOverflow</a>.");
jep.setEditable(false);//so its not editable
jep.setOpaque(false);//so we dont see whit background
jep.addHyperlinkListener(new HyperlinkListener() {
#Override
public void hyperlinkUpdate(HyperlinkEvent hle) {
if (HyperlinkEvent.EventType.ACTIVATED.equals(hle.getEventType())) {
System.out.println(hle.getURL());
Desktop desktop = Desktop.getDesktop();
try {
desktop.browse(hle.getURL().toURI());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
JFrame f = new JFrame("HyperlinkListener");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(jep);
f.pack();
f.setVisible(true);
}
});
}
}