Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6057735
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 23, 20262026-05-23T08:31:17+00:00 2026-05-23T08:31:17+00:00

I am writing a Clojure macro that accepts a description of a panel using

  • 0

I am writing a Clojure macro that accepts a description of a panel using java.awt.GridBagLayout and generates equivalent code (using (doto ...)) at compile time. I know about seesaw, but am trying to learn the ins and outs of macro writing.

My questions:

  • At what point during compilation are Java methods (like (Insets. 5 5 5 5)) compiled (bytecode generated)?
  • Why is it a problem returning these from the macro?
  • Shouldn’t the compiler “see” and compile the same thing as if I had hand-expanded the macro?
  • Is there anything that can be returned from helper functions that will improve the situation, perhaps using (eval ...) or #=(...), since there is no associated runtime penalty?

I know that this could be written as a (defn ...) and (easily) solve the problem. I would like to achieve the same result with a macro, because I can see other cases where the runtime performance penalty for a function might be unacceptable (not in this case, since this is GUI code). The reason I wrote this macro is because I believe that the result is much easier to read and maintain than the hand-expanded version.

I have included the definitions for the two (print-dup...) multimethods in a effort to satisfy the compiler and eliminate (unsuccessfully) the runtime error message “Can’t embed object in code, maybe print-dup not defined: java.awt.Insets[top=5,left=5,bottom=5,right=5]”

The macro is called like this:

(grid-bag-container (JPanel. (GridBagLayout.))
  [(JButton "Monday") :gridwidth 2 :weightx 1.0 :fill :HORIZONTAL]
  [(JCheckBox "Vacation")]
  [[(JLabel. "Arrive:")] [(JTextField. 6) :fill :HORIZONTAL]]
  [[(JLabel. "Depart:")] [(JTextField. 6) :fill :HORIZONTAL]])

Here is the intended expansion (pretty-printed for easy readability :-)):

(doto (JPanel. (GridBagLayout.))
  (.add (JButton "Monday")
        (GridBagConstraints. 0 0 2 1 1.0 0
                             (. GridBagConstraints WEST)
                             (. GridBagConstraints HORIZONTAL)
                             (Insets. 2 2 2 2) 0 0))
  (.add (JCheckBox "Vacation")
        (GridBagConstraints. 0 1 1 1 0 0
                             (. GridBagConstraints WEST)
                             (. GridBagConstraints NONE)
                             (Insets. 2 2 2 2) 0 0))
  (.add (JLabel. "Arrive:")
        (GridBagConstraints. 0 2 1 1 0 0
                             (. GridBagConstraints WEST)
                             (. GridBagConstraints NONE)
                             (Insets. 2 2 2 2) 0 0))
  (.add (JTextField. 6)
        (GridBagConstraints. 1 2 1 1 0 0
                             (. GridBagConstraints WEST)
                             (. GridBagConstraints HORIZONTAL)
                             (Insets. 2 2 2 2) 0 0))
  (.add (JLabel. "Depart:")
        (GridBagConstraints. 0 3 1 1 0 0
                             (. GridBagConstraints WEST)
                             (. GridBagConstraints NONE)
                             (Insets. 2 2 2 2) 0 0))
  (.add (JTextField. 6)
        (GridBagConstraints. 1 3 1 1 0 0
                             (. GridBagConstraints WEST)
                             (. GridBagConstraints HORIZONTAL)
                             (Insets. 2 2 2 2) 0 0)))

Here is the code:

(defmethod print-dup java.awt.GridBagConstraints [args writer]
  "A multimethod for converting java.awt.GridBagConstraints to a compiled form.
  @param args a collection of constructor arguments
  @param writer the Writer to which the output should be generated"
  (.write writer "#=(java.awt.GridBagConstraints. ")
  (.write writer (apply str (interpose " " (map str args))))
  (.write writer ")"))

(defmethod print-dup java.awt.Insets [args writer]
  "A multimethod for converting java.awt.Insets to a compiled form.
  @param args a collection of (Integer) constructor arguments
  @param writer the Writer to which the output should be generated"
  (.write writer "#=(java.awt.Insets. ")
  (.write writer (apply str (interpose " " (map str args))))
  (.write writer ")"))

