Rendering HTML in Java - java

I am trying to create a help panel for an application I am working on. The help file as already been created using html technology and I would like it to be rendered in a pane and shown. All the code I have seen shows how to render a site e.g. "http://google.com". I want to render a file from my pc e.g. "file://c:\tutorial.html"
This is the code i have, but it doesn't seem to be working.
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import java.awt.Color;
import java.awt.Container;
import java.io.IOException;
import static java.lang.System.err;
import static java.lang.System.out;
final class TestHTMLRendering
{
// ------------------------------ CONSTANTS ------------------------------
/**
* height of frame in pixels
*/
private static final int height = 1000;
/**
* width of frame in pixels
*/
private static final int width = 1000;
private static final String RELEASE_DATE = "2007-10-04";
/**
* title for frame
*/
private static final String TITLE_STRING = "HTML Rendering";
/**
* URL of page we want to display
*/
private static final String URL = "file://C:\\print.html";
/**
* program version
*/
private static final String VERSION_STRING = "1.0";
// --------------------------- main() method ---------------------------
/**
* Debugging harness for a JFrame
*
* #param args command line arguments are ignored.
*/
#SuppressWarnings( { "UnusedParameters" } )
public static void main( String args[] )
{
// Invoke the run method on the Swing event dispatch thread
// Sun now recommends you call ALL your GUI methods on the Swing
// event thread, even the initial setup.
// Could also use invokeAndWait and catch exceptions
SwingUtilities.invokeLater( new Runnable()
{
/**
* } fire up a JFrame on the Swing thread
*/
public void run()
{
out.println( "Starting" );
final JFrame jframe =
new JFrame( TITLE_STRING + " " + VERSION_STRING );
Container contentPane = jframe.getContentPane();
jframe.setSize( width, height );
contentPane.setBackground( Color.YELLOW );
contentPane.setForeground( Color.BLUE );
jframe.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
try
{
out.println( "acquiring URL" );
JEditorPane jep = new JEditorPane( URL );
out.println( "URL acquired" );
JScrollPane jsp =
new JScrollPane( jep,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
contentPane.add( jsp );
}
catch ( IOException e )
{
err.println( "can't find URL" );
contentPane.add( new JLabel( "can't find URL" ) );
}
jframe.validate();
jframe.setVisible( true );
// Shows page, with HTML comments erroneously displayed.
// The links are not clickable.
}
} );
}// end main
}// end TestHTMLRendering

Rendering HTML in Swing is problematic. Swing components have some native support for HTML but it's not even HTML4. It's (limited!) HTML 3.2. If you use a different desktop library API you'll have much better options
WebKit for SWT (ver. 0.6) for the Eclipse Standard Widget Tookit is an excellent option. As the name suggests, it plugs the WebKit rendering engine (which powers Chrome and Safari) into SWT;
Netbeans Platform may have some options too.
You may also want to look at Flying Saucer, which is:
An XML/XHTML/CSS 2.1 Renderer
(in 100% Java)

You forgot to set the content type of the JEditorPane.
jep.setContentType("text/html");

What #cletus says is all true. If you want to get your current app going though with a file-based URL, try setting:
URL = "file:///C://print.html"

Related

Vaadin 14 Open new component in new Browser tab

is there a way i can open a pdf embedded into a component and send to a new browser tab?
The idea is to set the resource to this component and open in a new tab. I will need to in more buttons later to navigate between different documents.
public class EmbeddedPdfDocument extends Component implements HasSize {
public EmbeddedPdfDocument(StreamResource resource) {
this();
getElement().setAttribute("data", resource);
}
public EmbeddedPdfDocument(String url) {
this();
getElement().setAttribute("data", url);
}
protected EmbeddedPdfDocument() {
getElement().setAttribute("type", "application/pdf");
setSizeFull();
}
}
This thread in the Vaadin.com forum discusses your issue.
Anchor::setTarget ➙ "_blank"
Use the Anchor widget for your link. See demo page.
➥ The key is to set the “target” to the string _blank.
String url = "…" ;
Anchor anchor = new Anchor( url , "Open a PDF document" ) ;
anchor.setTarget( "_blank" ) ; // Specify `_blank` to open in a new browser tab/window.
Here is a complete example app in Vaadin 14.1.19 based on a starter project of the Plain Java Servlet variety.
Run this example app. Click the link to see another web browser tab open and display the PDF document.
package work.basil.example;
import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.PWA;
/**
* The main view contains a button and a click listener.
*/
#Route ( "" )
// #PWA ( name = "Project Base for Vaadin", shortName = "Project Base" )
#CssImport ( "./styles/shared-styles.css" )
#CssImport ( value = "./styles/vaadin-text-field-styles.css", themeFor = "vaadin-text-field" )
public class MainView extends VerticalLayout
{
public MainView ( )
{
// Widgets
H1 heading = new H1( "Download PDF in browser tab" );
String url = "https://www.fda.gov/media/76797/download";
Anchor anchor = new Anchor( url , "Open a PDF document" );
anchor.setTarget( "_blank" ); // Specify `_blank` to open in a new browser tab/window.
// Arrange
this.add( heading , anchor );
}
}

Web scraping console output in Swing GUI [duplicate]

I have posted two pieces of code below. Both codes work fine individually. Now, when I run the file Easy, and click on the "Start" button, I want the class AddNumber to be implemented. I mean to say that, instead of the AddNumber running on the console, is there any way I could make AddNumber run in the JTextArea i have created in the first class upon clicking the "Start" button? I thought maybe by action listener?(the way we do in case of buttons) But I'm not sure. Is there any other way to make my JTextArea act as a console for the other .java files?
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Easy extends JFrame{
JTextArea text=new JTextArea();
JPanel panel=new JPanel(new GridLayout(2,2));
JButton button1 =new JButton("Start");
public Easy(){
panel.add(text);
panel.add(button1);
add(panel,BorderLayout.CENTER);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae){
//add code to call the other class and make the JTextArea act as a console
}
});
}
public static void main(String arg[]){
Easy frame=new Easy();
frame.setSize(300,100);
frame.setVisible(true);
}
}
The second class:
import java.util.Scanner;
class AddNumber
{
public static void main(String args[])
{
int x, y, z;
System.out.println("Enter two numbers to be added ");
Scanner in = new Scanner(System.in);
x = in.nextInt();
y = in.nextInt();
z = x + y;
System.out.println("Sum of entered numbers = "+z);
}
}
I have seen a few posts talking about PrintStream..but i don't think that applies here.
Please help me out. Thanks :)
UPDATE: well i found this link: http://www.codeproject.com/Articles/328417/Java-Console-apps-made-easy#HowtousethisJavaConsole1 and it works in the sense that it shows "Enter two numbers to be added "...but where can the user provide his input?
EDIT: I just had to make a reference of the console in the main method of my class...and it works... well, not exactly as i would've wished to..but partly..the input still has to go from the terminal of the IDE..
If you do a Google search for: "stdout JTextArea", you will a couple of links to solve your problem.
http://www.coderanch.com/t/458147/GUI/java/Redirect-output-stderr-stdout-JTextArea
Redirecting System.out to JTextPane
http://www.jcreator.com/forums/index.php?showtopic=773
In the last link, buddybob extends java.io.OutputStream to print standard output to his JTextArea. I included his solution below.
TextAreaOutputStream.java
/*
*
* #(#) TextAreaOutputStream.java
*
*/
import java.io.IOException;
import java.io.OutputStream;
import javax.swing.JTextArea;
/**
* An output stream that writes its output to a javax.swing.JTextArea
* control.
*
* #author Ranganath Kini
* #see javax.swing.JTextArea
*/
public class TextAreaOutputStream extends OutputStream {
private JTextArea textControl;
/**
* Creates a new instance of TextAreaOutputStream which writes
* to the specified instance of javax.swing.JTextArea control.
*
* #param control A reference to the javax.swing.JTextArea
* control to which the output must be redirected
* to.
*/
public TextAreaOutputStream( JTextArea control ) {
textControl = control;
}
/**
* Writes the specified byte as a character to the
* javax.swing.JTextArea.
*
* #param b The byte to be written as character to the
* JTextArea.
*/
public void write( int b ) throws IOException {
// append the data as characters to the JTextArea control
textControl.append( String.valueOf( ( char )b ) );
}
}
The TextAreaOutputStream extends the java.io.OutputStream class
and overrides its write(int) method overload, this class uses a
reference to a javax.swing.JTextArea control instance and then
appends output to it whenever its write( int b ) method is called.
To use the TextAreaOutputStream class, [yo]u should use:
Usage
// Create an instance of javax.swing.JTextArea control
JTextArea txtConsole = new JTextArea();
// Now create a new TextAreaOutputStream to write to our JTextArea control and wrap a
// PrintStream around it to support the println/printf methods.
PrintStream out = new PrintStream( new TextAreaOutputStream( txtConsole ) );
// redirect standard output stream to the TextAreaOutputStream
System.setOut( out );
// redirect standard error stream to the TextAreaOutputStream
System.setErr( out );
// now test the mechanism
System.out.println( "Hello World" );

