java - 根据多个按键更改 jtable 行选择

标签 java swing select keyboard jtable

我有一个 JTable,实际上有 6 列和许多行。现在我想更改选择并通过按键盘上的一个或多个键跳转到该行。

这是我想要的示例:

  • 如果我按键盘上的“S”,我的应用程序应该选择表中的第一行,其中有一个以字符“S”开头的条目。

  • 但是,如果我按两个键“SC”,它应该对以“SC”开头的行执行相同的操作,如上面所示。

  • 当我按另一个键(例如“BHM”)时,它应该对以“BHM”开头的行执行相同的操作,如上所示。

我已经实现了这个,但它不能正常工作

P.S GUI 也会在按键过多后卡住。

这是我的完整代码。

MyTable.java

public class MyTable extends JPanel {

public JScrollPane jScrollPane1;
public JTextField searchField;
public JTable table;
Object[] data = new Object[6];
ArrayList rows = new ArrayList();

MyTable() {
    table = new JTable();
    table.setAutoCreateRowSorter(true);
    table.setModel(new DefaultTableModel(
            new Object[][]{},
            new String[]{
                "Description", "Code", "Qty", "Cost", "Rate", "Packing"
            }
    ) {
        Class[] types = new Class[]{
            String.class, String.class, Integer.class, Double.class, Double.class, String.class
        };
        boolean[] canEdit = new boolean[]{
            false, false, false, false, false, false
        };

        public Class getColumnClass(int columnIndex) {
            return types[columnIndex];
        }

        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return canEdit[columnIndex];
        }
    });

    table.setColumnSelectionAllowed(true);
    table.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
    table.getTableHeader().setReorderingAllowed(false);

    table.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
    if (table.getColumnModel().getColumnCount() > 0) {
        table.getColumnModel().getColumn(0).setMinWidth(300);
        table.getColumnModel().getColumn(0).setPreferredWidth(300);
        table.getColumnModel().getColumn(0).setMaxWidth(1000);
        table.getColumnModel().getColumn(1).setMinWidth(100);
        table.getColumnModel().getColumn(1).setPreferredWidth(100);
        table.getColumnModel().getColumn(1).setMaxWidth(500);
        table.getColumnModel().getColumn(2).setMinWidth(50);
        table.getColumnModel().getColumn(2).setPreferredWidth(50);
        table.getColumnModel().getColumn(2).setMaxWidth(100);
        table.getColumnModel().getColumn(3).setMinWidth(80);
        table.getColumnModel().getColumn(3).setPreferredWidth(80);
        table.getColumnModel().getColumn(3).setMaxWidth(200);
        table.getColumnModel().getColumn(4).setMinWidth(80);
        table.getColumnModel().getColumn(4).setPreferredWidth(80);
        table.getColumnModel().getColumn(4).setMaxWidth(200);
        table.getColumnModel().getColumn(5).setMinWidth(80);
        table.getColumnModel().getColumn(5).setPreferredWidth(80);
        table.getColumnModel().getColumn(5).setMaxWidth(200);
    }
    table.setPreferredScrollableViewportSize(new Dimension(800, 600));
    table.setFillsViewportHeight(true);
    table.setRowHeight(30);
    JScrollPane scrollPane = new JScrollPane(table);
    add(scrollPane);
    table.addKeyListener(new SearchingKeyAdapter(table));
    addRowData();
    table.changeSelection(0, 0, false, false);
}

private static void createAndShowGUI() {
    //Create and set up the window.
    JFrame frame = new JFrame("MyTable");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //Create and set up the content pane.
    MyTable newContentPane = new MyTable();
    newContentPane.setOpaque(true);
    frame.setContentPane(newContentPane);


    //Display the window.
    frame.pack();
    frame.setVisible(true);
}

private void addRowData() {
    String desc = "SL 123";
    Integer code = 12345;
    Integer qty = 10;
    Double rate = new Double(1000);
    Double cost = new Double(900);
    String pack = "10x10x10";
    data[0] = desc;
    data[1] = code;
    data[2] = qty;
    data[3] = cost;
    data[4] = rate;
    data[5] = pack;
    DefaultTableModel model = (DefaultTableModel) table.getModel();
    for (int i = 0; i < 5; i++) {
        data[0] = "SL " + i;
        rows.add(data);
        model.addRow(data);
    }
    rows.clear();
    for (int i = 0; i < 5; i++) {
        data[0] = "SC " + i;
        rows.add(data);
        model.addRow(data);
    }
    data[0] = "AP";
    model.addRow(data);
    data[0] = "GP";
    model.addRow(data);
    data[0] = "PS";
    model.addRow(data);
    data[0] = "PP";
    model.addRow(data);
    data[0] = "BHM";
    model.addRow(data);
    data[0] = "BGP";
    model.addRow(data);
}

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}
}

