Thursday, November 21, 2013

Swing Components in HTML GUI in Java

I would like to use Swing components in a HTML based layout. Initially I tried to have empty elements with id attributes in the loaded text, but they were pruned from the internal representation, so I put text inside of them and replaced the whole element with the Swing component.

HtmlGui.java:
package ca.sarah_happy.sandbox;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URL;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.html.HTMLDocument;

public class HtmlGui implements Runnable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new HtmlGui());
    }

    private JTextPane viewer;
    private HTMLDocument document;

    @Override
    public void run() {
        try {
            viewer = new JTextPane();
            viewer.setEditable(false);
            viewer.setPreferredSize(new Dimension(400, 300));

            JFrame frame = new JFrame("screen");
            frame.setContentPane(new JScrollPane(viewer));
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

            URL screen = HtmlGui.class.getResource("screen.html");
            viewer.setPage(screen);
            document = (HTMLDocument) viewer.getDocument();
            viewer.addPropertyChangeListener("page", onLoad);

            frame.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private JSlider slider;

    private PropertyChangeListener onLoad = new PropertyChangeListener() {
        @Override
        public void propertyChange(PropertyChangeEvent e) {
            JButton button = new JButton("Button");
            button.addActionListener(onButton);
            insertComponent("button", button);

            slider = new JSlider();
            slider.addChangeListener(onSlider);
            insertComponent("slider", slider);
        }
    };

    private ChangeListener onSlider = new ChangeListener() {
        @Override
        public void stateChanged(ChangeEvent e) {
            addOutput("changed slider: " + slider.getValue());
        }
    };

    private void insertComponent(String id, Component component) {
        Element e = document.getElement(id);
        viewer.setCaretPosition(e.getStartOffset());
        viewer.moveCaretPosition(e.getEndOffset());
        viewer.insertComponent(component);
    }

    private ActionListener onButton = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent arg0) {
            addOutput("pressed button");
        }
    };

    private void addOutput(String text) {
        try {
            Element out = document.getElement("output");
            document.insertString(out.getEndOffset() - 1, text + "\n", null);
        } catch (BadLocationException ex) {
            ex.printStackTrace();
        }
    }
}

screen.html:
<html><body>
Some stuff...

<p><span id="button">button</span> <span id="slider">slider</span></p>

<p><i>Output:</i>
<div id="output"></div></p>
</body></html>

No comments:

Post a Comment