我在控制器类中设置了组合框的模型
cboCategory.setModel(new ModernDefaultComboBoxModel(model.getProductCategories()));
productCategories
是String
的List
。ModernDefaultComboBoxModel
只是扩展DefaultComboBoxModel
的模型。
public class ModernDefaultComboBoxModel extends DefaultComboBoxModel{
public ModernDefaultComboBoxModel(List<String> elements){
super(elements.toArray());
}
}
现在在我的模型中,productCategories
是从数据库中填充的,在SwingWorker
SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
@Override
protected Void doInBackground() throws Exception {
//query and resultset stuff
while (rs.next()) {
publish(rs.getString(1));
}
//cleanup stuff
}
@Override protected void process(List<String> chunks){
List<String> oldCategories = new ArrayList<String>(productCategories);
for(String cat : chunks){
productCategories.add(cat);
}
fireModelPropertyChange(PRODUCT_CATEGORIES, oldCategories, productCategories);
}
@Override
protected void done(){
//some stuff
}
};
worker.execute();
您可以看到每个publish
,它都会向其侦听器触发一个属性更改事件(fireModelPropertyChange
只是firePropertyChange
的包装器)。
现在在我的模型监听器中,
@Override
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
//some branching for the other models
else if(ProductModel.PRODUCT_CATEGORIES.equals(propName)){
List<String> newVal = (List<String>)evt.getNewValue();
//notify the model of the combobox that the data is changed, so refresh urself
}
//some stuff
}
我被困在我的ModelListener
需要通知视图中的组合框,其模型中的数据被更改的部分。我与JTable
有相同的情况,但对于JTable
,我可以从AbstractTableModel
实现的模型中调用fireTableRowsInserted
。
实际上,在AbstractListModel
中有一个方法fireContentsChanged
,但不像在JTable
中,这个方法是受保护的,所以我不能访问它。
我知道我可以创建一个ModernDefaultComboBoxModel
的实例,然后调用组合框的setModel
方法来刷新组合框,但我只是想知道是否有一种"更干净"的方式像JTable
一样干净
JComboBox
实现ListDataListener
是为了监听自己的ComboBoxModel
。对DefaultComboBoxModel
的任何更改都应该调用AbstractListModel
中相关的fireXxxx()
方法,并且JComboBox
应该看到更改。只需在process()
中更新combo的模型。
附录:这是一个更新模型的最小示例。在model.addElement()
上设置断点,调试,单击添加,然后进入方法以查看对fireIntervalAdded()
的调用,随后更新视图。
JFrame f = new JFrame("ComboWorkerTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(0, 1));
final JComboBox jcb = new JComboBox(new Integer[]{value});
f.add(new JButton(new AbstractAction("Add") {
@Override
public void actionPerformed(ActionEvent e) {
DefaultComboBoxModel model = (DefaultComboBoxModel) jcb.getModel();
model.addElement(++value);
}
}));
f.add(jcb);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);