【问题标题】:How to properly use TableCellRenderer to color matching cells如何正确使用 TableCellRenderer 对单元格进行颜色匹配
【发布时间】:2019-10-20 07:12:17
【问题描述】:

我正在开发一个从文件中读取数据并将其放入 jTable 的程序。 根据数据我计算BMI。

并且知道我正在尝试实现 TableCellRenderer 来为 BMI 列中的单元格着色。 Color.RED - 当 BMI > 25 Color.Yellow - 当 BMI

这是我的 Renderer,它是 Frame 的内部类:

public class BMIRenderer extends JPanel implements TableCellRenderer {

        public BMIRenderer() {
            super.setOpaque(true);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {

            Person p = (Person) value;

            if (p.getBMI() < 18) {
                super.setBackground(Color.YELLOW);
            } else if (p.getBMI() > 25) {
                setBackground(Color.RED);
            }

            return this;
        }
    }

为 jTable 添加渲染器:

mainTable.setDefaultRenderer(Person.class, new BMIRenderer());

Aaand 什么也没发生,我正在尝试扩展 DefaultTableCellRenderer 的不同方法,但您可以猜到输出是相同的。我想我在这段代码的语法中遗漏了一些东西。

这是框架的代码:

public class Frame extends JFrame {

    MyTableModel tableModel = new MyTableModel();
    JTable mainTable = new JTable();
    JPanel jPanel;
    JScrollPane scrollPane = new JScrollPane(mainTable);

    public Frame() throws ParseException, FileNotFoundException {
        this.setSize(new Dimension(500, 150));
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);

        mainTable.setDefaultRenderer(Person.class, new BMIRenderer());

        mainTable.setModel(tableModel);
        scrollPane.setVisible(true);

        jPanel = new JPanel(new BorderLayout());
        jPanel.setBorder(BorderFactory.createLineBorder(Color.black));
        jPanel.add(scrollPane, BorderLayout.CENTER);
        // this.pack();
        this.add(jPanel);

    public class BMIRenderer extends JLabel implements TableCellRenderer {

        public BMIRenderer() {
            super.setOpaque(true);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {

            Person p = (Person) value;

            if (p.getBMI() < 15) {
                super.setBackground(Color.YELLOW);
            } else if (p.getBMI() > 25) {
                setBackground(Color.RED);
            }

            return this;
        }
    }


    }

MyTableModel 类代码:

public class MyTableModel extends AbstractTableModel {

    ArrayList<Person> dataList;

    String imie, nazwisko;  //name, surname
    Color kolor;
    Integer wzrostCm, wagaKg; //weight, height
    Calendar cal;
    Person p;

    int BMI;
    int r, g, b;

    public MyTableModel() throws FileNotFoundException, ParseException {
        dataList = new ArrayList<Person>();

        Scanner read = new Scanner(new File("C:\\Users\\ziole\\EclipseWorkspace\\GUI_z07P_DOING\\src\\tabelka.txt"));

        String pattern = "yyyy-MM-dd";
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);

        System.out.println("Wczytany plik:");
        while (read.hasNext()) {
            cal = Calendar.getInstance();
            String newLine = read.nextLine();
            String[] elements = newLine.split(" ");

            System.out.println(newLine);

            imie = elements[0];
            nazwisko = elements[1];

            Date date = simpleDateFormat.parse(elements[2]);
            cal.setTime(date);

            String[] RGB = elements[3].split(",");
            r = Integer.parseInt(RGB[0]);
            g = Integer.parseInt(RGB[1]);
            b = Integer.parseInt(RGB[2]);
            kolor = new Color(r, g, b);

            wzrostCm = new Integer(elements[4]);
            wagaKg = new Integer(elements[5]);

            BMI = bmi(wagaKg, wzrostCm);

            dataList.add(new Person(imie, nazwisko, kolor, wzrostCm, wagaKg, cal, BMI));
        }

    }

    @Override
    public int getColumnCount() {
        return 7;
    }

    @Override
    public int getRowCount() {
        return dataList.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {

        p = dataList.get(rowIndex);

        switch (columnIndex) {
        case 0:
            return p.imie;
        case 1:
            return p.nazwisko;
        case 2:
            return data(cal, p);
        case 3:
            return p.kolor.getRGB();
        case 4:
            return p.wzrostCm;
        case 5:
            return p.wagaKg;
        case 6:
            return p.BMI;

        }

        return null;
    }

    @Override
    public String getColumnName(int column) {
        switch (column) {
        case 0:
            return "Imie";
        case 1:
            return "Nazwisko";
        case 2:
            return "data";
        case 3:
            return "Kolor";
        case 4:
            return "Wzrost[cm]";
        case 5:
            return "Waga[kg]";
        case 6:
            return "BMI";
        }
        return null;
    }

    public String data(Calendar cal, Person p) {
        // po Galicyjsku
        switch (p.cal.get(cal.MONTH)) {
        case 0:
            return "xaneiro";
        case 1:
            return "febreiro";
        case 2:
            return "marzo";
        case 3:
            return "abril";
        case 4:
            return "maio";
        case 5:
            return "xuño";
        case 6:
            return "xullo";
        case 7:
            return "agosto";
        case 8:
            return "setembro";
        case 9:
            return "outubro";
        case 10:
            return "novembro";
        case 11:
            return "decembro";

        default:
            break;
        }
        return null;

    }

    public int bmi(Integer waga, Integer wzrostCm) {

        double wzrostKwadrat = (int) Math.pow(wzrostCm, 2);
        double wynik = Math.round(((waga / wzrostKwadrat) * 10000));
        return (int) wynik;

    }


}

还有Person类:

public class Person {

