6

Lion と Java 7 にアップグレードした後、JTables で問題が発生しています。矢印キーを使用して選択範囲を移動する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 + "\"");
    }
}

Java 6で実行し、矢印キーを使用して移動すると。それは正常に動作します。例えば

$ 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 

setValueAt()ただし、Java 7 (Lion) で実行し、矢印キーで選択範囲を移動すると、空の文字列で呼び出されます。

例えば

$ 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 
""
""
""
""
""
$

バグを検索しましたが、何も思いつきませんでした。これは既知の問題ですか?

4

3 に答える 3

1

そのテーブルの例で遊んでいると、複数のバグがあるようです。

JDK1.6で期待どおりに動作する次のSSCCEを使用しました

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 では:

  • setValueAtテーブルを編集可能にするときに呼び出されるのがわかります。ただし、空の文字列ではなく、 my に含まれる実際の値を使用しますTableModel。これは、私のデータには何も変更されていないことを意味します。唯一厄介なことは、ナビゲーション中にテーブルが常に更新されていることです。回避策はもちろんsetValueAt、値がまったく更新されない場合、クイック終了パスを使用してメソッドを調整することです。

    if ( ( aValue != null && aValue.equals( getValueAt( row, column ) ) ) ||
         ( aValue == null && getValueAt( row, column ) == null ) ){
      return;
    }
    
  • 上矢印と下矢印でナビゲートすると、選択範囲が一度に 2 行ずつジャンプします。スタック トレースは、選択の変更がクラスに起因することを明らかにしますBasicTableUI#Actions(これは、アクション マップに配置されるアクションであるため、理にかなっています)。奇妙なことに、キーを 1 回押すと、このアクションが 2 回トリガーされます。これで、選択範囲が一度に 2 行ジャンプする理由がすでに説明されています。KEY_PRESSEDさらにデバッグすると、2 つの異なるイベントを受け取ったときに矢印キーを押すことが明らかになりました。私が知る限り、これらのイベントはそのように に配置され、EventQueueとは何の関係もありませんJTable。念のため、以下を含まない小さな SSCCE を作成しました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読みやすいように の出力を取り除いています) 。

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_PRESSEDJTable. これは、通常の文字キーを使用する場合には発生しません

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を見る:

KEY_TYPED (有効な Unicode 文字を生成できる場合にのみ生成されます。)

KEY_TYPED矢印を叩いたときにイベントが発生しないのは理にかなっていますが、 KEY_PRESSED2回発生するのは私の意見ではバグです(これについては後でバグレポートを記録します)。回避策は、そのようなイベントをインターセプトし、チェーンを通過させないことかもしれませんが、それは私には醜いハックのように思えます。

編集

もう一つの奇妙なこと。次の行をスニペットに追加すると

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

を使用aして次の行にジャンプできます (DOWN_ARROW を使用してデフォルトでトリガーされるアクションと同じ)。を押したときのイベントの順序が正しいためasetValueAtメソッドも呼び出されないようです。KEY_PRESSEDこれは、2つのイベントが何らかの形で編集を開始すると思わせます...

于 2012-11-15T22:44:43.087 に答える
0

これを回避するには、次を使用します。

putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);

ただし、この場合、直接入力してセルの編集を開始することはできません。編集を開始するには、マウスを使用する必要があります。Oracle http://bugs.sun.com/view_bug.do?bug_id=9006933にもバグを発行しましたが、それも利用できません...システムに問題があるようです。

于 2013-09-20T11:31:15.190 に答える
0

JTable セルをカーソル キーで移動すると、1.7.0_40 でこの問題がまだ発生します。これにより、すべてのフィールドが空白になります。

追加:

table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE)

その問題の発生を停止しますが、編集を開始するには「Enter」キーを押す必要があります。

代わりに、Jtables モデルの開始時に空の文字列をチェックし、問題を回避します。

すなわち

 if(Platform.isOSX())
        {
            if(value.equals(""))
            {
                return;
            }
        }

ただし、これは、ユーザーが実際にフィールドを空にしたい場合、変更が拒否されることを意味します。私自身のアプリケーションでは、別の deleteField() アクションを使用しているため、このような問題はありません。

この問題は、こちらの OpenJdk バグ トラッカーで確認できます。

https://bugs.openjdk.java.net/browse/JDK-8025126

現在、Jdk 9まで修正する予定はありません

于 2013-10-30T12:29:18.633 に答える