[英]Custom Render JPanel in a JList
我試圖通過修改渲染在 JList 中顯示面板。
我用 JLabel ( https://www.codejava.net/java-se/swing/jlist-custom-renderer-example ) 嘗試了一個例子,它工作得很好(見圖片)
所以我嘗試將它改編為 JPanel(而不是 JLabel),但我遇到了一個有趣的問題,我真的不知道如何解決它。
如您所見,不是只出現一次,而是每個國家和他的相關圖像都顯示在每一行上,我不明白為什么。 (有8行因為有8個國家)
這是我制作的代碼:
CountryRenderer.java
import java.awt.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class CountryRenderer extends JPanel implements ListCellRenderer<Country> {
@Override
public Component getListCellRendererComponent(JList<? extends Country> list, Country country, int index,
boolean isSelected, boolean cellHasFocus) {
String code = country.getCode();
// to load and resize the image
Image imgSettings = null;
try {
imgSettings = ImageIO.read(getClass().getResource("./images/" + code + "1.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
imgSettings = imgSettings.getScaledInstance(25, 25, imgSettings.SCALE_SMOOTH);
// create the button and put the image on it
JButton buttontest = new JButton() ;
buttontest.setIcon(new ImageIcon(imgSettings));
add(buttontest);
// create the text (name of the country)
JTextField txtest = new JTextField();
txtest.setText(country.getName());
add(txtest);
return this;
}
}
如果您需要其他 2 個文件來運行此文件,它們位於我在上面或此處提供的鏈接上:
國家.java
public class Country {
private String name;
private String code;
public Country(String name, String code) {
this.name = name;
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return name;
}
}
這是您可以運行的文件:JListCustomRendererExample.java
import javax.swing.*;
public class JListCustomRendererExample extends JFrame {
public JListCustomRendererExample() {
Country us = new Country("USA", "1");
Country in = new Country("India", "2");
Country vn = new Country("Vietnam", "3");
Country ca = new Country("Canada", "4");
Country de = new Country("Denmark", "5");
Country fr = new Country("France", "6");
Country gb = new Country("Great Britain", "7");
Country jp = new Country("Japan", "8");
//create the model and add elements
DefaultListModel<Country> listModel = new DefaultListModel<>();
listModel.addElement(us);
listModel.addElement(in);
listModel.addElement(vn);
listModel.addElement(ca);
listModel.addElement(de);
listModel.addElement(fr);
listModel.addElement(gb);
listModel.addElement(jp);
//create the list
JList<Country> countryList = new JList<>(listModel);
add(new JScrollPane(countryList));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("JList Renderer Example");
this.setSize(200, 200);
this.setLocationRelativeTo(null);
this.setVisible(true);
countryList.setCellRenderer(new CountryRenderer());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new JListCustomRendererExample();
}
});
}
}
編輯
我嘗試了@Gilbert le blanc 的回答,但我仍然有問題,我嘗試向這個 label 添加新元素,就像一個按鈕,我希望這些按鈕上有與國家行名稱相同的文本在。 示例:在美國行,我希望按鈕上有“美國”。
所以我在public Component getListCellRendererComponent
中添加了這 4 行:
label.setLayout(null);
JButton test = new JButton(country.getName());
test.setBounds(10,10,50,50);
label.add(test);
我得到了這個:
這不是預期的結果,這與我在第一個問題中遇到的問題有點相同,你知道為什么嗎? 有解決辦法嗎?
Oracle 有一個有用的教程,使用 Swing 創建 GUI 。 跳過 Netbeans 部分。
事實證明,您不能使用JPanel
來保存JList
選擇。 您必須使用JLabel
。
因此,我設計了一個略有不同的 GUI。 我從您使用的教程中復制了圖標。 這些圖標位於源代碼 zip 文件中。
我做的第一件不同的事情是將圖像添加到Country
class。我還將所有 class 字段設為最終字段,因為它們不會改變。
public class Country {
private final Image image;
private final String name;
private final String code;
public Country(String name, String code) {
this.name = name;
this.code = code;
this.image = getImage(code);
}
private Image getImage(String code) {
Image image = null;
try {
URL url = getClass().getResource("/images/" + code + ".png");
image = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
public String getName() {
return name;
}
public String getCode() {
return code;
}
public Image getImage() {
return image;
}
@Override
public String toString() {
return name;
}
}
接下來,我創建了一個CountryModel
class 來保存ListModel
。
public class CountryModel {
private final DefaultListModel<Country> listModel;
public CountryModel() {
Country us = new Country("USA", "us");
Country in = new Country("India", "in");
Country vn = new Country("Vietnam", "vn");
Country ca = new Country("Canada", "ca");
Country de = new Country("Denmark", "de");
Country fr = new Country("France", "fr");
Country gb = new Country("Great Britain", "gb");
Country jp = new Country("Japan", "jp");
// create the model and add elements
listModel = new DefaultListModel<>();
listModel.addElement(us);
listModel.addElement(in);
listModel.addElement(vn);
listModel.addElement(ca);
listModel.addElement(de);
listModel.addElement(fr);
listModel.addElement(gb);
listModel.addElement(jp);
}
public DefaultListModel<Country> getListModel() {
return listModel;
}
}
這簡化了JListCustomRendererExample
視圖 class。我創建國家 model,創建JFrame
,創建JList
JPanel
和JButton
JPanel
。
為JFrame
和JPanels
創建單獨的方法有助於將相似的代碼保持在一起,將不同的代碼分離到方法中。 這使得代碼更易於閱讀和修改。
JButton
JPanel
允許您創建將處理JList
選擇或選擇的ActionListener
。
public class JListCustomRendererExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new JListCustomRendererExample());
}
private final CountryModel model;
public JListCustomRendererExample() {
this.model = new CountryModel();
}
@Override
public void run() {
JFrame frame = new JFrame("JList Renderer Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(model), BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createMainPanel(CountryModel model) {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JList<Country> countryList = new JList<>(model.getListModel());
countryList.setCellRenderer(new CountryRenderer());
panel.add(new JScrollPane(countryList), BorderLayout.CENTER);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton button = new JButton("Select Countries");
panel.add(button, BorderLayout.CENTER);
return panel;
}
}
最后,我們有ListCellRenderer
class。
public class CountryRenderer implements ListCellRenderer<Country> {
private final JLabel label;
public CountryRenderer() {
this.label = new JLabel();
label.setOpaque(true);
}
@Override
public Component getListCellRendererComponent(JList<? extends Country> list,
Country country, int index, boolean isSelected, boolean cellHasFocus) {
label.setIcon(new ImageIcon(country.getImage()));
label.setText(country.getName());
if (isSelected) {
label.setBackground(list.getSelectionBackground());
label.setForeground(list.getSelectionForeground());
} else {
label.setBackground(list.getBackground());
label.setForeground(list.getForeground());
}
return label;
}
}
這是完整的可運行代碼。 我制作了額外的類內部類,這樣我就可以將代碼作為一個塊發布。
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Image;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
public class JListCustomRendererExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new JListCustomRendererExample());
}
private final CountryModel model;
public JListCustomRendererExample() {
this.model = new CountryModel();
}
@Override
public void run() {
JFrame frame = new JFrame("JList Renderer Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(model), BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createMainPanel(CountryModel model) {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JList<Country> countryList = new JList<>(model.getListModel());
countryList.setCellRenderer(new CountryRenderer());
panel.add(new JScrollPane(countryList), BorderLayout.CENTER);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton button = new JButton("Select Countries");
panel.add(button, BorderLayout.CENTER);
return panel;
}
public class CountryRenderer implements ListCellRenderer<Country> {
private final JLabel label;
public CountryRenderer() {
this.label = new JLabel();
label.setOpaque(true);
}
@Override
public Component getListCellRendererComponent(JList<? extends Country> list,
Country country, int index, boolean isSelected, boolean cellHasFocus) {
label.setIcon(new ImageIcon(country.getImage()));
label.setText(country.getName());
if (isSelected) {
label.setBackground(list.getSelectionBackground());
label.setForeground(list.getSelectionForeground());
} else {
label.setBackground(list.getBackground());
label.setForeground(list.getForeground());
}
return label;
}
}
public class CountryModel {
private final DefaultListModel<Country> listModel;
public CountryModel() {
Country us = new Country("USA", "us");
Country in = new Country("India", "in");
Country vn = new Country("Vietnam", "vn");
Country ca = new Country("Canada", "ca");
Country de = new Country("Denmark", "de");
Country fr = new Country("France", "fr");
Country gb = new Country("Great Britain", "gb");
Country jp = new Country("Japan", "jp");
// create the model and add elements
listModel = new DefaultListModel<>();
listModel.addElement(us);
listModel.addElement(in);
listModel.addElement(vn);
listModel.addElement(ca);
listModel.addElement(de);
listModel.addElement(fr);
listModel.addElement(gb);
listModel.addElement(jp);
}
public DefaultListModel<Country> getListModel() {
return listModel;
}
}
public class Country {
private final Image image;
private final String name;
private final String code;
public Country(String name, String code) {
this.name = name;
this.code = code;
this.image = getImage(code);
}
private Image getImage(String code) {
Image image = null;
try {
URL url = getClass().getResource("/images/" + code + ".png");
image = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
public String getName() {
return name;
}
public String getCode() {
return code;
}
public Image getImage() {
return image;
}
@Override
public String toString() {
return name;
}
}
}
好吧,我設法通過創建一個帶有偵聽器的 JPanel 來解決自己的問題,因此它就像一個 JList,但我可以將我想要的 object 放入其中,這樣它甚至可以更好地工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.