1

これは私が悩まされているメッセージです。これは、gridキープレスコンボshift-rightarrowまたはshift-leftarrow:

Exception in thread "AWT-EventQueue-0" javax.swing.text.StateInvariantError: 
Bad caret position

shift-uparrow(またはで「選択」しても問題ないことに注意してくださいshift-downarrow。)

「選択した」セルのフォントを変更しようとすると発生します。

  static Font fontSelected = new Font("Serif", Font.BOLD , POINTSIZE);
  static Font fontNormal = new Font("Serif", Font.PLAIN, POINTSIZE);

(Font.type を同じ(両方とも BOLD、両方とも PLAIN、両方とも ITALIC) にすれば、問題ありません。)

エラーは、次のように定義されているスタック (という名前) にpush「選択」したコードの近くで発生します。JTextFieldstack

class GenericStack<E>:
  public LinkedList <E> stack = new LinkedList<>();

スタックとフォントが使用されるクラス宣言は次のとおりです。

public class Grid  extends GenericStack<JTextField> implements ActionListener, KeyListener, KeyCodes, Serializable

にプッシュされるものは次のstackとおりです。

 public static JTextField[][] cells = new JTextField[N][N];

cells作成方法は次のとおりです。

    guiFrame.add(textPanel);
    for (int i = 0; i < N; i++) 
      for (int j = 0; j < N; j++) 
        cells[i][j] = addCell(textPanel, i, j);

  private JTextField addCell (Container parent, int row, int col) {
    JTextField cell;
    cell = new JTextField();
    cell.setFont(fontNormal);                  // 'default' font set
    cell.setText("x");                         // for debugging
    String r, c;                               // 11x11 grid
    if(row < N-1) r = "" + row; else r = "A";  // rows  r: 0,1,2,...A
    if(col < N-1) c = "" + col; else c = "A";  // cols  c: 0,1,2,...A
    cell.setActionCommand(r + c);              // cell rc: 00..0A;10..1A;...A0..AA;
    cell.addKeyListener(this);
    cell.setHorizontalAlignment(JTextField.CENTER);
    parent.add(cell);
    return cell;
  }  

主なものは次のとおりです。

  public static void main(String[] args)
  {    
     javax.swing.SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        new Grid();
      }
    });
  }

フォントが変更される場所は次のとおりです(「選択された」セルの場合):

if(currentCell.selected){
  Grid.cells[currentCell.row][currentCell.col].setBackground(Color.RED);
  Grid.cells[currentCell.row][currentCell.col].setFont(fontSelected);
  stack.push(Grid.cells[currentCell.row][currentCell.col]);
}

このコード ブロックでエラーが発生します。このsetFont行をコメント アウトしても問題ありません。代わりに、同じフォントを含むようにフォント宣言を変更しても問題ありません。

特に困惑しているのは、スタック トレースがエラーの原因となったコード行を特定していないことです。

4

2 に答える 2

2

例外が発生する理由はわかりませんが、Swing イベント スレッドでフォントの変更をキューに入れることで解決できます。

@Override
public void keyPressed(KeyEvent evt) {
  final JComponent comp = (JComponent) evt.getSource();
  int keyCode = evt.getKeyCode();
  boolean shiftIsDown = evt.isShiftDown();
  currentCell.selected = ((shiftIsDown & (keyCode == RIGHT | keyCode == UP
        | keyCode == LEFT | keyCode == DOWN)));
  if (currentCell.selected) {
     SwingUtilities.invokeLater(new Runnable() {
        public void run() {
           comp.setFont(fontSelected);
        }
     });
  }
}

私自身、Swing アプリケーションでは KeyListeners を避けようとしていますが、代わりにキーバインディングを好みます。例えば:

import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;

@SuppressWarnings("serial")
public class SSCCE2 extends JPanel {
   private static final int ROW_COUNT = 11;
   private static final int colCount = 3;
   private static final Font NORMAL_FONT = new Font("Serif", Font.PLAIN, 18);
   private static final Font SELECTED_FONT = NORMAL_FONT.deriveFont(Font.BOLD);

   private JTextField[][] fields = new JTextField[ROW_COUNT][ROW_COUNT];

