如何让JList的getSelectedValue()返回House类对象?
我在使用JList展示包含地址的House对象,这些House对象存储在Neighborhood类的TreeMap中(不确定这是不是最佳选择)。我通过Map.Entry和.entrySet()将数据添加到DefaultListModel,再绑定到JList。
点击列表中的House对象时,希望弹出JDialog显示该房屋的地址、楼层数等属性,但调用getSelectedValue()时只能拿到toString()形式的字符串或通用Object类型,无法直接调用house.getAddress()。尝试将选中值强制转换为House类时,出现错误:
中文报错: java.util.TreeMap$Entry类无法转换为House类
原英文报错: class java.util.TreeMap$Entry cannot be cast to class House
从Map中直接打印属性没问题,但放入JList后就出现转换错误。
问题代码
DefaultListModel model = new DefaultListModel(); for (Map.Entry<String, House> value : neighborhood.houses.entrySet()) { System.out.println(value); //System.out.println(value.getValue().getAddress()); //< This seems to work model.addElement(value); } JList list = new JList(model); list.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { System.out.println(list.getSelectedValue()); House selectedObj = (House)list.getSelectedValue(); HouseDialog houseDialog = new HouseDialog (selectedObj); } } });
错误原因
你往DefaultListModel中添加的是**Map.Entry<String, House>对象**,而非House对象!所以选中后获取到的是Entry实例,自然无法强制转换为House类。
解决方案
方案1:直接添加House对象到模型(推荐)
修改循环中的代码,将Entry对应的House对象加入模型,而非Entry本身:
DefaultListModel model = new DefaultListModel(); for (Map.Entry<String, House> entry : neighborhood.houses.entrySet()) { // 加入House对象,而非Entry model.addElement(entry.getValue()); }
此时在监听器中可以直接强转:
House selectedObj = (House) list.getSelectedValue(); HouseDialog houseDialog = new HouseDialog(selectedObj);
方案2:保留Entry,选中后先转Entry再取House
如果需要保留Entry(比如要用到TreeMap的key),则在监听器中先将选中值转为Map.Entry,再获取对应的House对象:
if (!e.getValueIsAdjusting()) { Map.Entry<String, House> selectedEntry = (Map.Entry<String, House>) list.getSelectedValue(); House selectedObj = selectedEntry.getValue(); HouseDialog houseDialog = new HouseDialog(selectedObj); }
额外优化:自定义JList显示内容
如果希望JList显示的是房屋地址(而非House默认的toString结果),可以自定义单元格渲染器:
list.setCellRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); // 针对House对象显示地址 if (value instanceof House) { setText(((House) value).getAddress()); } return this; } });
内容的提问来源于stack exchange,提问作者chalcedony

