在OS X Lion上使用Java 7中的JTable进行setValueAt的虚假调用? [英] Spurious calls to setValueAt with JTables in Java 7 on OS X Lion?

查看:114
本文介绍了在OS X Lion上使用Java 7中的JTable进行setValueAt的虚假调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

升级到Lion和Java 7之后,我遇到了JTables的问题。当我使用箭头键移动选择时,它调用 setValueAt(),其中空字符串作为编辑值。

After upgrading to Lion, and Java 7, I am running into issues with JTables. When I use arrow keys to move the selection around, its calling setValueAt() with empty strings as the edit value.

为了测试这个,我创建了一个带有表格的简单JFrame,并将以下类设置为其模型。

To test this, I created a simple JFrame with a table in it, and set the following class as its model.

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 + "\"");
    }
}

当我在Java 6下运行它,然后使用箭头键可以穿过它。它工作正常。例如

When I run it under Java 6, and then use the arrow keys to move through it. it works fine. 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()

However, when I run it under Java 7 (on Lion), and move the selection with the arrow keys, it ends up calling setValueAt() with empty strings.

例如

$ java -version
java version "1.7.0_05"
Java(TM) SE Runtime Environment (build 1.7.0_05-b06)
Java HotSpot(TM) 64-Bit Server VM (build 23.1-b03, mixed mode)
$ java -jar JavaApplication5.jar 
""
""
""
""
""
$

我是寻找错误,但我没有想出任何东西。这是一个已知的问题吗?

I've searched for bugs, but I haven't come up with anything. Is this a known problem?

推荐答案

在播放该表示例时似乎有一个以上的错误。

Seems like there is more then one bug when playing with that table example.

我使用了以下SSCCE,它在JDK1.6下按预期工作

I used the following SSCCE which works as expected under 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下但是:

Under JDK1.7 however:


  • 我看到在使表格可编辑时调用 setValueAt 。但是,不是使用空字符串,而是包含在我的 TableModel 中的实际值。这意味着没有任何内容更改为我的数据。唯一令人烦恼的是,在导航过程中我的表不断更新。解决方法当然是在没有更新值时使用快速退出路径调整 setValueAt 方法,例如添加

  • I see the setValueAt being called when making the table editable. However, not with an empty string but with the actual values which are contained in my TableModel. This means that nothing is changed to my data. Only annoying thing is that during the navigation my table is constantly updating. Workaround is of course to adjust the setValueAt method with a quick exit path when the value is not updated at all, e.g adding

if ( ( aValue != null && aValue.equals( getValueAt( row, column ) ) ) ||
     ( aValue == null && getValueAt( row, column ) == null ) ){
  return;
}


  • 使用向上和向下箭头导航使选择跳转2行一次。 Stacktraces显示选择的变化源自 BasicTableUI#Actions 类(这是有意义的,因为这是放置在动作映射中的动作)。奇怪的是,对于一次按键,此动作会被触发两次。这已经解释了为什么选择一次跳2行。进一步的调试显示,一旦我收到两个不同的 KEY_PRESSED 事件,点击我的箭头键。据我所知,这些事件就像 EventQueue 那样,与 JTable 无关。为了确保,我创建了一个小型SSCCE,它不包含 JTable

  • Navigating with the up and down arrows make the selection jump 2 rows at a time. Stacktraces reveal the change in selection originates from the BasicTableUI#Actions class (which makes sense as that is the action which is placed in the action map). The weird thing is that for one key-press this action is triggered twice. That already explains why the selection jumps 2 rows at a time. Further debugging revealed that for hitting my arrow key once I received two distinct KEY_PRESSED events. As far as I can tell, those event are placed like that on the EventQueue and have nothing to do with the JTable. Just to make sure, I created a small SSCCE which does not include a 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 );
       }
     }
    


  • 将焦点放在框架上,然后点击DOWN_ARROW会产生以下输出(剥离 toString 的输出以保持其可读性)

    Giving focus to the frame and then hitting the DOWN_ARROW results in the following output (stripped the output of toString to keep it readable)

    keyevent.getKeyCode() = 40
    ID = 960135925
    keyevent = java.awt.event.KeyEvent[KEY_PRESSED,keyCode=40,...
    keyevent.getKeyCode() = 40
    ID = 1192754471
    keyevent = java.awt.event.KeyEvent[KEY_PRESSED,keyCode=40,...
    keyevent.getKeyCode() = 40
    ID = 2012032999
    keyevent = java.awt.event.KeyEvent[KEY_RELEASED,keyCode=40,...
    

    在这里你可以清楚地看到你得到两个 KEY_PRESSED 的事件会混淆 JTable 。使用常规字符键时不会发生这种情况

    Here you can clearly see that you get two KEY_PRESSED events which confuse the JTable. This does not occur when using a regular character key

    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 :

    Looking at the javadoc in the KeyEvent class:


    KEY_TYPED(只有在可以生成有效的Unicode字符时才会生成。)

    KEY_TYPED (is only generated if a valid Unicode character could be generated.)

    有意义的是,当点击箭头时我不会得到 KEY_TYPED 事件,但它会触发 KEY_PRESSED 两次在我看来是一个错误(稍后会记录一个错误报告)。一个解决方法可能是拦截这样的事件,而不是通过链传递,但这听起来像是一个丑陋的黑客。

    it makes sense I won't get the KEY_TYPED event when hitting the arrow, but that it fires the KEY_PRESSED twice is in my opinion a bug (will log a bug report later on for this). A workaround might be to intercept such an event and not pass it through the chain but that sounds like an ugly hack to me.

    编辑

    另一个奇怪的事情。如果您将以下行添加到代码段

    Another weird thing. If you add the following line to the snippet

    table.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).
      put( KeyStroke.getKeyStroke( 'a' ), "selectNextRow" );
    

    你可以使用 a 跳转到下一行(默认情况下使用DOWN_ARROW触发的操作)。由于按 a 时事件的顺序正确,似乎也没有调用 setValueAt 方法。这让我觉得两个 KEY_PRESSED 事件以某种方式开始编辑......

    you can use the a to jump to the next line (same action as which is triggered by default by using the DOWN_ARROW). Due to the correct sequence of events when pressing a, it seems the setValueAt method is also not called. This makes me think that the two KEY_PRESSED events starts the editing somehow ...

    这篇关于在OS X Lion上使用Java 7中的JTable进行setValueAt的虚假调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