上下文:我有一个基于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中我会cluelist
和update-cluelist
是我的TableModel的私有成员和方法,而在clojure {{1表模型是cluelist
可以访问的动态范围变量。
我的主要问题是没有太多的clojure / swing代码,我可以寻找最佳实践。有没有人对最佳方法有任何建议?
答案 0 :(得分:2)
建议:使用原子作为cluelist。不断重新定义的cluelist不是表示可变数据的正确方法。老实说,我希望第二次定义cluelist时会抛出异常。
如果您将一个原子用于cluelist,则可以从观察者调用fireTableDataChanged
方法,而不是手动调用它。这意味着您可以随时(以及任何地方)更改原子,fireTableDataChanged
将自动调用,而无需显式调用。
def
的问题是,在多线程环境中多次调用def
并且Clojure会尝试将所有内容默认为相当线程安全。据我了解,使用var的“正确”方法是单独保留其根绑定(即,不要再次调用def
)并在需要本地更改时使用binding
。 def
可能会按照您使用它的方式工作,但语言设置为在这种情况下支持原子,引用或代理,这些可能在大多数情况下都会更好地工作(即您获得观察者)。此外,如果您稍后添加它们,则无需担心线程。