(defmacro grid-bag-container [container & args]
  "Fill a container having a GridBagLayout with the given components.
   The args can start with an optional default-constraints map (see the
   doc-string for build-gbc (below) for details on the constraints map).
   Following the optional default-constraints are zero or more rows.
   Each row is a vector containing either a single component specification
   or multiple vectors of component specifications. Each component specification
   is a component (e.g.: JButton) followed by one or more key-value constraints
   of the same form as the default-constraints. Note that these key-value
   pairs are NOT contained in a map. Each row vector will be placed in
   the next gridy position (starting with 0). If a row vector contains only
   one component specification, that component will be placed at gridx=0.
   If a row vector contains vectors, each will be placed at the next gridx
   position (starting with 0). The default values for the constraints are as
   follows:
     :gridwidth 1
     :gridheight 1
     :weightx 0
     :weighty 0
     :anchor :WEST
     :fill :NONE
     :insets (Insets. 5 5 5 5)
     :ipadx 0
     :ipady 0
   For example:
     (grid-bag-container
       (JPanel.)
       {:insets (Insets. 2 2 2 2)}              ; Override the default (Insets. 5 5 5 5)
       [button :gridwidth 2 :weightx 1]         ; Add a button at (gridx=0, gridy=0) with the
                                                ; gridwidth=2 (overriding the default 1),
                                                ; and weightx=1 (overriding the default 0)
       [[label] [textfield :fill :HORIZONTAL]]) ; Add a label at (gridx=0, gridy=1)
                                                ; and a textfield at (gridx=1, gridy=1),
                                                ; with fill=GridBagContraints.CENTER
                                                ; (overriding the default GridBagContraints.WEST)
   This example will expand to
     (doto container
       (.add button (build-gbc {:gridx 0 :gridwidth 2 :ipadx 0 :ipady 0 :anchor :WEST :weighty 0
                                :gridheight 1 :weightx 1 :fill :NONE :insets (Insets. 2 2 2 2)
                                :gridy 0}))
       (.add label (build-gbc {:gridx 0 :gridwidth 1 :ipadx 0 :ipady 0 :anchor :WEST :weighty 0
                               :gridheight 1 :weightx 0 :fill :NONE :insets (Insets. 2 2 2 2)
                               :gridy 1}))
       (.add textfield (build-gbc {:gridx 1 :gridwidth 1 :ipadx 0 :ipady 0 :anchor :WEST :weighty 0
                                   :gridheight 1 :weightx 0 :fill :HORIZONTAL :insets (Insets. 2 2 2 2)
                                   :gridy 1})))
   @param container the java.awt.Container to fill
   @args an optional default-constraints map followed by zero or more row specifications
   @returns the container

   build-gbc:
   Build and return a GridBagConstraints containing the given constraints map.
   Each constraint is a (:key value) pair where the name of the key is a
   GridBagConstraints field (e.g.: gridwidth) and the value is either a keyword
   (e.g.: :CENTER), in which case the GridBagConstraints constant of the same name
   (e.g.: GridBagConstraints.CENTER) is used, or anything else, in which case the
   corresponding field is set to that value.
   Example:
     (build-gbc {:gridx 0
                 :gridy 0
                 :gridheight 1
                 :gridwidth 2
                 :weightx 1
                 :weighty 0
                 :anchor :CENTER
                 :fill :NONE
                 :insets (Insets. 2 2 2 2)
                 :ipadx 0
                 :ipady 0})
   will build and return a GridBagConstraints containing the following field values:
     gridx 0
     gridy 0
     gridheight 1
     gridwidth 2
     weightx 1
     weighty 0
     anchor GridBagConstraints.CENTER
     fill GridBagConstraints.NONE
     insets (Insets. 2 2 2 2)
     ipadx 0
     ipady 0.
   @param constraints a map containing the GridBagConstraints constraint values
   @returns a new GridBagConstraints
   @see http://stuartsierra.com/2010/01/05/taming-the-gridbaglayout"
  (let [global-defaults {:gridwidth 1
                         :gridheight 1
                         :weightx 0
                         :weighty 0
                         :anchor :WEST
                         :fill :NONE
                         :insets (Insets. 5 5 5 5)
                         :ipadx 0
                         :ipady 0}
        defaults
        (if (map? (first args))
          (first args)
          {})

        args
        (into []
          (if (map? (first args))
            (rest args)
            args))

        build-gbc
        (fn [constraints]
          (let [process-value
                #(if (nil? %)
                  nil
                  (if (keyword? %)
                    `(. GridBagConstraints ~(symbol (name %)))
                    %))]
            `(GridBagConstraints.
              ~(process-value (:gridx constraints))
              ~(process-value (:gridy constraints))
              ~(process-value (:gridwidth constraints))
              ~(process-value (:gridheight constraints))
              ~(process-value (:weightx constraints))
              ~(process-value (:weighty constraints))
              ~(process-value (:anchor constraints))
              ~(process-value (:fill constraints))
              ~(process-value (:insets constraints))
              ~(process-value (:ipadx constraints))
              ~(process-value (:ipady constraints)))))]
    `(doto ~container
      ~@(loop [end (count args)
               gridy 0
               ret []]
        (if (= end gridy)
          ret
          (let [row (nth args gridy)
                process-item
                (fn [component gridx gridy constraints]
                  (let [constraints
                        (reduce into global-defaults
                          [{:gridx gridx :gridy gridy}
                           defaults
                           (vec (map vec (partition 2 constraints)))])]
                    `(.add ~component ~(build-gbc constraints))))]
            (if (vector? (first row))
              (recur end
                (inc gridy)
                (into ret (for [gridx (range (count row))
                                :let [item (nth row gridx)
                                      component (first item)
                                      constraints (rest item)]]
                  (process-item component gridx gridy constraints))))
              (recur end
                (inc gridy)
                (conj ret (let [component (first row)
                                constraints (rest row)]
                  (process-item component 0 gridy constraints)))))))))))
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-23T08:31:18+00:00Added an answer on May 23, 2026 at 8:31 am

    AFAICS, the problem you’re running into is that you generate your Inset objects in the macro, instead of the code to generate the Inset objects. IOW, your :insets (Insets. 5 5 5 5) in global-defaults should instead be :insets '(Insets. 5 5 5 5) or something similar.

    The print-dup code is confusing and not needed, so just leave it out.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm writing some Clojure code that depends upon a number of constants. They will
I'm creating a library that includes both Clojure and Java code, and would like
I'm writing some clojure code, and I'm relying on Joda time for time handling.
I am writing a small Clojure project using leiningen with the following directory structure:
I am writing a function for my Clojure program that reads user input from
As for the background, I am writing a web service in Clojure (using Compojure
It is my understanding that the default ClassLoader used in Java (and thus, Clojure)
We are considering writing a static analyzer to collect software metrics for Clojure code.
When writing a graphical interface, using Java, what's the appropriate way of switching between
I need to add several methods to a Clojure defprotocol that I am writing

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.