在论坛搜索了相当多的相关主题,发现大部分实现的都是整列的设置渲染方式!
即指定渲染可以自己创建相关的方法,主要是继承DefaultTableCellRenderer,虽然这里可以实现单个Component的渲染!
但在调用时,90%以上是使用table.getColumnModel().getColumn(列索引参数).setCellRenderer(自定义渲染器),这里面有个重要的缺陷,就是唯独没有对row的位置实现获取,故此请大家指点下,有没有好的办法实现?!我想这个的实现会有相当的意义!

解决方案 »

  1.   

    此回复为自动发出,仅用于显示而已,并无任何其他特殊作用
    楼主【adown】截止到2008-06-25 17:33:48的历史汇总数据(不包括此帖):
    发帖数:3                  发帖分:70                 
    结贴数:3                  结贴分:70                 
    未结数:0                  未结分:0                  
    结贴率:100.00%            结分率:100.00%            
    敬礼!
      

  2.   

    LZ说的对,大多数情况下我们都是直接继承DefaultTableCellRenderer类来实现渲染。在继承DefaultTableCellRenderer类的时候一般会重载一个叫getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)的方法。而渲染的实现过程就是在这个类里面实现的。
    从这个方法的参数可以看出,它是一个一个cell来渲染的,因此如果要实现行渲染理论上是可以的。我就不贴具体的代码了,LZ可以对row这个参数进行控制,应该就可以达到效果了。另外对于不需要渲染的cell,记住一定要在这个方法里也处理,不然会全部渲染上的!!
      

  3.   

    还是给你贴一段吧,刚写的,可以实现package zxj.client;import java.awt.Color;
    import java.awt.Component;
    import java.awt.GridLayout;import javax.swing.JPanel;
    import javax.swing.JTable;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.DefaultTableModel;public class TablePanel extends JPanel {
    JTable table = null;
    MyTableModel model = null;
    public TablePanel(){
    ininUI();
    }

    private void ininUI(){
    String[] clmnNames = {"aa","bb","cc"};
    model = new MyTableModel(clmnNames);
    table = new JTable(model);
    table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);

    model.addRow(new Object[]{"1","2","3"});
    model.addRow(new Object[]{"11","22","33"});
    model.addRow(new Object[]{"111","222","333"});

    table.getColumnModel().getColumn(0).setCellRenderer(new MuRender());
    table.getColumnModel().getColumn(1).setCellRenderer(new MuRender());
    table.getColumnModel().getColumn(2).setCellRenderer(new MuRender());
    setLayout(new GridLayout(1,1));
    add(table);
    }

    public class MuRender extends DefaultTableCellRenderer{
    public  Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
    {
    setText((String)value);
    if (row % 2 == 1) {
    setBackground(Color.RED);
    } else {
    setBackground(null);
    }
    return this;
    }

    public class MyTableModel extends DefaultTableModel {
    public MyTableModel(String[] clmnNames){
    super(clmnNames,0);
    }

    public boolean isCellEditable(int row, int column){
    return false;
    } }
    }
      

  4.   

    感谢luorigufeng的回复! 我在jtable中实现自定义渲染方式的目的:主要是为了做个输入的数据格式匹配检测! 
    合乎要求的使用默认的Renderer. 不符合的就带红色底显示!受到3楼的启示,我也创建了一个ColoredCellFieldRenderer,并且使用传参方式构造类package commonModel;import java.awt.Color;
    import java.awt.Component;
    import javax.swing.JTable;
    import javax.swing.JTextField;
    import javax.swing.table.TableCellRenderer;public class ColoredCellFieldRenderer extends JTextField implements TableCellRenderer
    {
    private int newRow,newColumn;
    public ColoredCellFieldRenderer(){}
    public ColoredCellFieldRenderer(int row, int column)
    {
    newRow = row;
    newColumn = column;
    }
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

    if(row ==newRow && column == newColumn)
    {
    setBackground(Color.RED);
    }else
    {
    setBackground(null);
    }
    setText((value == null) ? "" : value.toString());
    return this;
    }
    }但是在循环检测数据格式是否匹配时,发现它由于获取的是整列的model进行渲染的,在有多行同列的数据上出现错误的话,它会覆盖渲染,结果就会是每列有错的最后一个单元格被使用到改颜色,同列的上层有错数据不会改! 我个人认为根本的症结还是在于它使用的是整列的渲染模式所产生的! 有什么办法可以解决吗? 
      

  5.   

    需要自己处理的自己处理,不需要的调用super的getTableCellRendererComponent方法
    table代码class TestTable extends JTable {
            //key为需要处理单元格的flag
            private List<key> specialCellList = new ArrayList<key>();        {
                specialCellList.add(key1);
                specialCellList.add(key2);
            }
            public List<key> getSpecialCellList() {
                return specialCellList;
            }
        }
    renderer代码public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            
            if(table instanceof TestTable){
                TestTable t = (TestTable)table;
                if(t.getSpecialCellList().contains(key)){
                    // paint yourself
                    return paintComponent;
                }
            }
            return super.getTableCellRendererComponent();
        }
      

  6.   

    根据zwgs1985的思路是的确可以实现简单的table的整体render!
    可是在同一个table内,假如本身根据数据结构,还实现了其它的render,例如,带button,boolean的等等,由于是一
    次性的渲染,结果就把其它的render方式给覆盖了! 这是个相当棘手的问题. 看样子问题又回到了起点! 不知道还
    有没有其它好的解决办法?!
      

  7.   

    是这样的! 我的jtable是和数据库衔接的, 动态获取数据类型,假如是image的,就imageButton渲染,假如是date类型,就databutton渲染,假如是String类型,就jtextarea渲染!
      

  8.   

    有点麻烦,你就先把数据埴进去,然后再更改每个columnModule吧
      

  9.   

    如果不给table特别设置renderer的话,那么table的所有单元格用的都是同一个renderer
    如果设置了,那么就用不同的
    JTable的源代码:public TableCellRenderer getCellRenderer(int row, int column) {
            TableColumn tableColumn = getColumnModel().getColumn(column);
            TableCellRenderer renderer = tableColumn.getCellRenderer();
            if (renderer == null) {
                renderer = getDefaultRenderer(getColumnClass(column));
            }
            return renderer;
        }
    这样的话,只要你特别设置了renderer(甚至可以给每个单元格设置不同的renderer),那么在刷新的时候就会调用自己设置renderer的刷新方法;
    这样在prepareRenderer中,调用方法getTableCellRendererComponent方法之前,可以为renderer刷新做准备,在调用getTableCellRendererComponent方法的时候调用设置的属性进行刷新;
    注意,在每次刷新的时候都要进行设置,因为用到同类型renderer的一类单元格用的是同一个renderer,如果不重新设置,那么以后的单元格在刷新时都会用到以前单元格设置过的属性不知道能不能明白
      

  10.   

    感谢 zwgs1985 的指点,public TableCellRenderer getCellRenderer(int row, int column)这方法我也看过源代码! 还是不太明白你所说的设置顺序!可否用伪代码简单的表示出来! 谢谢!
      

  11.   

    也不知道是不是你想要得
    我在各个renderer中把颜色写死了,你可以在prepareRenderer方法中判断是什么renderer,在各个renderer中提供get,set方法,这样,在各个renderer的getTableCellRendererComponent中读取你在renderer设置的属性,进行刷新显示
    import java.awt.Color;
    import java.awt.Component;import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.UIManager;
    import javax.swing.border.Border;
    import javax.swing.border.EmptyBorder;
    import javax.swing.plaf.UIResource;
    import javax.swing.table.AbstractTableModel;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.TableCellRenderer;
    import javax.swing.table.TableModel;public class TableRendererTest extends JFrame {    public TableRendererTest() {
            TableModel dataModel = new AbstractTableModel() {
                public int getColumnCount() {
                    return 10;
                }            public int getRowCount() {
                    return 10;
                }            public Object getValueAt(int row, int col) {
                    if (row == 0 && col == 0) {
                        return Boolean.TRUE;
                    }
                    return new Integer(row * col);
                }
            };
            JTable table = new TestTable(dataModel);
            JScrollPane scrollpane = new JScrollPane(table);
            this.getContentPane().add(scrollpane);
        }    /**
         * @param args
         */
        public static void main(String[] args) {
            TableRendererTest jt = new TableRendererTest();
            jt.setVisible(true);
            jt.setSize(300, 200);
            jt.setDefaultCloseOperation(EXIT_ON_CLOSE);
        }    private class TestTable extends JTable {        public TestTable(TableModel dataModel) {
                super(dataModel);
            }        @Override
            public TableCellRenderer getCellRenderer(int row, int column) {
                if (row == 0 && column == 0) {
                    return new BooleanRenderer();
                } else if (row == 1 && column == 1) {
                    return new NumberRenderer();
                }
                return super.getCellRenderer(row, column);
            }        @Override
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
                // TODO Auto-generated method stub
                return super.prepareRenderer(renderer, row, column);
            }
        }    static class BooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource {
            private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);        public BooleanRenderer() {
                super();
                setHorizontalAlignment(JLabel.CENTER);
                setBorderPainted(true);
            }        public Component getTableCellRendererComponent(JTable table,
                                                           Object value,
                                                           boolean isSelected,
                                                           boolean hasFocus,
                                                           int row,
                                                           int column) {
                if (isSelected) {
                    setForeground(Color.RED);
                    super.setBackground(Color.YELLOW);
                } else {
                    setForeground(Color.YELLOW);
                    setBackground(Color.RED);
                }
                setSelected((value != null && ((Boolean) value).booleanValue()));            if (hasFocus) {
                    setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
                } else {
                    setBorder(noFocusBorder);
                }            return this;
            }
        }    /**
         * Default Renderers
         */
        static class NumberRenderer extends DefaultTableCellRenderer.UIResource {
            public NumberRenderer() {
                super();
                setHorizontalAlignment(JLabel.RIGHT);
            }        public Component getTableCellRendererComponent(JTable table,
                                                           Object value,
                                                           boolean isSelected,
                                                           boolean hasFocus,
                                                           int row,
                                                           int column) {
                if (isSelected) {
                    setForeground(Color.BLUE);
                    super.setBackground(Color.GREEN);
                } else {
                    setForeground(Color.GREEN);
                    setBackground(Color.BLUE);
                }            setValue(value);            if (hasFocus) {
                    setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
                } else {
                    setBorder(noFocusBorder);
                }            return this;
            }
        }
    }
      

  12.   

    感谢zwgs1985的回复! 花了两天时间查考了其它的帖子,我在想有没有更好一点的办法,可以动态的设置渲染方式,例如这样:import java.awt.Component;
    import javax.swing.JTable;
    import javax.swing.table.TableCellRenderer;
    import javax.swing.table.TableModel;public class CustomTable extends JTable
    {
    public CustomTable(TableModel model)
    {
    super(model);
    }

    @Override
    public TableCellRenderer getCellRenderer(int row, int column) 
    {
    TableCellRenderer renderer = null;
    renderer = (TableCellRenderer)getValueAt(row, column);//?????
    if(null == renderer)
    {
    renderer = super.getCellRenderer(row, column);
    }
            return renderer;
        }

    @Override
    public Component prepareRenderer(TableCellRenderer renderer, int row, int column) 
    {
             return super.prepareRenderer(renderer, row, column);
        }
    }本想这样可以获得单个cell的渲染,可加载其他类编译时却抛出异常
    [code=Jave]
    Exception occurred during event dispatching:
    java.lang.ClassCastException: java.lang.String
    [/code]
    难道不可以这样写吗?
      

  13.   

    renderer = (TableCellRenderer)getValueAt(row, column);//?????
    怎么这么转?肯定会报ClassCastException
    getValueAt得到的是value,不是renderer
    可以实现一个单元格一个renderer,就是稍麻烦些
      

  14.   

    这是采纳参考"哭泣的小白菜"的文章,见http://www.xici.net/b616472/d38389338.htm,他是用个Hashtable来获取值,我想它这样可以,我的怎么就抛出异常!
      

  15.   

    那也要看他往propertyRenderers里put什么东西啊,他在里面装了一些renderer,这样从propertyRenderers里get就捕会报错了,要是直接调用table的getValueAt取得的是table的内容,是Object类型的,往TableCellRenderer转就会报错
      

  16.   

    感谢zwgs1985的回复! 仔细看过"哭泣的小白菜"的文章后,发现也不是动态的调用renderer!
    不知道这种方式是不是算获取了单个的cell的渲染器?public TableCellRenderer getCellRenderer(int row, int column) 
    {
        TableColumn tableColumn = getColumnModel().getColumn(column);
        TableCellRenderer renderer = tableColumn.getCellRenderer();
        if (renderer == null && getValueAt(row,column) != null) 
                {
          renderer = getDefaultRenderer(getValueAt(row,column).getClass());
        }
        if (renderer == null) 
                {
          renderer = getDefaultRenderer(getColumnClass(column));
        }
        return renderer;
    }我总是希望能动态的调用渲染器,而不是预先就指定好? 难道这种思路有问题? 
      

  17.   

     
    public   TableCellRenderer   getCellRenderer(int   row,   int   column)   

            TableColumn   tableColumn   =   getColumnModel().getColumn(column); 
            TableCellRenderer   renderer   =   tableColumn.getCellRenderer(); 
            if   (renderer   ==   null   &&   getValueAt(row,column)   !=   null)   
                            { 
                renderer   =   getDefaultRenderer(getValueAt(row,column).getClass()); 
            } 
            if   (renderer   ==   null)   
                            { 
                renderer   =   getDefaultRenderer(getColumnClass(column)); 
            } 
            return   renderer; 

     
    这段代码由问题,首先: 使用tableColumn.getCellRenderer();的话就注定一列的cell用同类型的renderer...
    又不清楚你想实现什么东西了
      

  18.   

    其实我要实现的咚咚想来也很简单! 
    在初始化table时,根据数据库提取的字段类型首次确定了渲染方式! 此渲染方式与颜色无关。目的是做个数据输入的面板。
    输入完成后,由预定义的数据检测方法进行数据格式检测,非法就改变目标cell的底色为红色!反之无变化!这是二次渲染!问题也就是出现在这里。数据是动态的,设置的渲染方式由于获取的是整列的cell,就出现同列cell,只匹配出最后的错误处改颜色,前面的被覆盖了!就是这么个问题?zwgs1985指点下!
      

  19.   

    好像问题一直在绕圈
    首先:table可以支持给每个cell设置渲染方式,但是你是以列为单位进行设置的,那么就只讨论以列为单位的情况
    之后:每列用的renderer是一个对象,这是毋庸置疑的,你出现的问题就是因为这个原因引起的
    那么,解决这个问题的方式,就是在renderer渲染的时候。
    TableCellRenderer中的getTableCellRendererComponent方法是管这事的
    那么看看DefaultTableCellRenderer的实现public Component getTableCellRendererComponent(JTable table, Object value,
                              boolean isSelected, boolean hasFocus, int row, int column) {        Color fg = null;
            Color bg = null;        JTable.DropLocation dropLocation = table.getDropLocation();
            if (dropLocation != null
                    && !dropLocation.isInsertRow()
                    && !dropLocation.isInsertColumn()
                    && dropLocation.getRow() == row
                    && dropLocation.getColumn() == column) {            fg = UIManager.getColor("Table.dropCellForeground");
                bg = UIManager.getColor("Table.dropCellBackground");            isSelected = true;
            }        if (isSelected) {
                super.setForeground(fg == null ? table.getSelectionForeground()
                                               : fg);
                super.setBackground(bg == null ? table.getSelectionBackground()
                                               : bg);
    } else {
                super.setForeground(unselectedForeground != null
                                        ? unselectedForeground
                                        : table.getForeground());
        super.setBackground(unselectedBackground != null
                                        ? unselectedBackground
                                        : table.getBackground());
    }
    setFont(table.getFont()); if (hasFocus) {
                Border border = null;
                if (isSelected) {
                    border = UIManager.getBorder("Table.focusSelectedCellHighlightBorder");
                }
                if (border == null) {
                    border = UIManager.getBorder("Table.focusCellHighlightBorder");
                }
                setBorder(border);     if (!isSelected && table.isCellEditable(row, column)) {
                    Color col;
                    col = UIManager.getColor("Table.focusCellForeground");
                    if (col != null) {
                        super.setForeground(col);
                    }
                    col = UIManager.getColor("Table.focusCellBackground");
                    if (col != null) {
                        super.setBackground(col);
                    }
        }
    } else {
                setBorder(getNoFocusBorder());
    }        setValue(value);  return this;
        }红色部分是设置显示颜色的,那么就需要该这部分代码,当你判断某个单元格输入错误(或者从DB中读取添加到table中)的时候(你可能能判断是哪个错了,可以得到rowIndex和columnIndex,也就是行列的索引),这样,在table刷新的时候(如果不知道什么时候table刷新,你可以在输入后获得显示DB值之后强制table刷新),就会重新渲染,就会掉到getTableCellRendererComponent方法,而且调用N次(次数与刷新区域的单元格数有关),这样,你在这个方法里判断,如果出错了,你自己设置前景色和背景色,如果没错,就把红色部分的代码写上,如果从DefaultTableCellRenderer继承,那么更省事了,直接调用super就可以了,这样就不会出现设置一个错误cell的背景色,整列都跟着变了。
    这个问题和怎么设置renderer(以列为单位设置还是以单元格进行设置)没有关系,只是和刷新有关系,即每个单元格要在什么时候显示什么样的前景色和背景色有关系,也就是改写getTableCellRendererComponent方法,一个单元(在你的代码里可能指的是一列)的单元格在刷新时走的是同一个方法,因为他们用的是同一个renderer,只是走的分支不同,走那个分支需要你自己控制。哎,罗嗦了,你自己看看吧,如果还是不懂,我也没办法啦 :)
      

  20.   

    ...晕了,没涂上红色,红色部分的代码指的是if (isSelected) {
                super.setForeground(fg == null ? table.getSelectionForeground()
                                               : fg);
                super.setBackground(bg == null ? table.getSelectionBackground()
                                               : bg);
        } else {
                super.setForeground(unselectedForeground != null
                                        ? unselectedForeground
                                        : table.getForeground());
            super.setBackground(unselectedBackground != null
                                        ? unselectedBackground
                                        : table.getBackground());
        }
    PS:其他属性和颜色一样,都能用同样的方式设置