2

GridBagLayout ベースの JPanels の構築を支援する Clojure マクロに取り組んでいます。マクロ内のデフォルト マップで Java クラスを名前空間修飾に取得できますが、引数として渡されたものは取得できません。逆引用符、引用符、チルダ、またはその他の魔法の組み合わせが必要ですか?

(import [java.awt GridBagConstraints GridBagLayout Insets]
        [javax.swing JButton JPanel])

(defmacro make-constraints [gridx gridy & constraints]
  (let [defaults
        {:gridwidth 1 :gridheight 1 :weightx 0 :weighty 0
         :anchor 'GridBagConstraints/WEST :fill 'GridBagConstraints/NONE
         :insets `(Insets. 5 5 5 5) :ipadx 0 :ipady 0}

        values
        (assoc (merge defaults (apply hash-map constraints))
          :gridx gridx :gridy gridy)]
    `(GridBagConstraints. ~@(map (fn [value]
                                   (if
                                    (or
                                     (number? value)
                                     (string? value)
                                     (char? value)
                                     (true? value)
                                     (false? value)
                                     (nil? value))
                                    value
                                    `~value))
                                 (map values
                                      [:gridx :gridy :gridwidth :gridheight
                                       :weightx :weighty :anchor :fill
                                       :insets :ipadx :ipady])))))

Insetsデフォルトマップで定義されたを使用すると、次のように修飾されます(「シンボルキャプチャ」ではありません) (java.awt.Insets ...)

user=> (macroexpand-1 '(make-constraints 0 0 :weightx 1))
(java.awt.GridBagConstraints.
 0 0 1 1 1 0
 GridBagConstraints/WEST GridBagConstraints/NONE
 (java.awt.Insets. 5 5 5 5) 0 0)

しかし、引数として渡すと、そうではありません:

user=> (macroexpand-1 '(make-constraints 1 1 :insets (Insets. 2 2 2 2)))
(java.awt.GridBagConstraints.
 1 1 1 1 0 0
 GridBagConstraints/WEST GridBagConstraints/NONE
 (Insets. 2 2 2 2) 0 0)

私は単に執着者になろうとしているのではありません。GridBagConstraints適切なコンストラクターが見つからないというコンパイラ エラーが発生します。

4

2 に答える 2

3

わかりませんGridBagLayoutが、以下は基本的にマクロと同様に機能するはずです。:height1 より大きいコンポーネントがある場合は、nilその下に列を追加して、列カウンターの同期を維持する必要があります。カウンターを正しく保つために、行の前にarrive-text-field行を追加する必要があるよりも、高さが2になるとしましょう。それはただのクイックハックです。nildepart-label

(def default-opts
  {:insets   (Insets. 0 0 0 0)
   :width    1
   :height   1
   :weight-x 0.0
   :weight-y 0.0
   :fill     GridBagConstraints/NONE
   :anchor   GridBagConstraints/WEST
   :ipadx    0
   :ipady    0})

(defn grid-bag-constraints
  [x y global-opts opts]
  (let [{:keys [insets width height weight-x weight-h
                fill anchor ipadx ipady]}
        (merge default-opts global-opts opts)]
    (GridBagConstraints. x y width height weight-x weight-h
                         anchor fill insets ipadx ipady)))

(defn grid-bag-container
  [panel global-opts & rows]
  (doseq [[row-idx row] (map-indexed identity rows)
          [col-idx [target & {:as opts}]] (map-indexed identity row)
          :when target]
    (let [constraints (grid-bag-constraints col-idx row-idx global-opts opts)]
      (.add panel target constraints))))

使い方は今まで通り。

于 2011-07-01T13:09:15.080 に答える
1

これが私の解決策です。私が書いているSwingアプリケーションでそれを使用しています。これにより、(2つの異なるパネルの)コード記述の多くの行がすでに節約され、手書きのコードと同じくらい高速になります。

(defmacro grid-bag-container [container & args]
  "Fill and return a java.awt.Container that uses the GridBagLayout.
  The macro defines a set of default constraints for the GridBagConstraints:
    :gridwidth 1
    :gridheight 1
    :weightx 0
    :weighty 0
    :anchor :WEST
    :fill :NONE
    :insets (Insets. 5 5 5 5)
    :ipadx 0
    :ipady 0
  These defaults can be overridden in the call to the macro in two way:
    - If the first argument is a hash-map of constraint names and values
      (e.g.: {:weightx 1}), these will override the defaults for the
      entire container.
    - Each individual item (see below) can override the global defaults
      and container defaults for itself.
  The constraints consist of constraint name (as a keyword with the same
  name as the GridBagConstraints field), and a value, which can also be
  a keyword, in which case the appropriate constant from GridBagConstraints
  will be substituted (e.g.: :NONE == GridBagConstraints.NONE), or the value
  can be an expression (e.g.: 0 or (Insets. 2 2 2 2)).
  Following the optional container default overrides hash-map are one or
  more row specification vectors. Each vector represents one row and
  increments gridy (starting from 0). Each vector contains one or more
  item vectors representing the individual components to be added to the
  container. Each item vector has the component as its first value,
  followed by zero or more constraint overrides as keyword-value pairs.
  (e.g.: [myButton :gridwidth 2 :weightx 1]). The values may be keywords
  and are expanded to GridBagConstraints constants as described above.
  Each item vector gets the next value of gridx (starting with 0) in that
  row.
  For example:
    (grid-bag-container panel
      {:insets (Insets. 1 1 1 1)}
      [[button :gridwidth 2 :weightx 1.0 :fill :HORIZONTAL]]
      [[check-box :gridwidth 2 :weightx 1.0 :anchor :CENTER]]
      [[arrive-label] [arrive-text-field :fill :HORIZONTAL]]
      [[depart-label] [depart-text-field :fill :HORIZONTAL]])
  will expand to the hand-written equivalent:
    (doto panel
      (.add button
        (GridBagConstraints. 0 0 2 1 1.0 0  ; gridx: 0 gridy: 1
                             GridBagConstraints/WEST
                             GridBagConstraints/HORIZONTAL
                             (Insets. 1 1 1 1) 0 0))
      (.add check-box
        (GridBagConstraints. 0 1 2 1 1.0 0  ; gridx: 0 gridy: 1
                             GridBagConstraints/CENTER
                             GridBagConstraints/NONE
                             (Insets. 1 1 1 1) 0 0))
      (.add arrive-label
        (GridBagConstraints. 0 2 1 1 0 0    ; gridx: 0 gridy: 2
                             GridBagConstraints/WEST
                             GridBagConstraints/NONE
                             (Insets. 1 1 1 1) 0 0))
      (.add arrive-text-field
        (GridBagConstraints. 1 2 1 1 0 0    ; gridx: 1 gridy: 2
                             GridBagConstraints/WEST
                             GridBagConstraints/HORIZONTAL
                             (Insets. 1 1 1 1) 0 0))
      (.add depart-label
        (GridBagConstraints. 0 3 1 1 0 0    ; gridx: 0 gridy: 3
                             GridBagConstraints/WEST
                             GridBagConstraints/NONE
                             (Insets. 1 1 1 1) 0 0))
      (.add depart-text-field
        (GridBagConstraints. 1 3 1 1 0 0    ; gridx: 1 gridy: 3
                             GridBagConstraints/WEST
                             GridBagConstraints/HORIZONTAL
                             (Insets. 1 1 1 1) 0 0))
  @param container the java.awt.Container to fill
  @param args the components and GridBagContraints speicifcations
  @returns the filled Container"
  (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 rows]
        (if (map? (first args))
          [(into global-defaults (first args)) (rest args)]
          [global-defaults args])]
    `(doto ~container
      ~@(loop [gridy 0 rows rows ret []]
        (if (seq rows)
          (recur (inc gridy) (rest rows)
            (into ret
              (let [row (first rows)]
                (loop [gridx 0 row row ret []]
                  (if (seq row)
                    (recur (inc gridx) (rest row)
                      (conj ret
                        (let [item
                              (first row)

                              component
                              (first item)

                              constraints
                              (assoc (merge defaults
                                            (apply hash-map (rest item)))
                                :gridx gridx :gridy gridy)

                              constraint-values
                              (map (fn [value]
                                (if (keyword? value)
                                  `(. GridBagConstraints
                                      ~(symbol (name value)))
                                  `~value))
                                (map constraints
                                  [:gridx :gridy :gridwidth :gridheight
                                   :weightx :weighty :anchor :fill
                                   :insets :ipadx :ipady]))]
                          `(.add ~component (new GridBagConstraints
                                                 ~@constraint-values)))))
                    ret)))))
          ret)))))

amalloyuser100464、およびkotarakの支援に感謝します。

于 2011-07-01T12:41:29.550 に答える