    String imie, nazwisko;
    Color kolor;
    int r, g, b;
    Integer wzrostCm, wagaKg;
    Calendar cal;
    int BMI;

    public Person(String imie, String nazwisko, Color kolor, Integer wzrostCm, Integer wagaKg, Calendar cal, int BMI) {
        this.imie = imie;
        this.nazwisko = nazwisko;
        this.kolor = kolor;
        this.wzrostCm = wzrostCm;
        this.wagaKg = wagaKg;
        this.cal = cal;
        this.BMI = BMI;
    }
*here are simple getters and setters*
}

我从中读取的文件:

Jan Kowalski 1980-2-7 255,0,153 182 99
Michał Nowak 1988-8-13 0,0,153 177 73
Zofia Michalska 1971-6-12 255,0,51 162 53
Łukasz Gwózdz 1975-3-23 0,0,255 178 47
Tomasz Wójcik 1965-1-7 102,0,0 180 50
Beata Szczesniak 2000-8-28 51,102,0 160 70
Anna Pekala 1979-2-17 0,204,255 164 54
Robert Tarski 1971-11-2 255,102,0 176 70

在 Main 我只是创建 Frame's 对象。

【问题讨论】:

  • 你能把它变成SSCE吗?
  • 你为什么使用JPanel而不是JLabel?你可以试试public class BMIRenderer extends JLabel implements TableCellRenderer { 吗?你也可以只扩展DefaultTableCellRenderer 或不?可能更简单?
  • 好的,我把它切换到 jLabel 我应该在哪里看到区别?
  • 这只是一个建议。我必须先运行你的代码,看看发生了什么
  • 您将 BIRenderer 附加到 Person 类型的每一列 - 但实际上您的列都不是 Person 类型的...

标签: java swing jtable


【解决方案1】:

修改您的渲染器以扩展 DefaultTableCellRenderer,覆盖 getTableCellRendererComponent() 方法:

import javax.swing.table.DefaultTableCellRenderer;

public class BMIRenderer extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

        Person person = null;
        String bmiValue = "";
        if(value instanceof Person) {
            person = (Person)value;
            bmiValue = Integer.toString(person.getBMI());
        }

        //Pass just the bmiValue to the super method so the integer's toString() value is displayed
        super.getTableCellRendererComponent(table, bmiValue, isSelected, hasFocus, row, column);

        if(person != null) {
            if (person.getBMI() < 18) {
                super.setBackground(Color.YELLOW);
            } 
            else if (person.getBMI() > 25) {
                setBackground(Color.RED);
            }
        }

        return this;
    }
}

现在,修改您的表模型,使其返回第 6 列的整个 Person 对象,而不是 BMI 字段的 int 值:

@Override
public Object getValueAt(int rowIndex, int columnIndex) {

    Person person = dataList.get(rowIndex);

    switch (columnIndex) {
        case 0:
            return person.imie;
        case 1:
            return person.nazwisko;
        case 2:
            return data(cal, person);
        case 3:
            return person.kolor.getRGB();
        case 4:
            return person.wzrostCm;
        case 5:
            return person.wagaKg;
        case 6:
            //Return the entire Person object so that the column class matches to our custom cell renderer
            return person;

    }

    return null;
}

在您的 MyTableModel 类中,重写 getColumnClass() 方法,如下所示:

@Override
public Class<?> getColumnClass(int columnIndex) {
    switch (columnIndex) {
        case 0:
            return String.class;
        case 1:
            return String.class;
        case 2:
            return String.class;
        case 3:
            return Integer.class;
        case 4:
            return Integer.class;
        case 5:
            return Integer.class;
        case 6:
            return Person.class;

    }
    return Object.class;
}

【讨论】:

  • 我应该以哪种方式退货?简单的“return p”给了我人的哈希码
  • 好的,我更改 mainTable.setDefaultRenderer(Person.class, new BIRenderer());到 Object.class 并知道一切(我的意思是整个 jTable)是 .red 和 .yellow :/
  • @Mikosz 如果你得到了 person 的哈希码,那是因为你的 Person 类没有覆盖 toString() 并且你的自定义渲染器没有用来渲染这个值。我编码渲染器的方式,它应该只用于 BMI 列 #6。
  • 哦,那我应该覆盖它吗?比如:@Override public String toString() { return BMI; }
  • @Mikosz 在您的 JFrame 构造函数中,在调用 mainTable.setModel() 后尝试调用 mainTable.setDefaultRenderer() 因为我感觉在渲染器之后设置模型会导致渲染器被替换为默认渲染器,而不是您创建的渲染器。
猜你喜欢
  • 2011-08-13
  • 2018-06-02
  • 2021-07-08
  • 2020-01-05
  • 2010-09-24
  • 2016-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多