0

内部に JProgressBar を含むエディターとレンダラーで JTable を使用して解決できない問題があります。プログレスバーの値をインクリメントするスレッドを開始するために使用される 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);
        }
    }
}


助けてくれてありがとう。

4

1 に答える 1

1

それを機能させるために変更することがいくつかあります。

まず、MyObjectPanelクラスには変数が必要であり、呼び出されるMyObjectたびに新しい変数を返すのではなく、変数を返す必要があります。getMyObjectこの変数は、setMyObjectで が呼び出されたときに設定されMyObjectPanelます。

// End of variables declaration

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

MyObject getMyObject() {
  return object;
}

第 2 に、MyObjectクラスには、int rowそれが表す行を認識できる変数が必要です。この変数のゲッターも作成します。forのループでこの変数を設定しますcreateGUI

最後に、 in で、進行while中のセルである場合はセルの編集を停止する必要があります。これを行うには、この行が進行変数と同じかどうかをテーブルで確認します。このようなもの :ProgressRunnablerunJTable.getEditingRowisEditingmyObject.getRowmyObject

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

また、代わりにsetValuethere forを変更したことにも注意してください。fireTableRowsUpdated

これにより、必要に応じて動作するはずです。

を削除TableModelListenerして、 の前に 1 回createGUIだけ電話をかけることができます。setPreferredRowHeightspack

于 2013-03-07T20:23:55.947 に答える