2012-03-26 63 views
1

我在JTable单元格内使用JTextField;我使用TabelModel,其中有JTable的动态数据。现在,当我点击一个按钮时,我正在读取单元值。 问题是当前焦点没有返回更新值的单元格。例如,考虑这个程序:返回null的JTable单元格

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.GridLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.JTextField; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellRenderer; 

public class MyTable extends JFrame { 

    DefaultTableModel tmodel = new DefaultTableModel(new Object[][]{ 
      {"some"}, {"any"}, {"even"}, {"text"}, {"and"}, {""}}, 
     new Object[]{"Column 1"}); 

    public MyTable() { 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     final JTable table = new JTable(tmodel); 
     table.setDefaultRenderer(Object.class, new MyRenderer()); 
     getContentPane().add(new JScrollPane(table), BorderLayout.CENTER); 
     getContentPane().setLayout(new GridLayout(2, 2)); 
     JButton jb = new JButton("click me"); //button to display last cell data 
     jb.addActionListener(new ActionListener() { 

      public void actionPerformed(ActionEvent arg0) { 
       JOptionPane.showMessageDialog(
        null, table.getModel().getValueAt(5, 0)); 
      } 
     }); 
     getContentPane().add(jb); 
    } 

    public static void main(String arg[]) { 
     new MyTable().setVisible(true); 
    } 
} 

class MyRenderer implements TableCellRenderer { 

    public Component getTableCellRendererComponent(JTable table, Object value, 
     boolean isSelected, boolean hasFocus, int row, int column) { 
     JTextField editor = new JTextField(); 
     if (value != null) { 
      editor.setText(value.toString()); 
     } 
     return editor; 
    } 
} 

这里我将离开最后一个字段为空。当我读到

table.getModel().getValueAt(5, 0) 

我得到null。现在我将值改为5,0,然后再次点击按钮,但现在我又得到了null。现在令人惊讶的是,我编辑了一些其他单元格,再次单击按钮;现在我在单元格5,0处得到正确的数据!为什么是这样?这是一个错误?我尝试了几种可能性!

+2

1)为了更好地提供帮助,请发布[SSCCE](http://sscce.org/)。 (例如应包括显式导入)2)请为代码块使用一致的逻辑缩进。 – 2012-03-26 15:12:20

+0

检查'getValueAt(1,0)'是否返回'any',也许问题出在你的索引上? – maialithar 2012-03-26 15:29:09

+0

@ h4b0不,不,我多次检查过。具有焦点的单元格返回旧值而不是更新的单元格。 – 2012-03-26 15:30:36

回答

4

结合@ kleopatra的suggestion和@ mkorble的帮助revisions,这里有一些基于你的例子的其他想法。特别注意使用setDefaultButton()Action连同Key Bindings

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.KeyStroke; 
import javax.swing.table.DefaultTableModel; 

/** @see https://stackoverflow.com/q/9874664/230513 */ 
public class MyTable extends JFrame { 

    private static final String show = "Show"; 
    private DefaultTableModel tmodel = new DefaultTableModel(
     new Object[][]{ 
      {"edit"}, {"any"}, {"cell"}, {"text"}, {"and"}, {"edit me"}}, 
     new Object[]{ 
      "Column 1"}); 
    private JTable table = new JTable(tmodel); 
    private Action showAction = new ShowAction(show); 
    private JButton jb = new JButton(showAction); 

    public MyTable() { 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setLocationByPlatform(true); 
     table.putClientProperty("terminateEditOnFocusLost", true); 
     KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); 
     table.getInputMap(JTable.WHEN_FOCUSED).put(enter, show); 
     table.getActionMap().put(show, showAction); 
     add(new JScrollPane(table), BorderLayout.CENTER); 
     table.setPreferredScrollableViewportSize(new Dimension(400, 200)); 
     JPanel panel = new JPanel(); 
     panel.add(jb); 
     getRootPane().setDefaultButton(jb); 
     add(panel, BorderLayout.SOUTH); 
     pack(); 
    } 

    private class ShowAction extends AbstractAction { 

     private ShowAction(String name) { 
      super(name); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      if (table.isEditing()) { 
       table.getCellEditor().stopCellEditing(); 
      } 
      int row = table.getSelectedRow(); 
      if (row > -1) { 
       JOptionPane.showMessageDialog(
        MyTable.this, table.getModel().getValueAt(row, 0)); 
      } 
     } 
    } 

    public static void main(String arg[]) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new MyTable().setVisible(true); 
      } 
     }); 
    } 
} 
+0