SearchingKeyAdapter.java

public class SearchingKeyAdapter extends KeyAdapter {

String key = "";
private final JTable table;
private int selectedRow = -1;//before start

public SearchingKeyAdapter(JTable table) {
    this.table = table;
}

@Override
public void keyPressed(KeyEvent e) {
    key += String.valueOf(e.getKeyChar());
}

@Override
public void keyReleased(KeyEvent e) {
    String keyChar = key.toUpperCase();
    key = "";
    TableModel model = table.getModel();
    int startRow = selectedRow;
    if (selectedRow == model.getRowCount() - 1) {
        startRow = -1;//Go before start
    }
    int col = 0;
    for (int row = startRow + 1; row < model.getRowCount(); row++) {
        String value = (String) model.getValueAt(row, col);
        if (value != null && !value.isEmpty() && value.toUpperCase().startsWith(keyChar)) {
            table.getSelectionModel().clearSelection();
            table.getColumnModel().getSelectionModel().clearSelection();
            table.setRowSelectionInterval(row, row);
            table.changeSelection(row, col, false, false);
            selectedRow = row;
            return;
        }
    }
}
}

谢谢!

最佳答案

I have implemented this but it is not working properly

您的示例似乎并未假设所选行是通过箭头键或鼠标单击更改的。

<小时/>

JList 中修改类似的函数可能比创建自己的 KeyListener 更容易。

JList#getNextMatch(...): Returns the next list element whose toString value starts with the given prefix.

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.Position;

public class MyTable2 extends JPanel {
  public JScrollPane jScrollPane1;
  public JTextField searchField;
  public JTable table;
  private final Object[] data = new Object[6];
  private final ArrayList<Object[]> rows = new ArrayList<>();

  private MyTable2() {
    table = new JTable();
    table.setAutoCreateRowSorter(true);
    table.setModel(new DefaultTableModel(
                     new String[] {
                       "Description", "Code", "Qty", "Cost", "Rate", "Packing"
                     }, 0
    ) {
      Class[] types = new Class[] {
        String.class, String.class, Integer.class, Double.class, Double.class, String.class
      };
      @Override public Class getColumnClass(int columnIndex) {
        return types[columnIndex];
      }
      @Override public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false;
      }
    });

    table.setColumnSelectionAllowed(true);
    table.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
    table.getTableHeader().setReorderingAllowed(false);

    table.getColumnModel().getSelectionModel().setSelectionMode(
        ListSelectionModel.SINGLE_SELECTION);
    table.setPreferredScrollableViewportSize(new Dimension(800, 600));
    table.setFillsViewportHeight(true);
    table.setRowHeight(30);

    //table.addKeyListener(new SearchingKeyAdapter(table));
    table.addKeyListener(new TableNextMatchKeyHandler());

    JScrollPane scrollPane = new JScrollPane(table);
    add(scrollPane);
    addRowData();
    table.changeSelection(0, 0, false, false);
  }

  private static void createAndShowGUI() {
    JFrame frame = new JFrame("MyTable");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(new MyTable2());
    frame.pack();
    frame.setVisible(true);
  }

  private void addRowData() {
    String desc = "SL 123";
    Integer code = 12345;
    Integer qty = 10;
    Double rate = new Double(1000);
    Double cost = new Double(900);
    String pack = "10x10x10";
    data[0] = desc;
    data[1] = code;
    data[2] = qty;
    data[3] = cost;
    data[4] = rate;
    data[5] = pack;
    DefaultTableModel model = (DefaultTableModel) table.getModel();
    for (int i = 0; i < 5; i++) {
      data[0] = "SL " + i;
      rows.add(data);
      model.addRow(data);
    }
    rows.clear();
    for (int i = 0; i < 5; i++) {
      data[0] = "SC " + i;
      rows.add(data);
      model.addRow(data);
    }
    data[0] = "AP";
    model.addRow(data);
    data[0] = "GP";
    model.addRow(data);
    data[0] = "PS";
    model.addRow(data);
    data[0] = "PP";
    model.addRow(data);
    data[0] = "BHM";
    model.addRow(data);
    data[0] = "BGP";
    model.addRow(data);
  }

  public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }
}

