微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

当 AbstractTableModel 调用 fireTableStructureChanged 时,Java JTable 列丢失 TableCellRenderer

如何解决当 AbstractTableModel 调用 fireTableStructureChanged 时,Java JTable 列丢失 TableCellRenderer

我有一个 JTable,我想在其中使用 JProgressBar 来呈现其中一列中的数据。我可以通过调用 setCellRenderer() 来做到这一点。

但是,我还有一个 SwingWorker,它可以修改我的 AbstractTableModel 以向表中添加一列,在这种情况下,我调用了 fireTableStructureChanged()。不幸的是,这会导致我的列丢失自定义 TableCellRenderer。

我尝试过 setautocreateColumnsFromModel(false),但这会阻止我的 AbstractTableModel 添加新列。这是我的代码

package components;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;

public class LostRenderer extends JPanel {

    private static final long serialVersionUID = 1L;

    // Make the JTable a field,so inner class TableCellTask can access it
    private final JTable table;

    public class ProgressBarCellRenderer extends JProgressBar implements TableCellRenderer {

        private static final long serialVersionUID = 1L;

        @Override
        public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) {
            setValue((int) value);
            return this;
        }
    }
    
    public LostRenderer() {
        super(new GridLayout(1,0));

        MyTableModel myTableModel = new MyTableModel();
        table = new JTable(myTableModel);
        table.setPreferredScrollableViewportSize(new Dimension(500,70));
        table.setFillsViewportHeight(true);

        table.getColumn("Progress").setCellRenderer(new ProgressBarCellRenderer());
        /*
         * NOTE: table.setautocreateColumnsFromModel(true); (or commenting out the call)
         * results in the column renderer getting lost when table structure is changes.
         * Setting it to false maintains column renderer,but no new columns get added.
         */
        table.setautocreateColumnsFromModel(true);
        
        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(table);

        //Add the scroll pane to this panel.
        add(scrollPane);

        new TableCellTask(myTableModel).execute();
    }

    private class TableCellTask extends SwingWorker<Void,Integer> {
        
        private final MyTableModel myTableModel;
        
        public TableCellTask(MyTableModel myTableModel) {
            this.myTableModel = myTableModel;
        }
        
        @Override
        protected Void doInBackground() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
            publish(new Integer( 0));
            return null;
        }

        @Override
        protected void process(List<Integer> tableCells) {
            for (int tableCell : tableCells) {
                myTableModel.process(tableCell);
            }
        }
    }

    class MyTableModel extends AbstractTableModel {

        private static final long serialVersionUID = 1L;
        
        private List<Integer> data = new ArrayList<Integer>();

        public int getColumnCount() {
            return data.size() + 1;
        }

        public int getRowCount() {
            return 1;
        }

        public String getColumnName(int col) {
            if (col == 0) {
                return "Progress";
            } else {
                return "Data" + col;
            }
        }

        public Object getValueAt(int row,int col) {
            if (col == 0) {
                return 50;
            } else {
                return data.get(col - 1);
            }
        }

        public Class<?> getColumnClass(int c) {
            return getValueAt(0,c).getClass();
        }

        public void process(int value) {
            data.add(value);
            fireTableStructureChanged();
        }

    }

    /**
     * Create the GUI and show it.  For thread safety,* this method should be invoked from the
     * event-dispatching thread.
     * 
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("LostRenderer");
        frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        LostRenderer newContentPane = new LostRenderer();
        newContentPane.setopaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {

        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokelater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });

    }
}

这是表格开始时的样子(使用正确的 JProgressBar 渲染):

Before AbstractTableModel calls fireTableStructureChanged()

这是我添加列后的样子(列丢失了 JProgressBar 渲染):

After AbstractTableModel calls fireTableStructureChanged()

如有任何建议,我们将不胜感激。

解决方法

我不得不重新排列您的代码,但我想出了以下 GUI。

JTable Renderer 1

2 秒后。

JTable Renderer 2

我所做的主要更改是在您的 TableModel 中为第一列指定一个唯一的类值。然后,我可以将 JProgressBar 渲染器设置为该列作为默认渲染器。

它使阅读您代码的人更容易分离您的类并组织代码,以便重要的部分在前,更详细的部分在后。

无需扩展 JPanelJProgressBar。您应该扩展 Swing 组件或任何 Java 类的唯一时间是当您想要覆盖一个或多个类方法时。

这是完整的可运行代码。

import java.awt.BorderLayout;
import java.awt.Component;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;

public class JTableRendererGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new JTableRendererGUI());
    }
    
    private JTable table;
    
    private MyTableModel myTableModel;
    
    public JTableRendererGUI() {
        this.myTableModel = new MyTableModel();
    }
    
    @Override
    public void run() {
        JFrame frame = new JFrame("JTable Renderer");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(createMainPanel(),BorderLayout.CENTER);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        
        new TableCellTask(myTableModel).execute();
    }
    
    private JPanel createMainPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        
        table = new JTable(myTableModel);
        table.setDefaultRenderer(MyTableModel.class,new ProgressBarCellRenderer());
        table.setAutoCreateColumnsFromModel(true);
        table.setFillsViewportHeight(true);
        JScrollPane scrollPane = new JScrollPane(table);
        
        panel.add(scrollPane,BorderLayout.CENTER);
        
        return panel;
    }
    
    public class TableCellTask extends SwingWorker<Void,Integer> {

        private final MyTableModel myTableModel;

        public TableCellTask(MyTableModel myTableModel) {
            this.myTableModel = myTableModel;
        }

        @Override
        protected Void doInBackground() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            publish(0);
            return null;
        }

        @Override
        protected void process(List<Integer> tableCells) {
            for (int tableCell : tableCells) {
                myTableModel.process(tableCell);
            }
        }
    }
    
    public class MyTableModel extends AbstractTableModel {

        private static final long serialVersionUID = 1L;

        private List<Integer> data = new ArrayList<Integer>();

        public int getColumnCount() {
            return data.size() + 1;
        }

        public int getRowCount() {
            return 1;
        }

        public String getColumnName(int col) {
            if (col == 0) {
                return "Progress";
            } else {
                return "Data" + col;
            }
        }

        public Object getValueAt(int row,int col) {
            if (col == 0) {
                return 50;
            } else {
                return data.get(col - 1);
            }
        }

        public Class<?> getColumnClass(int c) {
            if (c == 0) {
                return MyTableModel.class;
            } else {
                return getValueAt(0,c).getClass();
            }
        }

        public void process(int value) {
            data.add(value);
            fireTableStructureChanged();
        }

    }
    
    public class ProgressBarCellRenderer implements TableCellRenderer {
        
        private JProgressBar progressBar;
        
        public ProgressBarCellRenderer() {
            this.progressBar = new JProgressBar();
        }

        @Override
        public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) {
           progressBar.setValue((int) value);
           return progressBar;
        }

    }

}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?