这是一个了不起的解决方案...它可以完美地按照我的意愿工作。 谢谢大家:) – 2012-03-28 05:03:02

+0

有礼貌的咳嗽......这个例子有点复杂,并非既不需要也不推荐。 a)OPs示例工作所需的全部内容(现在我理解了问题,最后:-)是设置terminateEdit客户端属性b)输入绑定覆盖表的自己的输入(隐式地终止编辑)c)从不如果你不需要它,调用一个按钮的点击(而不是连接动作)d)安全防护尚未提交的编辑感觉颠倒:应该在显示而不是输入时完成 – kleopatra 2012-03-28 09:51:47

+0

@kleopatra:对所有计数都是正确的;谢谢。我恳求不小心克隆:-) – trashgod 2012-03-28 10:55:27

5

有几个点,你的例子中考虑:

首先,你应该有Java - Tutorials看看,了解渲染和编辑的内JTable中的概念,因为你还挺这里的东西混合起来。在你的Renderer中,你使用了一个没有意义的JTextField,因为这个对象只是用来在你的tableModel中呈现数据。通常使用JLabel来呈现,因为你不会在Renderer中编辑一个值。

此外,你的例子(尽管我还没有尝试过)应该工作,因为JTable已经有了一个DefaultEditor。也许你只是忘记了在点击按钮之前按回车来提交值,以检查哪个值在?

我真的可以推荐阅读this tutorial并搜索一些关于如何正常处理这个问题的例子。你应该找到很多实例。

+0

...很好的答案+1 – mKorbel 2012-03-26 15:45:43

+0

渲染只是我真实项目的一个简单例子。没有这个问题。 你说得对。按输入提交更改,但如何通过代码来完成? 我搜索了很多例子。 JTable&渲染和编辑不是问题。获得价值是。 – 2012-03-26 15:47:09

+0

你的例子似乎不足以满足你的用例。你想要你的例子到底是什么?在编辑单元格中的值时,数据不会保存在TableModel中,因此除非您提交(按下Enter键或更改焦点)该值,否则无法向模型询问当前值。你在编辑单元格时是否需要这个值? – crusam 2012-03-26 15:57:50

5

我认为,每一种类型的数组的开始0(零),然后输出到JOptionPane的是正确的(返回空字符串),点点修改你的原代码,加入最重要的摇摆rulles

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.table.DefaultTableModel; 

public class MyTable extends JFrame { 

    private static final long serialVersionUID = 1L; 
    private DefaultTableModel tmodel = new DefaultTableModel(new Object[][]{ 
       {"some"}, {"any"}, {"even"}, {"text"}, {"and"}, {"xxxxxxxxxxxxxxxxxxxxxxx"}}, 
      new Object[]{"Column 1"}); 

    public MyTable() { 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     final JTable table = new JTable(tmodel); 
     table.setPreferredScrollableViewportSize(table.getPreferredSize()); 
     add(new JScrollPane(table), BorderLayout.CENTER); 
     JButton jb = new JButton("click me"); //button to display last cell data 
     jb.addActionListener(new ActionListener() { 

      public void actionPerformed(ActionEvent arg0) { 
       JOptionPane.showMessageDialog(null, table.getModel().getValueAt(5, 0)); 
      } 
     }); 
     add(jb, BorderLayout.SOUTH); 
     pack(); 
     setVisible(true); 
    } 

    public static void main(String arg[]) { 
     EventQueue.invokeLater(new Runnable() {//added initial thread 

      @Override 
      public void run() { 
       MyTable myTable = new MyTable(); 
      } 
     }); 
    } 
} 
+0

无法正常工作。你是否运行过代码?问题不是设计 – 2012-03-26 15:44:00

+1

@Ashok Raj确信desing是关于成功的,对于复合JComponents来说最重要的是,我离开回答Renderer/Editor问题,因为(@ymene)触及了这个问题,通过回答你的问题 – mKorbel 2012-03-26 15:48:00

+0

我同意你的意见,但是上面的图片只是一个简单的例子,不是我的实际应用。我可以做一个解决方法,但我真的想知道解决这个问题 – 2012-03-26 15:54:38