//@see javax/swing/plaf/basic/BasicListUI.Handler
//@see javax/swing/plaf/basic/BasicTreeUI.Handler
class TableNextMatchKeyHandler extends KeyAdapter {
  private static final int TARGET_COLUMN = 0;
  private static final long TIME_FACTOR = 500L;
  private String prefix = "";
  private String typedString;
  private long lastTime;
  private boolean isNavigationKey(KeyEvent event) {
    JTable table = (JTable) event.getComponent();
    InputMap im = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    KeyStroke key = KeyStroke.getKeyStrokeForEvent(event);
    return Objects.nonNull(im) && Objects.nonNull(im.get(key));
  }
  @Override public void keyPressed(KeyEvent e) {
    if (isNavigationKey(e)) {
      prefix = "";
      typedString = "";
      lastTime = 0L;
    }
  }
  @Override public void keyTyped(KeyEvent e) {
    JTable src = (JTable) e.getComponent();
    int max = src.getRowCount();
    if (max == 0 || e.isAltDown() || isNavigationKey(e)) {
        //|| BasicGraphicsUtils.isMenuShortcutKeyDown(e)) {
      // Nothing to select
      return;
    }
    boolean startingFromSelection = true;
    char c = e.getKeyChar();
    int increment = e.isShiftDown() ? -1 : 1;
    long time = e.getWhen();
    int startIndex = src.getSelectedRow();
    if (time - lastTime < TIME_FACTOR) {
      typedString += c;
      if (prefix.length() == 1 && c == prefix.charAt(0)) {
        // Subsequent same key presses move the keyboard focus to the next
        // object that starts with the same letter.
        startIndex += increment;
      } else {
        prefix = typedString;
      }
    } else {
      startIndex += increment;
      typedString = String.valueOf(c);
      prefix = typedString;
    }
    lastTime = time;

    selectAndScrollNextMatch(src, max, e, prefix, startIndex, startingFromSelection);
  }
  private static void selectAndScrollNextMatch(
      JTable src, int max, KeyEvent e, String prefix,
      int startIndex, boolean startingFromSelection) {
    int start = startIndex;
    boolean isStartingSelection = startingFromSelection;
    if (start < 0 || start >= max) {
      if (e.isShiftDown()) {
        start = max - 1;
      } else {
        isStartingSelection = false;
        start = 0;
      }
    }
    Position.Bias bias = e.isShiftDown() ? Position.Bias.Backward : Position.Bias.Forward;
    int index = getNextMatch(src, prefix, start, bias);
    if (index >= 0) {
      src.getSelectionModel().setSelectionInterval(index, index);
      src.scrollRectToVisible(src.getCellRect(index, TARGET_COLUMN, true));
    } else if (isStartingSelection) { // wrap
      index = getNextMatch(src, prefix, 0, bias);
      if (index >= 0) {
        src.getSelectionModel().setSelectionInterval(index, index);
        src.scrollRectToVisible(src.getCellRect(index, TARGET_COLUMN, true));
      }
    }
  }
  //@see javax/swing/JList#getNextMatch(String prefix, int startIndex, Position.Bias bias)
  //@see javax/swing/JTree#getNextMatch(String prefix, int startIndex, Position.Bias bias)
  public static int getNextMatch(
      JTable table, String prefix, int startingRow, Position.Bias bias) {
    int max = table.getRowCount();
    if (Objects.isNull(prefix) || startingRow < 0 || startingRow >= max) {
      throw new IllegalArgumentException();
    }
    String uprefix = prefix.toUpperCase(Locale.ENGLISH);

    // start search from the next/previous element froom the
    // selected element
    int increment = bias == Position.Bias.Forward ? 1 : -1;
    int row = startingRow;
    do {
      Object value = table.getValueAt(row, TARGET_COLUMN);
      String text = Objects.toString(value, "");
      if (text.toUpperCase(Locale.ENGLISH).startsWith(uprefix)) {
        return row;
      }
      row = (row + increment + max) % max;
    } while (row != startingRow);
    return -1;
  }
}

关于java - 根据多个按键更改 jtable 行选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41724510/

相关文章:

jquery,选择器,查找,文本

java - com.sun.jersey 和 org.glassfish.jersey 的区别

Java线程内部

java - 测量单位 API (JSR-363) - 浮点错误

Java - 设置装饰 JFrame 的大小

mysql - 如何从多个表中选择同一列

java - 未知错误阻止子类的构造

java - 如何在JPanel中查看BufferedImage?

java - 我应该如何针对不同的分辨率缩放菜单大小?

php - 使用 Symfony 和 Doctrine 按月和年检索项目