【问题标题】:Implements a custom CellEditor for a JTable with 2 columns (String, Integer) and n Rows为具有 2 列(字符串、整数)和 n 行的 JTable 实现自定义 CellEditor
【发布时间】:2012-04-22 02:05:31
【问题描述】:

我有一个 N 行 2 列的 JTable 我需要实现一个自定义 CellEditor 类来访问每个单元格的数据输入

table.getCellEditor(int row, int column).getCellEditorValue()

我用过这个 CellEditor 类

class MyEditor extends DefaultCellEditor {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private JTextField textField;
        private boolean valueSet;
          public MyEditor() {
            super(new JTextField());
          }

          @Override
            public boolean isCellEditable(EventObject eo) {
                System.err.println("isCellEditable");
                if (eo instanceof KeyEvent) {
                    KeyEvent ke = (KeyEvent) eo;
                    System.err.println("key event: " + ke.getKeyChar());
                    textField.setText(String.valueOf(ke.getKeyChar()));
                    valueSet = true;
                } else {
                    valueSet = false;
                }
                return true;
            }
    }

但不足以访问正确单元格位置中的数据...(并且似乎所有表格都被视为一个完整的单元格)

我发现的所有示例都与使用单元格编辑器在输入不正确但足够清晰可以帮助我解决问题的情况下阻止编辑单元格有关。

PS 如果您想详细了解整个界面(不)是如何工作的,那么整个代码是这样的:

public class CompileDataJob extends JFrame {
      private boolean DEBUG = false;
    private JPanel contentPane;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    CompileDataJob frame = new CompileDataJob();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public CompileDataJob() {
        setTitle("Inserisci i parametri dei lavori");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 551, 293);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);

        JPanel panel_1 = new JPanel();
        final JTable table = new JTable(new MyTableModel());

        JButton btnNewButton = new JButton("    OK   ");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try{
                    DataJobManager.azzeraListaLavori();
                    int numJob=DataJobManager.loadNumeroLavori();
                    LinkedList<Job> listaLavori=new LinkedList<Job>();
                    String id;
                    int time;
                    for (int rowIndex=0; rowIndex<numJob; rowIndex++){
                            id=(String)(table.getCellEditor(rowIndex,0).getCellEditorValue());
                            time=Integer.parseInt(((String)((table.getCellEditor(rowIndex, 1)).getCellEditorValue())));
                            Job l=new Job(id,time);
                            listaLavori.add(l);
                    }
                        DataJobManager.saveListaLavori(listaLavori);
                        CompileDataJob.this.dispose();
                        JOptionPane.showMessageDialog(CompileDataJob.this,"Data Saved");
                }catch(Exception ecc){
                    JOptionPane.showMessageDialog(CompileDataJob.this,"Error during the saving.");
                }
            }
        });
        panel_1.add(btnNewButton);

        JButton btnNewButton_1 = new JButton("Cancel");
        btnNewButton_1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                CompileDataJob.this.dispose();
            }
        });

        JPanel panel = new JPanel();



        table.setDefaultEditor(Object.class,new MyEditor());

        table.setPreferredScrollableViewportSize(new Dimension(500, 70));
        table.setFillsViewportHeight(true);
        table.getSelectionModel().addListSelectionListener(
                new ListSelectionListener() {
                    public void valueChanged(ListSelectionEvent event) {
                        int viewRow = table.getSelectedRow();
                        JLabel statusText=new JLabel();
                        if (viewRow < 0) {
                            //Selection got filtered away.
                            statusText.setText("");
                        } else {
                            int modelRow = 
                                table.convertRowIndexToModel(viewRow);
                            statusText.setText(
                                String.format("Selected Row in view: %d. " +
                                    "Selected Row in model: %d.", 
                                    viewRow, modelRow));
                        }
                    }
                }
        );


                //Create the scroll pane and add the table to it.
                JScrollPane scrollPane = new JScrollPane(table);

                        //Set up column sizes.
                        initColumnSizes(table);

        panel_1.add(btnNewButton_1);
        GroupLayout gl_contentPane = new GroupLayout(contentPane);
        gl_contentPane.setHorizontalGroup(
            gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_contentPane.createSequentialGroup()
                    .addGroup(gl_contentPane.createParallelGroup(Alignment.TRAILING, false)
                        .addComponent(panel_1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(panel, GroupLayout.DEFAULT_SIZE, 525, Short.MAX_VALUE))
                    .addContainerGap())
        );
        gl_contentPane.setVerticalGroup(
            gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_contentPane.createSequentialGroup()
                    .addComponent(panel, GroupLayout.PREFERRED_SIZE, 213, GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(ComponentPlacement.RELATED, 61, Short.MAX_VALUE)
                    .addComponent(panel_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
        );
        GroupLayout gl_panel = new GroupLayout(panel);
        gl_panel.setHorizontalGroup(
            gl_panel.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_panel.createSequentialGroup()
                    .addGap(11)
                    .addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addContainerGap(12, Short.MAX_VALUE))
        );
        gl_panel.setVerticalGroup(
            gl_panel.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_panel.createSequentialGroup()
                    .addGap(5)
                    .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 197, Short.MAX_VALUE)
                    .addContainerGap())
        );
        panel.setLayout(gl_panel);
        contentPane.setLayout(gl_contentPane);



    }

    private void initColumnSizes(JTable table) {
        MyTableModel model = (MyTableModel)table.getModel();
        TableColumn column = null;
        Component comp = null;
        int headerWidth = 0;
        int cellWidth = 0;
        Object[] longValues = model.longValues;
        TableCellRenderer headerRenderer =
            table.getTableHeader().getDefaultRenderer();

        for (int i = 0; i < 2; i++) {
            column = table.getColumnModel().getColumn(i);

            comp = headerRenderer.getTableCellRendererComponent(
                                 null, column.getHeaderValue(),
                                 false, false, 0, 0);
            headerWidth = comp.getPreferredSize().width;

            comp = table.getDefaultRenderer(model.getColumnClass(i)).
                             getTableCellRendererComponent(
                                 table, longValues[i],
                                 false, false, 0, i);
            cellWidth = comp.getPreferredSize().width;

            if (DEBUG) {
                System.out.println("Initializing width of column "
                                   + i + ". "
                                   + "headerWidth = " + headerWidth
                                   + "; cellWidth = " + cellWidth);
            }

            column.setPreferredWidth(Math.max(headerWidth, cellWidth));
        }
    }

    class MyEditor extends DefaultCellEditor {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private JTextField textField;
        private boolean valueSet;
          public MyEditor() {
            super(new JTextField());
          }

          @Override
            public boolean isCellEditable(EventObject eo) {
                System.err.println("isCellEditable");
                if (eo instanceof KeyEvent) {
                    KeyEvent ke = (KeyEvent) eo;
                    System.err.println("key event: " + ke.getKeyChar());
                    textField.setText(String.valueOf(ke.getKeyChar()));
                    //textField.select(1,1);
                    //textField.setCaretPosition(1);
                    //textField.moveCaretPosition(1);
                    valueSet = true;
                } else {
                    valueSet = false;
                }
                return true;
            }
    }





    class MyTableModel extends AbstractTableModel {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private String[] columnNames = {"Nome Job", "Durata"};
        int numJob=DataJobManager.loadNumeroLavori();
        private Object[][] data = getDatiDefaultTabella();

        public class Job {
            public int time; // Should n't this be a long?
            public String jobName;
        }

        public Object[][] getDatiDefaultTabella(){
            Object[][] tabella=new Object[numJob][2];
            for(int i=0; i<numJob; i++){
                for(int j=0; j<2; j++){
                    tabella[i][j]="inserisci dati";
                }
            }

            return tabella;
        }

        public Object[][] getTabella(){
            return data;
        }


        public int getColumnCount() {
            return columnNames.length;
        }

        public int getRowCount() {
            return numJob;
        }

        public String getColumnName(int col) {
            return columnNames[col];
        }

        public Object getValueAt(int row, int col) {
            return data[row][col];
        }

        /*
         * JTable uses this method to determine the default renderer/
         * editor for each cell.  If we didn't implement this method,
         * then the last column would contain text ("true"/"false"),
         * rather than a check box.
         */
        public Class getRowClass(int r) {
            return getValueAt(r, 0).getClass();
        }

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


        /*
         * Don't need to implement this method unless your table's
         * editable.
         */
        public boolean isCellEditable(int row, int col) {
            //Note that the data/cell address is constant,
            //no matter where the cell appears onscreen.
            return true;
        }



        /*
         * Don't need to implement this method unless your table's
         * data can change.
         */
        public void setValueAt(Object value, int row, int col) {
            if (DEBUG) {
                System.out.println("Setting value at " + row + "," + col
                                   + " to " + value
                                   + " (an instance of "
                                   + value.getClass() + ")");
            }

            data[row][col] = value;
            fireTableCellUpdated(row, col);

            if (DEBUG) {
                System.out.println("New value of data:");
                printDebugData();
            }
        }

        private void printDebugData() {
            int numRows = getRowCount();
            int numCols = getColumnCount();

            for (int i=0; i < numRows; i++) {
                System.out.print("    row " + i + ":");
                for (int j=0; j < numCols; j++) {
                    System.out.print("  "  + data[i][j]);
                }
                System.out.println();
            }
            System.out.println("--------------------------");
        }
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */

        public void run() {
            try {
                CompileDataJob frame = new CompileDataJob();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
}

【问题讨论】:

  • 该代码无法编译,因此很难看出您如何使用它。
  • 我已经编辑并添加了整个界面代码......所以现在你可以尝试编译它,如果你愿意。 DataJobManager 只是一个输入\输出流类,我在其中存储和加载一些数据,而 Job 是一个简单的对象,String id, int time
  • @AndreaF 我在这里删除了我的答案,也许有人可以帮助你......
  • 我希望如此^^ 无论如何谢谢...这些该死的 jtables 真是让人头疼
  • 不是,一切都隐藏在(JTable table, Object value, boolean isSelected, int row, int column)int row, int column

标签: java swing jtable tablecellrenderer tablecelleditor


【解决方案1】:

好的,我想我明白了。 我稍微优化了你的代码并删除了我不需要的东西。您可以重新添加它。

这是编译数据作业

public class CompileDataJob extends JFrame {
    final boolean DEBUG = false;
  private final JPanel contentPane;

  /**
   * Launch the application.
   */
  public static void main(String[] args) {
      EventQueue.invokeLater(new Runnable() {
          public void run() {
              try {
                  CompileDataJob frame = new CompileDataJob();
                  frame.setVisible(true);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      });
  }

  /**
   * Create the frame.
   */
  public CompileDataJob() {
      setTitle("Inserisci i parametri dei lavori");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setBounds(100, 100, 551, 293);
      contentPane = new JPanel();
      contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
      setContentPane(contentPane);

      JPanel panel_1 = new JPanel();
      final JTable table = new JTable(new MyTableModel());

      JButton add = new JButton(" ADD ");
      add.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            ((MyTableModel)table.getModel()).addRow(new Job(0, ""));
        }
      });

      JButton btnNewButton = new JButton("    OK   ");
      btnNewButton.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
              try{
                      DataJobManager.saveListaLavori(((MyTableModel)table.getModel()).getJobs());
                      CompileDataJob.this.dispose();
                      JOptionPane.showMessageDialog(CompileDataJob.this,"Data Saved");
              }catch(Exception ecc){
                  JOptionPane.showMessageDialog(CompileDataJob.this,"Error during the saving.");
              }
          }
      });
      panel_1.add(btnNewButton);
      panel_1.add(add);
      JButton btnNewButton_1 = new JButton("Cancel");
      btnNewButton_1.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent arg0) {
              CompileDataJob.this.dispose();
          }
      });

      JPanel panel = new JPanel();