   public SSCCE2() {
      FontAction fontAction = new FontAction();
      int condition = WHEN_FOCUSED;

      setLayout(new GridLayout(ROW_COUNT, ROW_COUNT));
      for (int i = 0; i < fields.length; i++) {
         for (int j = 0; j < fields[i].length; j++) {
            JTextField cell = new JTextField(colCount);
            InputMap inputMap = cell.getInputMap(condition);
            ActionMap actionMap = cell.getActionMap();
            int[] arrowKeyCodes = {KeyEvent.VK_UP, KeyEvent.VK_DOWN, 
                  KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT};
            for (int keyCode : arrowKeyCodes) {
               KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 
                     KeyEvent.SHIFT_DOWN_MASK);
               inputMap.put(keyStroke, keyStroke.toString());
               actionMap.put(keyStroke.toString(), fontAction);
            }
            cell.setFont(NORMAL_FONT);
            cell.setHorizontalAlignment(JTextField.CENTER);
            add(cell);
            fields[i][j] = cell;
         }
      }


   }

   private class FontAction extends AbstractAction {
      @Override
      public void actionPerformed(ActionEvent evt) {
         for (JTextField[] row : fields) {
            for (JTextField textField : row) {
               if (textField.hasFocus()) {
                  textField.setFont(SELECTED_FONT);
               } else {
                  textField.setFont(NORMAL_FONT);
               }
            }
         }
      }
   }

   private static void createAndShowGui() {
      SSCCE2 mainPanel = new SSCCE2();

      JFrame frame = new JFrame("SSCCE2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
于 2013-10-13T04:46:24.963 に答える
0

メッセージの取得に影響しないカーソル移動コードを含むすべてを削除したため、これを実行するとグリッドが表示され、エラーを取得するには、シフト キーを押しながら右矢印キーを押します。(これは私がすべきことでしたか??) (追伸 -- 一般的なリンク リスト (スタック) のものをすべて取り出しましたが、問題とは何の関係もありませんでした。)

package sscce;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

class Cell 
{
  int row, col;
  boolean selected;

  Cell(int row, int col){
    this.row = row;
    this.col = col;  
  } 
}

public class SSCCE implements ActionListener, KeyListener
{
  public static final int LEFT = 37, UP = 38, RIGHT = 39, DOWN = 40;
  public static final int N = 11;
  JFrame guiFrame;
  JPanel textPanel;
  public static JTextField[][] cells = new JTextField[N][N];
  public static Cell currentCell = new Cell(0,0);

  static Font fontSelected = new Font("Serif", Font.BOLD , 12);
  static Font fontNormal = new Font("Serif", Font.PLAIN, 12);

  public SSCCE(){ 
    textPanel = new JPanel();
    textPanel.setLayout(new GridLayout(N, N));
    guiFrame = new JFrame();
    guiFrame.setMinimumSize(new Dimension(400, 400));
    guiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    guiFrame.setLocationRelativeTo(null);    
    guiFrame.add(textPanel);
    for (int i = 0; i < N; i++) 
      for (int j = 0; j < N; j++) 
        cells[i][j] = addCell(textPanel, i, j);
    guiFrame.setVisible(true);
  }  

  private JTextField addCell (Container parent, int row, int col) {
    JTextField cell;
    cell = new JTextField();
    cell.setFont(fontNormal);
    cell.addKeyListener((KeyListener) this);
    cell.setHorizontalAlignment(JTextField.CENTER);
    parent.add(cell);
    return cell;
  }  

  public static void main(String[] args)
  {    
     javax.swing.SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        new SSCCE();
      }
    });
  }

  @Override
  public void keyPressed(KeyEvent evt) { 
    int keyCode = evt.getKeyCode();
    boolean shiftIsDown = evt.isShiftDown();
    currentCell.selected = ((shiftIsDown & (keyCode == RIGHT | keyCode == UP | keyCode == LEFT | keyCode == DOWN)));
    if(currentCell.selected ){
      SSCCE.cells[currentCell.row][currentCell.col].setFont(fontSelected);
    }
   }
  @Override
  public void keyTyped(KeyEvent e){     }
  @Override
  public void keyReleased(KeyEvent e){  }
  @Override
  public void actionPerformed(ActionEvent e){}
}
于 2013-10-13T01:27:55.217 に答える