重新填充 JComboBox 模型,同时保持当前选择

问题描述 投票:0回答:1

我对 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();
                }
            }
        });
    }
}
java swing jcombobox
1个回答
0
投票

为什么我必须处理组合框?我以为模型就足够了...

我同意,更新模型应该会导致视图更新。

您的代码始终设置可能导致问题的所选项目。

我修改了您的代码,以在模型中找不到所选项目时清除所选项目,并且您不需要引用组合框:

// 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;
© www.soinside.com 2019 - 2024. All rights reserved.