Sunday, January 30, 2022

Displaying Hiccup generated HTML with Swing

HTML is a very common data format, so we can make use of it with both ClojureScript as well as Clojure. In the later case, we can use HTML generated by Clojure in Java Swing applications. A number of Java Swing classes optionally use HTML in order to enrich the content of their interfaces. We can provide that HTML using Hiccup like so.
(ns swing-hiccup.basic
  (:require [hiccup.core :refer :all]
            [garden.core :refer [css]))
  (:import (javax.swing JFrame JLabel)))

(def introduction-to-category-theory
  [:html
   [:h1 "Introduction to category theory"]
   "The elements of a category are"
   [:ol
    [:li "Objects"]
    [:li "Morphisms"]]
   "associated to these elements of a category are functions"
   [:ol
    [:li "A source function f : Morphisms -> Objects"]
    [:li "A target function f : Morphisms -> Objects"]
    [:li "A composition function f : Morphisms2* -> Morphisms"]
    [:li "An identity function f : Objects -> Morphisms"]]
   "that satisfy axioms of associativity and identity."])

(defn view-html
  [arg]

  (let [^JFrame f (JFrame.)
        ^JLabel p (JLabel.
                    ^String
                    (html arg))]
    (.add f p)
    (.setTitle f "Abstract Algebra")
    (.setVisible f true)
    (.setSize f 450 300)))
This produces a Java Swing JFrame as depicted below, and so with Hicccup you can freely integrate HTML generated by Clojure into your Java swing applications. The Java standard library is much more sophisticated then just this, however. Java also comes with standard support for stylesheets provided by the java.swing.text.html package in the java.desktop module. In order to make things a little more interesting, here we not only use HTML and CSS in a Java Swing application, we programatically generate the HTML using Clojure.

This demonstrates how easy it is to generate HTML using Clojure because thanks to Hiccup it allows you to represent HTM as the same sort of S-expression the rest of the language deals with. It is for this resaon that I have always felt that Clojure is the best language for generating HTML (such as in Java Swing applications that make use of HTML or on the web).

In order to also programatically generate CSS as well we can simply make use of the Garden library. Garden is for CSS what Hiccup is for HTML, as it allows us to generated CSS from Clojure's EDN expressions. With this HTML, CSS, etc can all be represented as no different then any other data structure in Clojure. This gets to one of the advantages of the language which is that it is a common format for all kinds of data, as well as a common language for both the server side and the client side with Clojure Common.

In order to then display the generated HTML and CSS we just have to create a JEditorPane containing a HTMLEditorKit and then put it in a standard Java Swing JFrame. The CSS is added automatically by add rule on the Swing StyleSheet, and the HTML is provided as the text of the JEditorPane. Type hinting is used throughout to improve performance.
(ns swing-hiccup.styled
  (:require [hiccup.core :refer :all]
            [garden.core :refer [css]]
            [swing-hiccup.basic :refer :all])
  (:import (javax.swing JFrame JEditorPane)
           (javax.swing.text.html HTMLEditorKit StyleSheet)))

(defn join-table
  [n]

  (letfn [(cell-value [x y]
            (bit-or x y))]
    (map
      (fn [i]
        (map
          (fn [j]
            (cell-value i j))
          (range n)))
      (range n))))

(defn wrap-table
  [coll]

  (vec
    (conj
      (map
        (fn [row]
          (vec
            (conj
              (map
                (fn [i]
                  [:td (.toString i)])
                row)
              :tr)))
        coll)
      :table)))

(def css-data
  [[:body {:color "white"}]
   [:td {:border "1px solid black"
         :color "black"
         :font-size "16px"}]])

(def html-data
  [:html
   [:body
    (wrap-table (join-table 8))]])

(defn view-styled-html
  [html-data css-data]

  (let [^JEditorPane pane (JEditorPane.)
        ^HTMLEditorKit kit (HTMLEditorKit.)
        ^StyleSheet style-sheet (.getStyleSheet kit)
        ^JFrame frame (JFrame. )]
    (.setEditable pane false)
    (.setEditorKit pane kit)
    (.addRule style-sheet (css css-data))
    (.setDocument pane (.createDefaultDocument kit))
    (.setText pane (html html-data))
    (.add frame pane)
    (.setSize frame 350 350)
    (.setVisible frame true)
    (.setTitle frame "Multiplication Table")))
This Clojure based Java Swing application then produces an output JFrame that looks as displayed in the image below. The table displayed is a join semilattice of a boolean algebra, which can simply be described by bitwise operations. Hopefully this demonstrates the utility of HTML and CSS both in Clojure and in ClojureScript because even when are building our graphical interfaces with Java and Swing there are a number of cases in which we can make use of HTML and CSS. Its typically easier to use Clojure to generate HTML then Java, but it is easy enough to switch between the two of them.

No comments:

Post a Comment