//      table.setDefaultEditor(Object.class,new MyEditor());

      table.setPreferredScrollableViewportSize(new Dimension(500, 70));
      table.setFillsViewportHeight(true);

              //Create the scroll pane and add the table to it.
              JScrollPane scrollPane = new JScrollPane(table);


      panel_1.add(btnNewButton_1);
      GroupLayout gl_contentPane = new GroupLayout(contentPane);
      gl_contentPane.setHorizontalGroup(
          gl_contentPane.createParallelGroup(Alignment.LEADING)
              .addGroup(gl_contentPane.createSequentialGroup()
                  .addGroup(gl_contentPane.createParallelGroup(Alignment.TRAILING, false)
                      .addComponent(panel_1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                      .addComponent(panel, GroupLayout.DEFAULT_SIZE, 525, Short.MAX_VALUE))
                  .addContainerGap())
      );
      gl_contentPane.setVerticalGroup(
          gl_contentPane.createParallelGroup(Alignment.LEADING)
              .addGroup(gl_contentPane.createSequentialGroup()
                  .addComponent(panel, GroupLayout.PREFERRED_SIZE, 213, GroupLayout.PREFERRED_SIZE)
                  .addPreferredGap(ComponentPlacement.RELATED, 61, Short.MAX_VALUE)
                  .addComponent(panel_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
      );
      GroupLayout gl_panel = new GroupLayout(panel);
      gl_panel.setHorizontalGroup(
          gl_panel.createParallelGroup(Alignment.LEADING)
              .addGroup(gl_panel.createSequentialGroup()
                  .addGap(11)
                  .addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                  .addContainerGap(12, Short.MAX_VALUE))
      );
      gl_panel.setVerticalGroup(
          gl_panel.createParallelGroup(Alignment.LEADING)
              .addGroup(gl_panel.createSequentialGroup()
                  .addGap(5)
                  .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 197, Short.MAX_VALUE)
                  .addContainerGap())
      );
      panel.setLayout(gl_panel);
      contentPane.setLayout(gl_contentPane);



  }
}

