这个swing tablemodel代码设计得很糟糕吗?

时间:2012-02-07 11:34:17

标签: swing clojure

上下文:我有一个基于clojure的填字游戏应用程序,其主要UI是一个带有两个选项卡的JTabbedPane,一个网格和一个线索表。线索表是一个线索向量的视图,但是向量本身不是数据的权威存储,而是通过(active-cluelist)函数从几个内部数据结构动态生成,由线索选项卡触发地选择。

所以这是线索表的实现:

(def cluelist [])
(def update-cluelist)
(def model)

(defn make []
  (let [column-names ["Sq" "Word" "Clue"]
        column-widths [48 200 600]
        table-model (proxy [AbstractTableModel] []
                      (getColumnCount [] (count column-names))
                      (getRowCount [] (count cluelist))
                      (isCellEditable [row col] (= col 2))
                      (getColumnName [col] (nth column-names col))
                      (getValueAt [row col] (get-in cluelist [row col]))
                      (setValueAt [s row col]
                                  (let [word (get-in cluelist [row 1])]
                                    (add-clue word s) ; editing a cell updates the main clue data
                                    (def cluelist (assoc-in cluelist [row 2] s))
                                    (. this fireTableCellUpdated row col))))
        table (JTable. table-model)
        ]

; some pure display stuff elided

(def model table-model)
)

(defn update-cluelist []
  (def cluelist (active-cluelist))
  (.fireTableDataChanged model))

在另一个讨论中有人指出,(update-cluelist)手动调用fireTableDataChanged是一个主要的代码味道,因为TableModel类之外的任何内容都不应该调用该方法。但是,我觉得这是从外部源动态生成表的不可避免的后果。文档不太有用 - 他们说明了

  

您的自定义类只需要调用以下一个   AbstractTableModel方法每次表数据都被更改   外部来源。

隐含地假定CustomTableModel类是数据的权威来源。

此处还有一些clojure / java阻抗不匹配 - 在java中我会cluelistupdate-cluelist是我的TableModel的私有成员和方法,而在clojure {{1表模型是cluelist可以访问的动态范围变量。

我的主要问题是没有太多的clojure / swing代码,我可以寻找最佳实践。有没有人对最佳方法有任何建议?

1 个答案:

答案 0 :(得分:2)

建议:使用原子作为cluelist。不断重新定义的cluelist不是表示可变数据的正确方法。老实说,我希望第二次定义cluelist时会抛出异常。

如果您将一个原子用于cluelist,则可以从观察者调用fireTableDataChanged方法,而不是手动调用它。这意味着您可以随时(以及任何地方)更改原子,fireTableDataChanged将自动调用,而无需显式调用。

def的问题是,在多线程环境中多次调用def并且Clojure会尝试将所有内容默认为相当线程安全。据我了解,使用var的“正确”方法是单独保留其根绑定(即,不要再次调用def)并在需要本地更改时使用bindingdef可能会按照您使用它的方式工作,但语言设置为在这种情况下支持原子,引用或代理,这些可能在大多数情况下都会更好地工作(即您获得观察者)。此外,如果您稍后添加它们,则无需担心线程。