本範例構建一個 Swing 表單介面,包含「省/直轄市」與「市/縣」兩個 JComboBox,實現經典的二級聯動效果:選擇省份後,城市下拉框即時更新為該省份對應的城市列表。資料結構採用 LinkedHashMap<String, String[]> 保持省份順序,UI 採用 DefaultComboBoxModel 動態綁定資料。
CityMap 類別靜態初始化全國 34 個省級行政區及其轄下城市:
public class CityMap {
public static Map<String, String[]> model = new LinkedHashMap<>();
static {
model.put("北京", new String[]{"北京"});
model.put("上海", new String[]{"上海"});
model.put("廣東", new String[]{"廣州","深圳","佛山","東莞", ...});
// ... 其餘省份
}
}
使用 LinkedHashMap 保證遍歷順序與插入順序一致,下拉框顯示順序穩定。
MainFrame 繼承 JFrame,採用絕對佈局 (null layout) 配合 BackgroundPanel 繪製背景圖:
public class MainFrame extends JFrame {
private JComboBox<String> comboBox; // 省份
private JComboBox<String> cityComboBox; // 城市
...
}
public Object[] getProvince() {
Set<String> set = CityMap.model.keySet();
return set.toArray(); // 直接轉 Object[] 供 DefaultComboBoxModel 使用
}
public String[] getCity(String province) {
return CityMap.model.get(province);
}
comboBox.addItemListener(e -> {
if (e.getStateChange() == ItemEvent.SELECTED) {
String province = (String) comboBox.getSelectedItem();
cityComboBox.removeAllItems();
cityComboBox.setModel(new DefaultComboBoxModel<>(getCity(province)));
}
});
JPanel,重寫 paintComponent() 繪製拉伸背景圖。
介面包含:姓名、性別、省市聯動、詳細地址、Email、儲存/重置按鈕,模擬真實註冊表單場景。
| 維度 | 做法 | 優勢 |
|---|---|---|
| 資料結構 | LinkedHashMap<String, String[]> | 有序、查找 O(1)、記憶體緊湊 |
| 模型驅動 | DefaultComboBoxModel | 分離資料與視圖,支援動態替換 |
| 事件處理 | ItemListener + SELECTED 狀態過濾 | 避免雙重觸發(DESELECTED + SELECTED) |
| 資源管理 | SwingResourceManager 快取 | 避免重複載入圖片,提升效能 |
| 背景繪製 | 自定義 JPanel + paintComponent | 輕量級背景,不干擾子元件佈局 |
e.getStateChange() == ItemEvent.SELECTED,否則邏輯執行兩次。getCity() 應檢查 province != null,否則 map.get(null) 回傳 null 導致 NPE。GridBagLayout、MigLayout 或 TableLayout 實現響應式佈局。native2ascii 轉義。Map<String, Map<String, String[]>>)。AutoCompleteDecorator 或自定義 ComboBoxModel)。本範例以 Map + JComboBox + ItemListener 實現經典省市二級聯動,程式碼結構清晰、資料與 UI 分離、事件處理規範。掌握此模式,可輕鬆應用於「國家-城市」、「分類-子分類」、「品牌-車系」等各類層級聯動場景。