这是工作

public class Job {
    public int time = 500; // Should n't this be a long?
    public String jobName;
    public boolean processed = false;

    public Job(int time, String jobName) {
        this.time = time;
        this.jobName = jobName;
    }

    public boolean isProcessed() {
        return processed;
    }
}

这是您的 TableModel,它是可优化的,但可以工作...

class MyTableModel extends AbstractTableModel {
    private static final long serialVersionUID = 1L;
    private final List<Job> objects = new ArrayList<Job>();
    private final String[] columnNames = { "Nome Job", "Durata", "processed" };

    private final Class<?>[] metaModell = new Class[]{String.class, Integer.class, Boolean.class};

    public int getColumnCount() {
        return columnNames.length;
    }

    public int getRowCount() {
        return objects.size();
    }

    @Override
    public String getColumnName(int col) {
        return columnNames[col];
    }

    public Object getValueAt(int row, int col) {
        if (row >= objects.size()) 
            return null;
        Job job = getRow(row);
        switch (col) {
            case 0:
                return job.jobName;
            case 1:
                return job.time;
            case 2:
                return job.isProcessed();
        }
        return null;
    }

    private Job getRow(int row) {
        return objects.get(row);
    }

    @Override
    public Class<?> getColumnClass(int c) {
        if (c < metaModell.length)
            return metaModell[c];
        return Object.class;
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return col >= 0 && col < columnNames.length;
    }

    @Override
    public void setValueAt(Object value, int row, int col) {
        Job job = getRow(row);
        switch (col) {
            case 0:
                job.jobName = (String) value;
                break;
            case 1:
                job.time = (Integer) value;
                break;
//          case 2:
//              job.processed = (Boolean) value;
//              break;
        }
        fireTableDataChanged();
    }

    public List<Job> getJobs() {
        return objects;
    }

    public void addRow(Job job) {
        this.objects.add(job);
        fireTableDataChanged();
    }
}

如您所见,我删除了所有 MyEditor 内容以及编辑器内容中复杂的 getValues。我改为在表模型中添加了一个方法 addJob()getJobs

【讨论】:

  • 出现了一点错误,但工作正常...非常感谢!
【解决方案2】:

好的,你的类确实定义了一个 CellEditor,但它没有做任何 DefaultEditor 不会做的事情。

此外,您不要将它们粘在一起。 您的 JTable 不知道它应该使用哪个 CellEditor。 您必须告诉您的表使用您的编辑器实现。 有多种方法可以做到这一点(例如,为一个类设置一个默认渲染器,它由你的 tablemodel 返回)。 您还可以将 CellEditor 直接分配给列( column.setCellEditor(new MyCellEditor()); --> http://docs.oracle.com/javase/tutorial/uiswing/components/table.html)

【讨论】:

  • 这个我知道...但是问题是如何实现正确的cellEditor来满足这个问题的解决方案。
  • 好的,我不确定我是否遇到了您的问题。您有一个包含两列的表(1. 列是一个数字 -> 工作编号,2. 列是一个字符串)。所以你必须为 Integer.class 和 String.class 设置 2 个默认编辑器。 Object.class 可能会做你想做的事,但你的 get*Class() 方法确实返回具体的类,所以也使用具体的编辑器(据我所知,还注册了 String 的默认编辑器)
  • 我想说的是:尝试table.setDefaultEditor(Integer.class,new MyEditor());table.setDefaultEditor(String.class,new MyEditor());而不是table.setDefaultEditor(Object.class,new MyEditor());
  • 第 1 列是一个字符串作业,第 2 列是一个数字 int... 表格显示正确,但是当您尝试从单元格编辑器获取数据以从已编辑的 @987654326 中提取新数据时@ 只返回最后一个单元格的数据,不返回传递的坐标数据。
  • 好吧,我还是不明白你的问题。为什么要从 cellEditor 中获取值?您的数据存储在您的表模型中。问它,不要打扰单元格编辑器。它只是编辑表格模型的帮手。 Java 负责将模型数据传输到编辑器并返回到模型。如果要向表模型添加新条目,请执行类似于此的操作 -> tblModel.addItem(new Job("", 0));之后您可以通过 gui 编辑表格中的单元格(因此您不必手动调用单元格编辑器)
猜你喜欢
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-16
  • 1970-01-01
相关资源
最近更新 更多