Java simple web browser weird output

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.

Handle on launched JavaFX Application

How do I get a handle on a JavaFX application started using the following code?
CPUUsageChart.launch(CPUUsageChart.class);
CPUUsageChart extends Application from JavaFX and I am launching it from a main method of a simple Java project.
What I ultimately want to achieve is, that I can start the App and use its methods in the simple Java code, so that I do not have to do the calling in the Constructor of the Application extending class. I only want to use JavaFX's abilities for drawing charts and save them to HDD, for later usage, but I do not need to see any GUI made in JavaFX.
Proposed Solution
You can only launch an application once, so there will only ever be a single instance of your application class.
Because there is only a single instance of the application, you can store a reference to the instance in a static variable of the application when the application is started and you can get the instance as required from a static method (a kind of singleton pattern).
Caveats
Care must be taken to ensure:
The instance is available before you try to use it.
That threading rules are appropriately observed.
That the JavaFX Platform is appropriately shutdown when it is no longer required.
Sample Solution
The sample code below uses a lock and a condition to ensure that the application instance is available before you try to use it. It will also require explicit shutdown of the JavaFX platform when it is no longer required.
Thanks to StackOverflow user James-D for some edit assistance with this code.
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class CPUUsageChart extends Application {
private static CPUUsageChart appInstance;
private static final Lock lock = new ReentrantLock();
private static final Condition appStarted = lock.newCondition();
/**
* Starts the application and records the instance.
* Sets the JavaFX platform not to exit implicitly.
* (e.g. an explicit call to Platform.exit() is required
* to exit the JavaFX Platform).
*/
#Override
public void start(Stage primaryStage) {
lock.lock();
try {
Platform.setImplicitExit(false);
appInstance = this;
appStarted.signalAll();
} finally {
lock.unlock();
}
}
/**
* Get an instance of the application.
* If the application has not already been launched it will be launched.
* This method will block the calling thread until the
* start method of the application has been invoked and the instance set.
* #return application instance (will not return null).
*/
public static CPUUsageChart getInstance() throws InterruptedException {
lock.lock();
try {
if (appInstance == null) {
Thread launchThread = new Thread(
() -> launch(CPUUsageChart.class),
"chart-launcher"
);
launchThread.setDaemon(true);
launchThread.start();
appStarted.await();
}
} finally {
lock.unlock();
}
return appInstance;
}
/**
* Public method which can be called to perform the main operation
* for this application.
* (render a chart and store the chart image to disk).
* This method can safely be called from any thread.
* Once this method is invoked, the data list should not be modified
* off of the JavaFX application thread.
*/
public void renderChart(
ObservableList<XYChart.Data<Number, Number>> data
) {
// ensure chart is rendered on the JavaFX application thread.
if (!Platform.isFxApplicationThread()) {
Platform.runLater(() -> this.renderChartImpl(data));
} else {
this.renderChartImpl(data);
}
}
/**
* Private method which can be called to perform the main operation
* for this application.
* (render a chart and store the chart image to disk).
* This method must be invoked on the JavaFX application thread.
*/
private void renderChartImpl(
ObservableList<XYChart.Data<Number, Number>> data
) {
LineChart<Number, Number> chart = new LineChart<>(
new NumberAxis(),
new NumberAxis(0, 100, 10)
);
chart.setAnimated(false);
chart.getData().add(
new XYChart.Series<>("CPU Usage", data)
);
Scene scene = new Scene(chart);
try {
LocalDateTime now = LocalDateTime.now();
File file = Paths.get(
System.getProperty("user.dir"),
"cpu-usage-chart-" + now + ".png"
).toFile();
ImageIO.write(
SwingFXUtils.fromFXImage(
chart.snapshot(null, null),
null
),
"png",
file
);
System.out.println("Chart saved as: " + file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
To use this (from any thread):
try {
// get chartApp instance, blocking until it is available.
CPUUsageChart chartApp = CPUUsageChart.getInstance();
// call render chart as many times as you want
chartApp.renderChart(cpuUsageData);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// note your program should only ever exit the platform once.
Platform.exit();
}
Complete sample application which creates five graphs of cpu usage data with ten samples in each chart, each sample spaced by 100 milliseconds. As the sample invokes the chart application to render the charts, it will create chart png image files in the current java working directory and the file names will be output to the system console. No JavaFX stage or window is displayed.
Code to sample CPU usage copied from: How to get percentage of CPU usage of OS from java
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.XYChart;
import javax.management.*;
import java.lang.management.ManagementFactory;
public class ChartTest {
public static void main(String[] args) {
try {
CPUUsageChart chart = CPUUsageChart.getInstance();
for (int i = 0; i < 5; i++) {
ObservableList<XYChart.Data<Number, Number>> cpuUsageData = FXCollections.observableArrayList();
for (int j = 0; j < 10; j++) {
cpuUsageData.add(
new XYChart.Data<>(
j / 10.0,
getSystemCpuLoad()
)
);
Thread.sleep(100);
}
chart.renderChart(cpuUsageData);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (MalformedObjectNameException | ReflectionException | InstanceNotFoundException e) {
e.printStackTrace();
} finally {
Platform.exit();
}
}
public static double getSystemCpuLoad() throws MalformedObjectNameException, ReflectionException, InstanceNotFoundException {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
AttributeList list = mbs.getAttributes(name, new String[]{ "SystemCpuLoad" });
if (list.isEmpty()) return Double.NaN;
Attribute att = (Attribute)list.get(0);
Double value = (Double)att.getValue();
if (value == -1.0) return Double.NaN; // usually takes a couple of seconds before we get real values
return ((int)(value * 1000) / 10.0); // returns a percentage value with 1 decimal point precision
}
}
Sample output (percentage CPU usage on the Y axis, and time in tenth of second sample spacing on the X axis).
Background Information
Application javadoc to further understand the JavaFX application lifecycle.
Related question: How do I start again an external JavaFX program? Launch prevents this, even if the JavaFX program ended with Platform.Exit
Alternate Implementations
You could use a JFXPanel rather than a class which extends Application. Though, then your application would also have a dependency on Swing.
You could make the main class of your application extend Application, so the application is automatically launched when your application is started rather than having a separate Application just for your usage chart.
If you have lots and lots of charts to render you could look a this off screen chart renderer implementation.

Using an icon image for a GUI

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.

Categories

Resources