在OS X Lion上使用Java 7中的JTables对setValueAt进行虚假调用?
升级到Lion和Java7之后,我遇到了JTables的问题。当我使用箭头键移动选择时,其调用在OS X Lion上使用Java 7中的JTables对setValueAt进行虚假调用?,java,swing,osx-lion,java-7,Java,Swing,Osx Lion,Java 7,升级到Lion和Java7之后,我遇到了JTables的问题。当我使用箭头键移动选择时,其调用setValueAt(),将空字符串作为编辑值 为了测试这一点,我创建了一个简单的JFrame,其中包含一个表,并将下面的类设置为它的模型 public class SpyModel extends AbstractTableModel { public int getColumnCount() { return 5; } public int getRowCount() { retur
setValueAt()
,将空字符串作为编辑值
为了测试这一点,我创建了一个简单的JFrame,其中包含一个表,并将下面的类设置为它的模型
public class SpyModel extends AbstractTableModel {
public int getColumnCount() { return 5; }
public int getRowCount() { return 5; }
public Object getValueAt(int rowIndex, int columnIndex) { return ""; }
public boolean isCellEditable(int rowIndex, int columnIndex) { return true; }
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
System.out.println(aValue == null ? "null" : "\"" + aValue + "\"");
}
}
当我在Java6下运行它时,然后使用箭头键在其中移动。它很好用。e、 g
$ java -version
java version "1.6.0_33"
Java(TM) SE Runtime Environment (build 1.6.0_33-b03-424-11M3720)
Java HotSpot(TM) 64-Bit Server VM (build 20.8-b03-424, mixed mode)
$ java -jar JavaApplication5.jar
但是,当我在Java 7(在Lion上)下运行它,并用箭头键移动选择时,它最终会用空字符串调用setValueAt()
e、 g
我已经找过虫子了,但什么也没找到。这是一个已知的问题吗 在使用该表示例时,似乎存在不止一个bug 我使用了下面的SSCCE,它在JDK1.6下按预期工作
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class TableBugDemo {
public static void main( String[] args ) {
JFrame frame = new JFrame( "TestFrame" );
final JTable table = new JTable( new SpyModel() );
table.getSelectionModel().addListSelectionListener( new ListSelectionListener() {
@Override
public void valueChanged( ListSelectionEvent e ) {
Thread.dumpStack();
System.out.println(table.getSelectedRow());
}
} );
frame.add( table );
frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
public static class SpyModel extends DefaultTableModel{
public SpyModel() {
super( new String[][]{
new String[]{ "row1-1", "row1-2", "row1-3"},
new String[]{ "row2-1", "row2-2", "row2-3"},
new String[]{ "row3-1", "row3-2", "row3-3"},
new String[]{ "row4-1", "row4-2", "row4-3"},
}, new String[]{"col1", "col2", "col3"});
}
@Override
public void setValueAt( Object aValue, int row, int column ) {
System.out.println( "TableBugDemo$SpyModel.setValueAt" );
Thread.dumpStack();
super.setValueAt( aValue, row, column );
}
@Override
public boolean isCellEditable( int row, int column ) {
return false;
}
}
}
但是,在JDK1.7下:
- 我看到在使表格可编辑时调用了
。但是,不是使用空字符串,而是使用mysetValueAt
中包含的实际值。这意味着我的数据没有任何更改。唯一恼人的是,在导航过程中,我的表不断更新。解决方法当然是在值根本没有更新时,通过快速退出路径调整TableModel
方法,例如添加setValueAt
if ( ( aValue != null && aValue.equals( getValueAt( row, column ) ) ) || ( aValue == null && getValueAt( row, column ) == null ) ){ return; }
- 使用向上和向下箭头导航可使选择一次跳过两行。Stacktraces显示选择的变化源于
类(这很有意义,因为这是放置在动作图中的动作)。奇怪的是,按下一个键,这个动作会触发两次。这已经解释了为什么选择一次跳两行。进一步的调试显示,对于一次按我的箭头键,我收到了两个不同的BasicTableUI#Actions
键被按下的事件。据我所知,这些事件与
上的事件类似,与EventQueue
无关。为了确保这一点,我创建了一个小型SSCCE,其中不包括JTable
:JTable
import javax.swing.JFrame; import javax.swing.WindowConstants; import java.awt.AWTEvent; import java.awt.EventQueue; import java.awt.Toolkit; import java.awt.event.AWTEventListener; import java.awt.event.KeyEvent; public class KeyEventBugDemo { public static void main( String[] args ) { EventQueue.invokeLater(new Runnable() { @Override public void run() { JFrame testframe = new JFrame( "testframe" ); testframe.setSize( 300,300 ); testframe.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE ); testframe.setVisible( true ); } } ); Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener() { @Override public void eventDispatched( AWTEvent event ) { if (event instanceof KeyEvent ){ KeyEvent keyevent = ( KeyEvent ) event; System.out.println( "keyevent.getKeyCode() = " + keyevent.getKeyCode() ); System.out.println( "ID = " + System.identityHashCode( keyevent ) ); System.out.println( "keyevent = " + keyevent ); } } }, AWTEvent.KEY_EVENT_MASK ); } }
toString
的输出以保持可读性)
在这里,您可以清楚地看到按下两个键
事件会混淆JTable
。使用常规字符键时不会发生这种情况
keyevent.getKeyCode() = 65
ID = 1023134153
keyevent = java.awt.event.KeyEvent[KEY_PRESSED,keyCode=65,keyText=A,
ID = 914147942
keyevent = java.awt.event.KeyEvent[KEY_TYPED,keyCode=0,keyText=Unknown
keyevent.getKeyCode() = 65
ID = 986450556
keyevent = java.awt.event.KeyEvent[KEY_RELEASED,keyCode=65,keyText=A,keyChar='a',
查看KeyEvent
类中的javadoc:
键入的密钥(仅当可以生成有效的Unicode字符时才生成。)
按箭头时,我不会键入键
事件,但按两次键会触发,我认为这是一个错误(稍后将为此记录错误报告)。一个解决办法可能是拦截这样一个事件,而不是通过链传递它,但这听起来像是一个丑陋的黑客
编辑
另一件奇怪的事。如果将以下行添加到代码段中
table.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).
put( KeyStroke.getKeyStroke( 'a' ), "selectNextRow" );
您可以使用a
跳到下一行(与默认情况下使用向下箭头触发的操作相同)。由于按下a
时事件顺序正确,因此似乎也不会调用setValueAt
方法。这使我认为按下两个键
事件会以某种方式启动编辑…解决方法是使用:
putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
但在这种情况下,您将无法通过直接键入在单元格中开始编辑。您必须使用鼠标开始编辑。我还向Oracle发布了一个bug,但它也不可用。。。似乎他们的系统有问题。除了更新,我仍然看到1.7.0(40)的问题,因为我用光标键在我的JTable单元格中移动,它会导致进入的每个字段都被清空
添加:
table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE)
停止该问题的发生,但我必须按“回车”键开始编辑
相反,在Jtables模型开始时,检查空字符串并返回将解决此问题
i、 e
但这确实意味着,如果用户确实想要清空该字段,那么更改将被拒绝。在我自己的应用程序中,这并不是一个问题,因为我有一个单独的deleteField()操作供他们使用
这个问题可以在这里的OpenJdk bug跟踪器中找到
目前,在Jdk 9发布之前,这个问题还没有得到解决。我已经把它作为一个bug提交了:这个bug在最新的Jdk 7(9版)中没有得到解决。bug报告不再可见,苹果最新的JDK 6推送将Java 7作为默认版本,并删除Java首选项应用程序。有趣的时刻。非常有趣的是,你看到它被原始值和双键事件调用。我只是重新运行了我的应用程序(不是示例),并确认了最初的行为<使用空字符串调用code>setValueAt()
,我没有观察到双键事件。运行您的示例,我得到了替换为相同的字符串行为,但不是双键事件。我把表格放在一个滚动窗格中,并在表格上调用setCellSelectionEnabled(true),以使其更符合应用程序。我使用build 1.7.0_04-ea-b11
(默认情况下获得的JDK)@Bill我添加了一个小编辑。看起来setValueAt
调用与我的机器上按下的两个键直接相关我现在无法检查,但昨晚我想我注意到(在启用单元格选择的情况下)对setValueAt
的伪调用仅在上/下移动而非左/右移动时发生。编辑顺便说一句,我现在在最新的下载。u09 IIRC。谢谢,但那真的不行。
putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE)
if(Platform.isOSX())
{
if(value.equals(""))
{
return;
}
}