我对 Java 和 Java Swing 很陌生,但它是我继承的。 我试图找出使组合框与不断变化的列表保持同步的最佳方法。如果用户已经选择了一个项目并且该项目仍在新列表中,我想保持它的选择状态。以下代码似乎有效,但我正在寻找建议以使其更好、更干净等,尤其是在摆动工人的“完成”方法中。目前我正在处理组合框和模型(我认为仅模型就足够了)。
在我的示例中,汽车列表前 4 辆相同,后 5-7 辆随机添加或删除。
class CBItem {
private int id;
private String description;
public CBItem(int id, String description) {
this.id = id;
this.description = description;
}
public int getId() {
return id;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return description;
}
@Override
public boolean equals(Object o) {
boolean equal = true;
if (!(o instanceof CBItem)) {
equal = false;
}
else {
CBItem other = (CBItem)o;
equal = other.description.equals(this.description);
}
return equal;
}
}
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.Timer;
public class JComboBoxFiller extends JFrame {
private static final long serialVersionUID = 1L;
JPanel pnlMain;
DefaultComboBoxModel<CBItem> mdlCars = new DefaultComboBoxModel<CBItem>();
List<CBItem> lstCurrentCars = new ArrayList<CBItem>();
JComboBox<CBItem> cbxCars;
final String[] arrCarNames = new String[] {"Audi", "BMW", "Chevrolet", "Dodge", "Ford", "Hyundai", "Jaguar"};
public JComboBoxFiller() {
setTitle("ComboBox Filler Demo");
setBounds(100, 100, 400, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pnlMain = new JPanel(new BorderLayout());
setContentPane(pnlMain);
cbxCars = new JComboBox<CBItem>(mdlCars);
JPanel pnlCenter = new JPanel();
pnlCenter.add(cbxCars, BorderLayout.CENTER);
pnlMain.add(pnlCenter, BorderLayout.CENTER);
setVisible(true);
// Every 5 seconds repopulate the list of cars
Timer timer = new Timer(3000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new RepopulateCarsWorker().execute();
}
});
timer.start();
}
// This will be called every 5 seconds. It populates a list of 4 to 7 cars (CBItems)
// then updates the combobox (cbxCars) with the new values.
// It needs to keep the current car selected (if one was and still exists)
private class RepopulateCarsWorker extends SwingWorker<ArrayList<CBItem>, Void>
{
ArrayList<CBItem> lstNewCars = new ArrayList<CBItem>();
protected ArrayList<CBItem> doInBackground()
{
Random rand = new Random();
int lastCar = 4 + rand.nextInt(3);
for (int c = 0; c < lastCar; c++) {
lstNewCars.add(new CBItem(c, arrCarNames[c]));
}
return lstNewCars;
}
protected void done()
{
try
{
ArrayList<CBItem> lstNewCars = get();
// If list stayed the same, nothing to do
if (lstNewCars.equals(lstCurrentCars)) {
return;
}
// Save the current selection so it can be reselected
CBItem cbCurrentSelection = (CBItem) mdlCars.getSelectedItem();
mdlCars.removeAllElements();
mdlCars.addAll(lstNewCars);
// Reselect if there was a selected item and it still exists
// Question: Why do I have to deal with the combobox?
// I thought model would be enough...
mdlCars.setSelectedItem(cbCurrentSelection);
cbxCars.setSelectedIndex(mdlCars.getIndexOf(cbCurrentSelection));
// Update current list for next comparison
lstCurrentCars = lstNewCars;
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JComboBoxFiller frame = new JComboBoxFiller();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
为什么我必须处理组合框?我以为模型就足够了...
我同意,更新模型应该会导致视图更新。
您的代码始终设置可能导致问题的所选项目。
我修改了您的代码,以在模型中找不到所选项目时清除所选项目,并且您不需要引用组合框:
// Save the current selection so it can be reselected
CBItem cbCurrentSelection = (CBItem) mdlCars.getSelectedItem();
// Reselect if there was a selected item and it still exists
// Question: Why do I have to deal with the combobox?
// I thought model would be enough...
mdlCars.removeAllElements();
mdlCars.addAll(lstNewCars);
int selected = mdlCars.getIndexOf(cbCurrentSelection);
if (selected == -1)
mdlCars.setSelectedItem(null);
else
mdlCars.setSelectedItem(cbCurrentSelection);
//cbxCars.setSelectedIndex(mdlCars.getIndexOf(cbCurrentSelection));
// Update current list for next comparison
lstCurrentCars = lstNewCars;