そのテーブルの例で遊んでいると、複数のバグがあるようです。
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_PRESSED
、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を見る:
KEY_TYPED (有効な Unicode 文字を生成できる場合にのみ生成されます。)
KEY_TYPED
矢印を叩いたときにイベントが発生しないのは理にかなっていますが、 KEY_PRESSED
2回発生するのは私の意見ではバグです(これについては後でバグレポートを記録します)。回避策は、そのようなイベントをインターセプトし、チェーンを通過させないことかもしれませんが、それは私には醜いハックのように思えます。
編集
もう一つの奇妙なこと。次の行をスニペットに追加すると
table.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).
put( KeyStroke.getKeyStroke( 'a' ), "selectNextRow" );
を使用a
して次の行にジャンプできます (DOWN_ARROW を使用してデフォルトでトリガーされるアクションと同じ)。を押したときのイベントの順序が正しいためa
、setValueAt
メソッドも呼び出されないようです。KEY_PRESSED
これは、2つのイベントが何らかの形で編集を開始すると思わせます...