【问题标题】:Add behavior to a default JTable cell renderer将行为添加到默认的 JTable 单元格渲染器
【发布时间】:2018-03-05 13:12:55
【问题描述】:

如果我使用以下内容来显示 JTable:

package jtable.fontsize;
import java.awt.BorderLayout;
import java.awt.Font;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

import rcutil.swing.table.LastColumnChangesWidthJTable;


public class JTableCellPlay extends JFrame
{
  public JTableCellPlay()
  {
    super("setting Table font size");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public static void main(String ... arguments) throws InvocationTargetException, InterruptedException
  {
    JTableCellPlay mainScreen = new JTableCellPlay();
    mainScreen.go();
  }

  public void go() throws InvocationTargetException, InterruptedException
  {
    SwingUtilities.invokeAndWait(new Runnable() { public void run() { createScreen(); } } );
    setVisible(true);
  }

  public void createScreen()
  {
    LastColumnChangesWidthJTable aLittleJTable = new LastColumnChangesWidthJTable(new LittleTableModel());
    aLittleJTable.setDefaultRenderer(Integer.class, new IntegerCellRenderer());
    JScrollPane scrollPane = new JScrollPane(aLittleJTable);
    add(scrollPane, BorderLayout.CENTER);
    pack();
  }
}

使用以下渲染器:

package jtable.fontsize;

import java.awt.Color;
import java.awt.Component;

import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;


public class IntegerCellRenderer extends JLabel implements TableCellRenderer
{
  @Override
  public Component getTableCellRendererComponent
                      (JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
  {
    String resultString = String.format("~%d~", (Integer)value);
    setText(resultString);
    setHorizontalAlignment(JLabel.CENTER);
//    if (isSelected) 
//    { 
//      setOpaque(true);  // evidently necessary for JLabel as a component in a JTable cell
//      setBackground(Color.GRAY);
//    }
    return this;
  }
}

以及以下模型(这样您的代码才能运行,是的,我知道还有其他方法可以做到这一点):

package jtable.fontsize;

import javax.swing.table.AbstractTableModel;

public class LittleTableModel extends AbstractTableModel
{
  public Class<? extends Object> getColumnClass(int column)
  {
    Class<? extends Object> c = null;
    switch (column)
    {
    case 0: c = String.class; break;
    case 1: c = Integer.class; break;
    case 2: c = String.class; break;
    }
    return c;
  }

  String[] columnNames = { "first", "second", "third" };
  Object[][] data = { { "one", 2, "three" }, { "four", 5, "six" } };

  public int getColumnCount() { return 3; }
  public int getRowCount() { return 2; }
  public String getColumnName(int index) { return columnNames[index]; }

  public Object getValueAt(int row, int column)
  {
    Object result = data[row][column];
    return result;
  }
}

然后,当我选择其中一行时,两个字符串列会获得选择突出显示,但“整数”列不会。

如果我注释掉设置“整数”渲染器的行,则单击一行会按预期选择整行。

我知道我可以使用渲染器中注释掉的行来突出显示单元格,添加 setOpaque(true) 和 setBackground(Color) 甚至玩游戏来正确选择和未选择的背景颜色,但我怀疑有以某种方式使用最初用于此类事情的相同渲染器,只需使用我的渲染器中的代码来完成我需要做的特殊事情。有人能解释一下它是如何工作的吗?

【问题讨论】:

标签: java swing jtable tablecellrenderer


【解决方案1】:

为什么不简单地为您的渲染器提供一个 else 块,您可以在其中撤消在 if 块中所做的更改?

if (isSelected) {
    setOpaque(true); 
    setBackground(Color.GRAY);
} else {
    setOpaque(false); // allow underlying color to show
    setBackground(null); // no color added
}

或者另一种选择是让您的渲染器类扩展 DefaultTableCellRenderer 而不是实现 TableCellRenderer,从而允许您使用默认渲染器的先天突出显示功能:

@SuppressWarnings("serial")
class IntegerCellRenderer2 extends DefaultTableCellRenderer {
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
            int row, int column) {
        String resultString = String.format("~%d~", (Integer) value);
        setText(resultString);
        setHorizontalAlignment(JLabel.CENTER);
        return super.getTableCellRendererComponent(table, resultString, isSelected, hasFocus, row, column);
    }
}

请注意,您可以在其构造函数中设置渲染器的一些属性。例如:

@SuppressWarnings("serial")
class IntegerCellRenderer2 extends DefaultTableCellRenderer {
    public IntegerCellRenderer2() {
        setHorizontalAlignment(JLabel.CENTER);
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
            int row, int column) {
        String resultString = String.format("~%d~", (Integer) value);
        setText(resultString);
        // setHorizontalAlignment(JLabel.CENTER);
        return super.getTableCellRendererComponent(table, resultString, isSelected, hasFocus, row, column);
    }
}

【讨论】:

  • 好吧,我不知道不透明的设置和背景是什么,先验的,就像我知道选择颜色是灰色一样。正如我所说,我知道我可以打电话找出那些是什么,但我想知道更好的方法。您的第二种方法似乎有效,但对我来说似乎很狡猾 - 如果默认渲染器设置对齐怎么办?我不喜欢在我的类中有依赖于其超类内部的代码。
  • @arcy:究竟你想做什么?
  • @arcy;如果你使用默认渲染器,你可以很容易地查询超级组件的背景状态和不透明属性状态,但同样,你最终想用这个做什么?
  • 我正在尝试使用默认渲染器的默认行为,而不是尝试复制它。
  • @arcy,如果您只是创建自定义渲染器来格式化数据,那么覆盖默认渲染器的 setValue(...) 方法会更容易,如 Using Custom Renderers 上的 Swing 教程中所示。如果你想变得更漂亮,你可以创建一个可重用的渲染器,它接受 Formatter 作为参数,如Table Format Renderers 中所示
猜你喜欢
  • 2011-10-02
  • 2013-02-10
  • 2013-11-13
  • 2014-06-26
  • 2014-03-08
  • 1970-01-01
  • 2014-06-27
  • 1970-01-01
  • 2018-04-19
相关资源
最近更新 更多