簡體   English   中英

當 AbstractTableModel 調用 fireTableStructureChanged 時 Java JTable 列丟失 TableCellRenderer

[英]Java JTable column loses TableCellRenderer when AbstractTableModel calls fireTableStructureChanged

我有一個 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 渲染): 在 AbstractTableModel 調用 fireTableStructureChanged() 之前

這是我添加列后的樣子(列丟失了 JProgressBar 渲染): AbstractTableModel 調用 fireTableStructureChanged() 之后

任何建議,將不勝感激。

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

JTable 渲染器 1

2 秒后。

JTable 渲染器 2

我所做的主要更改是在TableModel中為第一列提供一個唯一的 class 值。 然后,我可以將JProgressBar渲染器設置為該列作為默認渲染器。

它使閱讀您的代碼的人更容易分離您的類並組織代碼,以便重要部分放在首位,然后是更詳細的部分。

無需擴展JPanelJProgressBar The only time you should extend a Swing component, or any Java class, is when you want to override one or more of the class methods.

這是完整的可運行代碼。

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;
        }

    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM