如何让 JLabel 在运行时 JTable 列交换后仍然出现?

How to make JLabel still appear after JTable column swap in the runtime?

我有一个 JTable:

不幸的是,在我交换列之后,标志不再呈现:

我认为这是我的 getColumnClass 方法的错误,我已经为每一列修复了 class,但我不知道如何解决这个问题。

package zad1;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Arrays;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

public class CountryTable extends JTable {




    public CountryTable(String countriesFileName) {
        Vector<String> columnNames = new Vector<String>();
        Vector<Vector<Object>> data = new Vector<Vector<Object>>();
        try {
            BufferedReader br = new BufferedReader(new FileReader(countriesFileName));
            columnNames.addAll(Arrays.asList(br.readLine().split("\t")));
            System.out.println(columnNames);
            String line;
            while ((line = br.readLine()) != null) {
                String[] attributes = line.split("\t");
                Vector<Object> rowData = new Vector<Object>();
                rowData.add(attributes[0]);
                rowData.add(attributes[1]);
                rowData.add(Long.valueOf(attributes[2]));
                BufferedImage icon = ImageIO.read(new File("./data/" + attributes[3]));
                double ratio = (double) icon.getWidth() / icon.getHeight();
                rowData.add(new ImageIcon(icon.getScaledInstance(30, 20, Image.SCALE_FAST)));
                data.add(rowData);
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        setModel(new MyTableModel(data, columnNames));
        setRowHeight(30);
        getColumnModel().getColumn(2).setCellRenderer(new PopulationCellRenderer());
        for (int i = 0; i < getColumnCount(); i++) {
            getColumnModel().getColumn(i).setWidth(400);
        }
    }

    @Override
    public Class getColumnClass(int column) {
        switch (column) {
        case 0:
            return String.class;// Panstwo
        case 1:
            return String.class;// stolica
        case 2:
            return Long.class;// ludnosc
        case 3:
            return Icon.class; // flaga jakiej klasy jest dana komorka w danej kolumnie aby tabela ja poprawnie wyswietlila
        default:
            return String.class;
        }
    }


    class MyTableModel extends DefaultTableModel {
        public MyTableModel(Vector<Vector<Object>> data, Vector<String> columnNames) {
            super(data, columnNames);//wywolanie konstruktora z nadklasy
            System.out.println(columnNames);
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return column == 3;
        }
    }

    class PopulationCellRenderer extends JLabel implements TableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            Long population = (Long) value;
            setHorizontalAlignment(JLabel.RIGHT);
            if (population > 20000000) {
                setForeground(Color.red);
            } else {
                setForeground(Color.BLACK);
            }
            setText(population + "");
            return this;
        }

    }
}

不需要为此扩展 JTable。您的示例在 视图 中覆盖了 getColumnClass(),而在 模型 中应该这样做。 Icon.classdefault renderer 将应用于列移动的任何位置。

private final TableModel model = new DefaultTableModel(data, columnNames) {

    @Override
    public Class<?> getColumnClass(int column) {
        switch (column) {
             …
        }
    }
};

这也使得在每种类型的基础上应用 PopulationCellRenderer 成为可能:

table.setDefaultRenderer(Long.class, new PopulationRenderer());

还考虑扩展 DefaultTableCellRenderer,如 @mKorbel here, using a NumberFormat, as shown below. Based on an example 所示,下面的独立代码显示了更正的 TableModel 和更新的 TableCellRenderer.

import java.awt.*;
import java.text.NumberFormat;
import javax.swing.*;
import javax.swing.table.*;

public class TableExample {

    private static final long CUSP = 20000000;
    private JFrame frame = new JFrame("Table Demo");
    private Icon errorIcon = (Icon) UIManager.getIcon("OptionPane.errorIcon");
    private Icon infoIcon = (Icon) UIManager.getIcon("OptionPane.informationIcon");
    private Icon warnIcon = (Icon) UIManager.getIcon("OptionPane.warningIcon");
    private String[] columnNames = {"String", "Long", "Float", "Double", "Boolean", "Icon"};
    private Object[][] data = {
        {"aaa", CUSP - 1, 12.15F, 100.05, true, (errorIcon)},
        {"bbb", CUSP, 7.154F, 6.1555, false, (infoIcon)},
        {"ccc", CUSP + 1, 0.1135F, 3.1455, true, (warnIcon)},
        {"ddd", 42L, 31.15F, 10.05, true, (errorIcon)},
        {"eee", 12345L, 5.154F, 16.1555, false, (infoIcon)},
        {"fff", 54321L, 4.1135F, 31.1455, true, (warnIcon)}};
    private final TableModel model = new DefaultTableModel(data, columnNames) {

        @Override
        public Class<?> getColumnClass(int column) {
            switch (column) {
                case 0:
                    return String.class;
                case 1:
                    return Long.class;
                case 2:
                    return Float.class;
                case 3:
                    return Double.class;
                case 4:
                    return Boolean.class;
                case 5:
                    return Icon.class;
                default:
                    return String.class;
            }
        }
    };
    private final JTable table = new JTable(model);

    private static class PopulationRenderer extends DefaultTableCellRenderer {

        NumberFormat f = NumberFormat.getInstance();

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int col) {
            JLabel r = (JLabel) super.getTableCellRendererComponent(
                table, value, isSelected, hasFocus, row, col);
            if (col == 1) {
                r.setHorizontalAlignment(JLabel.RIGHT);
                Long population = (Long) value;
                if (population > CUSP) {
                    r.setForeground(Color.red);
                } else {
                    r.setForeground(Color.BLACK);
                }
                r.setText(f.format(population));
            }
            return r;
        }
    }

    public TableExample() {
        int h = infoIcon.getIconHeight();
        table.setRowHeight(h);
        table.setPreferredScrollableViewportSize(
            new Dimension(table.getPreferredSize().width, 4 * h));
        table.setAutoCreateRowSorter(true);
        table.setDefaultRenderer(Long.class, new PopulationRenderer());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new JScrollPane(table));
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            TableExample tableExample = new TableExample();
        });
    }
}