Java JTable中的ProgressBar

Java JTable中的ProgressBar,java,swing,jtable,tablecelleditor,Java,Swing,Jtable,Tablecelleditor,我有一个问题,我无法解决使用JTable和包含JProgressBar的编辑器和渲染器的问题。我有一个JButton,用来启动一个线程,增加进度条的值。问题是当我点击JTable的单元格时,进度条不再刷新自己。我试图将ChangeListener添加到进度条中以终止编辑,但其他单元格也无法编辑。 这是一个SSCCE: public class TableTest { final static MyObjectTableModel model = new MyObjectTableMod

我有一个问题,我无法解决使用JTable和包含JProgressBar的编辑器和渲染器的问题。我有一个JButton,用来启动一个线程,增加进度条的值。问题是当我点击JTable的单元格时,进度条不再刷新自己。我试图将ChangeListener添加到进度条中以终止编辑,但其他单元格也无法编辑。
这是一个SSCCE:

public class TableTest {

    final static MyObjectTableModel model = new MyObjectTableModel();
    final static JTable table = new JTable(model);
    private static Map<Integer, Future> mapSubmittedReadProgress = new HashMap<Integer, Future>();
    final static StartProgressActionListener progressActionListener = new StartProgressActionListener();
    final static CloseActionListener closeActionListener = new CloseActionListener();
    final static ProgressChangeListener progressChangeListener = new ProgressChangeListener();

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TableTest().createGUI();
            }
        });
    }

    public static class MyObjectTableModel extends AbstractTableModel {

        private LinkedList<MyObject> myList;

        public MyObjectTableModel() {
            super();
            myList = new LinkedList<MyObject>();
        }

        public MyObjectTableModel(SortedSet<MyObject> myObjects) {
            super();
            this.myList = new LinkedList<MyObject>(myObjects);
        }

        public void addRow(MyObject myObject) {
            myList.add(myObject);
            fireTableRowsInserted(myList.size() - 1, myList.size() - 1);
        }

        public void removeRow(int row) {
            myList.remove(row);
            fireTableRowsDeleted(row, row);
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            myList.set(rowIndex, (MyObject) aValue);
            fireTableCellUpdated(rowIndex, 0);
        }

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

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

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            switch (columnIndex) {
                case 0:
                    return MyObject.class;
                default:
                    throw new IllegalArgumentException("invalid column: " + columnIndex);
            }
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            switch (columnIndex) {
                case 0:
                    return myList.get(rowIndex);
                default:
                    throw new IllegalArgumentException("invalid column: " + columnIndex);
            }
        }

        public MyObject getMyObjectAt(int row) {
            return myList.get(row);
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return true;
        }

        public int getIndexOf(MyObject myObject) {
            return myList.indexOf(myObject);
        }
    }

    private static void createGUI() {
        JFrame f = new JFrame("TableTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        table.getModel().addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        setPreferredRowHeights();
                    }
                });
            }
        });

        for (int i = 0; i < 16; i++) {
            MyObject myObject = new MyObject();
            myObject.setText1("" + i);
            model.addRow(myObject);
        }
        table.setOpaque(false);
        table.setShowGrid(false);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        table.setDefaultRenderer(MyObject.class, new MyTableCellRenderer());
        table.setDefaultEditor(MyObject.class, new MyTableCellEditor());
        table.setFillsViewportHeight(true);
        f.add(new JScrollPane(table));

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static void setPreferredRowHeights() {
        for (int row = 0; row < table.getRowCount(); row++) {
            setPreferredRowHeight(row);
        }
    }

    private static void setPreferredRowHeight(int row) {
        int prefHeight = getPreferredRowHeight(row);
        table.setRowHeight(row, prefHeight);
    }

    public static int getPreferredRowHeight(int row) {
        int pref = 0;
        for (int column = 0; column < table.getColumnCount(); column++) {
            TableCellRenderer renderer = table.getCellRenderer(row, column);
            Component comp = table.prepareRenderer(renderer, row, column);
            pref = Math.max(pref, comp.getPreferredSize().height);
        }
        return pref > 0 ? pref : table.getRowHeight();
    }

    private static class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {

        private MyObjectPanel myObjectPanel = new MyObjectPanel();
        private transient List<CellEditorListener> listeners;

        public MyTableCellEditor() {
            myObjectPanel.addStartProgressActionListener(progressActionListener);
            myObjectPanel.addCloseActionListener(closeActionListener);
//            myObjectPanel.addProgressChangeListener(progressChangeListener);
            listeners = new ArrayList<>();
        }

        @Override
        public boolean isCellEditable(EventObject e) {
            return true;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            MyObject myObject = (MyObject) value;
            myObjectPanel.setMyObject(myObject);
            return myObjectPanel;
        }

        @Override
        public Object getCellEditorValue() {
            MyObject myObject = myObjectPanel.getMyObject();
            return myObject;
        }

        @Override
        public void addCellEditorListener(CellEditorListener l) {
            listeners.add(l);
        }

        @Override
        public void removeCellEditorListener(CellEditorListener l) {
            listeners.remove(l);
        }

        @Override
        protected void fireEditingStopped() {
            ChangeEvent ce = new ChangeEvent(this);
            for (int i = listeners.size() - 1; i >= 0; i--) {
                ((CellEditorListener) listeners.get(i)).editingStopped(ce);
            }
        }
    }

    private static class MyTableCellRenderer implements TableCellRenderer {

        private MyObjectPanel myObjectPanel = new MyObjectPanel();

        public MyTableCellRenderer() {
            myObjectPanel.addStartProgressActionListener(progressActionListener);
            myObjectPanel.addCloseActionListener(closeActionListener);
//            myObjectPanel.addProgressChangeListener(progressChangeListener);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            MyObject myObject = (MyObject) value;
            myObjectPanel.setMyObject(myObject);
            return myObjectPanel;
        }
    }

    private static class ProgressChangeListener implements ChangeListener {

        @Override
        public void stateChanged(ChangeEvent e) {
            if (table.isEditing()) {
                table.getCellEditor().stopCellEditing();
            }
        }
    }

    private static class CloseActionListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            if (table.isEditing()) {
                table.getCellEditor().stopCellEditing();
            }
            model.removeRow(table.getSelectedRow());
        }
    }

    private static class StartProgressActionListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            if (table.isEditing()) {
                table.getCellEditor().stopCellEditing();
            }
            final ExecutorService executor = Executors.newFixedThreadPool(1);
            int row = table.getSelectedRow();
            MyObject myObject = (MyObject) table.getValueAt(row, 0);
            myObject.setStartEnable(false);
            myObject.setText1Enable(false);
            myObject.setText2Enable(false);
            Runnable progressRunnable = new ProgressRunnable(table.getSelectedRow(), myObject);
            final Future<?> submit = executor.submit(progressRunnable);
            mapSubmittedReadProgress.put(table.getSelectedRow(), submit);
        }
    }

    private static class ProgressRunnable implements Runnable {

        private ExecutorService executor;
        private long beT;
        private int dur = 30; // s
        private int progress = 0;
        private int row;
        private MyObject myObject;

        public ProgressRunnable(int row) {
        }

        private ProgressRunnable(int selectedRow, MyObject myObject) {
            this.row = selectedRow;
            this.myObject = myObject;
            beT = System.currentTimeMillis();
        }

        @Override
        public void run() {
            boolean abort = false;
            int i = 0;
            while (i <= dur && !abort) {
                final long curT = System.currentTimeMillis();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    abort = true;
                    executor.shutdown();
                }
                if (Thread.currentThread().isInterrupted()) {
                    abort = true;
                    executor.shutdown();
                }
                progress = (int) Math.round(100 * ((double) (curT - beT) / 1000) / dur);
                myObject.setProgress(progress);
                table.setValueAt(myObject, row, 0);
                i++;
            }
        }
    }

    // My object
    static class MyObject {

        private String text1;
        private String text2;
        private int progress;
        private boolean startEnable = true;
        private boolean abortEnable = true;
        private boolean text1Enable = true;
        private boolean text2Enable = true;
        private boolean closeEnable = true;

        public String getText1() {
            return text1;
        }

        public void setText1(String text1) {
            this.text1 = text1;
        }

        public String getText2() {
            return text2;
        }

        public void setText2(String text2) {
            this.text2 = text2;
        }

        public int getProgress() {
            return progress;
        }

        public void setProgress(int progress) {
            this.progress = progress;
        }

        public boolean isStartEnable() {
            return startEnable;
        }

        public void setStartEnable(boolean startEnable) {
            this.startEnable = startEnable;
        }

        public boolean isAbortEnable() {
            return abortEnable;
        }

        public void setAbortEnable(boolean abortEnable) {
            this.abortEnable = abortEnable;
        }

        public boolean isText1Enable() {
            return text1Enable;
        }

        public void setText1Enable(boolean text1Enable) {
            this.text1Enable = text1Enable;
        }

        public boolean isText2Enable() {
            return text2Enable;
        }

        public void setText2Enable(boolean text2Enable) {
            this.text2Enable = text2Enable;
        }

        public boolean isCloseEnable() {
            return closeEnable;
        }

        public void setCloseEnable(boolean closeEnable) {
            this.closeEnable = closeEnable;
        }
    }

    // MyObjectPanel
    static class MyObjectPanel extends javax.swing.JPanel {

        /**
         * Creates new form MyObjectPanel
         */
        public MyObjectPanel() {
            initComponents();
        }

        /**
         * This method is called from within the constructor to initialize the
         * form. WARNING: Do NOT modify this code. The content of this method is
         * always regenerated by the Form Editor.
         */
        @SuppressWarnings("unchecked")
        // <editor-fold defaultstate="collapsed" desc="Generated Code">
        private void initComponents() {

            jTextField1 = new javax.swing.JTextField();
            jTextField2 = new javax.swing.JTextField();
            jProgressBar1 = new javax.swing.JProgressBar();
            btnStart = new javax.swing.JButton();
            btnStop = new javax.swing.JButton();
            btnClose = new javax.swing.JButton();

            btnStart.setText("Start");

            btnStop.setText("Stop");

            btnClose.setText("Close");

            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
            this.setLayout(layout);
            layout.setHorizontalGroup(
                    layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jTextField1)
                    .addComponent(jTextField2)
                    .addComponent(jProgressBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                    .addComponent(btnStart)
                    .addGap(18, 18, 18)
                    .addComponent(btnStop)
                    .addGap(18, 18, 18)
                    .addComponent(btnClose)
                    .addGap(0, 199, Short.MAX_VALUE)))
                    .addContainerGap()));
            layout.setVerticalGroup(
                    layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                    .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(18, 18, 18)
                    .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(18, 18, 18)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnStart)
                    .addComponent(btnStop)
                    .addComponent(btnClose))
                    .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)));
        }// </editor-fold>
        // Variables declaration - do not modify
        private javax.swing.JButton btnClose;
        private javax.swing.JButton btnStart;
        private javax.swing.JButton btnStop;
        private javax.swing.JProgressBar jProgressBar1;
        private javax.swing.JTextField jTextField1;
        private javax.swing.JTextField jTextField2;
        // End of variables declaration

        void setMyObject(MyObject myObject) {
            jTextField1.setText(myObject.getText1());
            jTextField2.setText(myObject.getText2());
            jProgressBar1.setValue(myObject.getProgress());
            btnStart.setEnabled(myObject.isStartEnable());
            btnClose.setEnabled(myObject.isCloseEnable());
            btnStop.setEnabled(myObject.isAbortEnable());
            jTextField1.setEnabled(myObject.isText1Enable());
            jTextField2.setEnabled(myObject.isText2Enable());
        }

        MyObject getMyObject() {
            MyObject myObject = new MyObject();
            myObject.setText1(jTextField1.getText());
            myObject.setText2(jTextField2.getText());
            myObject.setProgress(jProgressBar1.getValue());
            myObject.setStartEnable(btnStart.isEnabled());
            myObject.setCloseEnable(btnClose.isEnabled());
            myObject.setAbortEnable(btnStop.isEnabled());
            myObject.setText1Enable(jTextField1.isEnabled());
            myObject.setText2Enable(jTextField2.isEnabled());
            return myObject;
        }

        void addStartProgressActionListener(ActionListener progressActionListener) {
            btnStart.addActionListener(progressActionListener);
        }

        void addCloseActionListener(ActionListener closeActionListener) {
            btnClose.addActionListener(closeActionListener);
        }

        void addProgressChangeListener(ChangeListener changeListener) {
            jProgressBar1.addChangeListener(changeListener);
        }
    }
}
公共类TableTest{
最终静态MyObjectTableModel=新的MyObjectTableModel();
最终静态JTable表=新JTable(模型);
私有静态映射MapSubmittedDeardProgress=新HashMap();
最终静态StartProgressActionListener progressActionListener=新StartProgressActionListener();
最终静态CloseActionListener CloseActionListener=新CloseActionListener();
最终静态ProgressChangeListener ProgressChangeListener=新的ProgressChangeListener();
/**
*@param指定命令行参数
*/
公共静态void main(字符串[]args){
invokeLater(新的Runnable(){
@凌驾
公开募捐{
新建TableTest().createGUI();
}
});
}
公共静态类MyObjectTableModel扩展了AbstractTableModel{
私人LinkedList myList;
公共MyObjectTableModel(){
超级();
myList=新的LinkedList();
}
公共MyObjectTableModel(分类集myObjects){
超级();
this.myList=新的LinkedList(myObject);
}
public void addRow(MyObject MyObject){
添加(myObject);
fireTableRowsInserted(myList.size()-1,myList.size()-1);
}
公共无效清除器OW(int行){
myList.remove(行);
fireTableRowsDeleted(行,行);
}
@凌驾
public void setValueAt(对象有效、int行索引、int列索引){
myList.set(行索引,(MyObject)aValue);
fireTableCellUpdated(行索引,0);
}
@凌驾
public int getRowCount(){
返回myList.size();
}
@凌驾
public int getColumnCount(){
返回1;
}
@凌驾
公共类getColumnClass(int columnIndex){
开关(列索引){
案例0:
返回MyObject.class;
违约:
抛出新的IllegalArgumentException(“无效列:“+columnIndex”);
}
}
@凌驾
公共对象getValueAt(int行索引、int列索引){
开关(列索引){
案例0:
返回myList.get(行索引);
违约:
抛出新的IllegalArgumentException(“无效列:“+columnIndex”);
}
}
公共MyObject getMyObjectAt(int行){
返回myList.get(行);
}
@凌驾
公共布尔值isCellEditable(int-rowIndex、int-columnIndex){
返回true;
}
public int getIndexOf(MyObject MyObject){
返回myList.indexOf(myObject);
}
}
私有静态void createGUI(){
JFrame f=新JFrame(“表格测试”);
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table.getModel().addTableModelListener(新的TableModelListener()){
@凌驾
公共作废表已更改(TableModelEvent e){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
setPreferredRowHeights();
}
});
}
});
对于(int i=0;i<16;i++){
MyObject MyObject=新的MyObject();
myObject.setText1(“+i”);
model.addRow(myObject);
}
表1.set不透明(假);
表1.setShowGrid(假);
表.setSelectionMode(ListSelectionModel.SINGLE_选择);
setDefaultRenderer(MyObject.class,新的MyTableCellRenderer());
setDefaultEditor(MyObject.class,新的MyTableCellEditor());
表.setFillsViewPerthweight(真);
f、 添加(新JScrollPane(表));
f、 包装();
f、 setLocationRelativeTo(空);
f、 setVisible(真);
}
私有静态void setPreferredRowHeights(){
对于(int row=0;row0?pref:table.getRowHeight();
}
私有静态类MyTableCellEditor扩展AbstractCellEditor实现TableCellEditor{
私有MyObjectPanel MyObjectPanel=新建MyObjectPanel();
私有临时列表侦听器;
公共MyTableCellEditor(){
myObjectPanel.addStartProgressActionListener(progressActionListener);
myObjectPanel.addCloseActionListener(closeActionListener);
//myObjectPanel.addProgressChangeListener(progressChangeListener);
侦听器=新的ArrayList();
}
@凌驾
公共布尔值isCellEditable(EventObject e){
返回true;
}
@凌驾
公共组件getTableCellEditorComponent(JTable表、对象值、布尔值、整数行、整数列
// End of variables declaration

private MyObject object;
void setMyObject(MyObject myObject) {
  object = myObject;
...
}

MyObject getMyObject() {
  return object;
}
myObject.setProgress(progress);
          if (table.isEditing()) {
            if (table.getEditingRow() == myObject.getRow()) {
              table.getCellEditor().stopCellEditing();
            }
          }
          model.fireTableRowsUpdated(row, row);