java - JTable 移动屏幕/指针来搜索文本

标签 java swing jtable

我需要突出显示文本并将整个屏幕/ View 移动到搜索的文本。例如:如果 View 包含 1 到 1000 个数字(行),如果我输入搜索文本 55 并单击“搜索”按钮,首先它必须将屏幕移动到文本 55(第一次出现),然后应该仅突出显示 55,而不是其他出现的 55。当我按住“搜索”按钮时,搜索应进一步进行并突出显示 155,然后突出显示 255、355、455、555 等。一次只能突出显示一个 55。

它应该具有与记事本相同的搜索体验。

这是一个有效的用例吗?我是 Swings 的新手,尝试构建一个小型应用程序作为学习的一部分。已经编写了示例代码(引用了其他帖子),但这一次突出显示了所有出现的情况,并且不确定如何将 View 移动到第一个出现的情况。请提出建议。

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Form extends JFrame {

    private String textForSearch = "";
    private JTable t;

    public Form() {

        t = new JTable();

        String[] headers = new String[]{"first", "second", "third"};
        DefaultTableModel model = new DefaultTableModel(0, 0);
        model.setColumnIdentifiers(headers);

        for(int i =0;i<1000;i++){
            model.addRow(new Object[]{i});
            model.addRow(new Object[]{i});
        }

        t.setModel(model);

        for(int i =0;i<t.getColumnCount();i++){
            t.getColumnModel().getColumn(0).setCellRenderer(getRenderer());
        }

        JScrollPane jsp = new JScrollPane(t);
        final RightPanel right = new RightPanel();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        add(jsp, BorderLayout.CENTER);
        add(right, BorderLayout.EAST);
        pack();
        setLocationRelativeTo(null);
    }

    private TableCellRenderer getRenderer() {
        return new TableCellRenderer() {
            JTextField f = new JTextField(5);

            @Override
            public Component getTableCellRendererComponent(JTable arg0, Object arg1, boolean arg2, boolean arg3, int arg4, int arg5) {
                if(arg1 != null){
                    f.setText(arg1.toString());
                    String string = arg1.toString();
                    if(string.contains(textForSearch)){
                        int indexOf = string.indexOf(textForSearch);
                        try {
                            f.getHighlighter().addHighlight(indexOf,indexOf+textForSearch.length(),new javax.swing.text.DefaultHighlighter.DefaultHighlightPainter(Color.RED));
                        } catch (BadLocationException e) {
                            e.printStackTrace();
                        }
                    }
                } else {
                    f.setText("");
                    f.getHighlighter().removeAllHighlights();
                }
                return f;
            }
        };
    }

    class RightPanel extends JPanel{

        public RightPanel(){
            setLayout(new GridBagLayout());
            GridBagConstraints c = new GridBagConstraints();
            c.insets = new Insets(5, 5, 5, 5);
            c.gridy = 0;
            final JTextField f = new JTextField();
            add(f,c);
            JButton b = new JButton("search");
            b.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {
                    textForSearch = f.getText();
                    t.repaint();
                }
            });
            c.gridy++;
            add(b,c);
        }
    }

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                new Form().setVisible(true);
            }
        });
    }
}

编辑: 从其他帖子中,找到了将指针/屏幕移动到特定行的解决方案,但不确定如何获取搜索文本的 rowIndex 值:

public static void scrollToVisible(JTable table, int rowIndex, int vColIndex) {
    if (!(table.getParent() instanceof JViewport)) return;
    JViewport viewport = (JViewport) table.getParent();
    Rectangle rect = table.getCellRect(rowIndex, vColIndex, true);
    Point pt = viewport.getViewPosition();
    rect.setLocation(rect.x - pt.x, rect.y - pt.y);
    viewport.scrollRectToVisible(rect);
}

添加供其他人引用:

在屏幕中间显示所选行: http://www.java2s.com/Code/Java/Swing-JFC/ScrollingaCelltotheCenterofaJTableComponent.htm

最佳答案

我想我已经成功地做到了你想要的,就像你说的Notepad++搜索之类的。不要使用 new JTextField() 作为渲染器,只需扩展 JTextField 并实现 TableCellRenderer。然后在您的操作监听器中,找到具有该值的单元格的索引,并让渲染器仅突出显示该单元格。

✓ 每次搜索 1 次(而且仅突出显示 1 次)。

✓ 滚动找到的值。

✓ 没有搜索时发出蜂鸣声。

✓ 从头开始​​时会发出蜂鸣声。

✓ 搜索后不会丢失选择(您可以更改它)

预览: enter image description here

代码中的一些额外注释。

package test;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Form extends JFrame {

    private String textForSearch = "";
    private JTable t;
    private static int rowIndex = -1;
    public Form() {

        t = new JTable();

        String[] headers = new String[]{"first", "second", "third"};
        DefaultTableModel model = new DefaultTableModel(0, 0);
        model.setColumnIdentifiers(headers);

        for(int i =0;i<1555;i++){
            model.addRow(new Object[]{i});
        }

        t.setModel(model);

        for(int i =0;i<t.getColumnCount();i++){
            t.getColumnModel().getColumn(0).setCellRenderer(new MyTextFieldRenderer()); //Add JTextField as renderer
        }
        JScrollPane jsp = new JScrollPane(t);
        final RightPanel right = new RightPanel();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        add(jsp, BorderLayout.CENTER);
        add(right, BorderLayout.EAST);
        pack();
        setLocationRelativeTo(null);
    }

    private class MyTextFieldRenderer extends JTextField implements TableCellRenderer{

        @Override
        public Component getTableCellRendererComponent(JTable arg0, Object arg1, boolean arg2, boolean arg3, int row,
                int col) {
            String string = String.valueOf(arg1);
            this.setText(string);
            if(row == rowIndex) //Check if the row of the found text matches this value
            {
                int indexOf = getText().indexOf(textForSearch);
                try {
                    getHighlighter().addHighlight(indexOf, indexOf + textForSearch.length(),
                            new javax.swing.text.DefaultHighlighter.DefaultHighlightPainter(Color.RED));
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
            return this;
        }

    }
    class RightPanel extends JPanel{

        public RightPanel(){
            setLayout(new GridBagLayout());
            GridBagConstraints c = new GridBagConstraints();
            c.insets = new Insets(5, 5, 5, 5);
            c.gridy = 0;
            final JTextField f = new JTextField(11);
            add(f,c);
            JButton b = new JButton("search");
            b.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {
                    //Start all over again
                    int tempRow = rowIndex;
                    if (rowIndex + 1 >= t.getRowCount())
                    {
                        rowIndex = -1;
                        Toolkit.getDefaultToolkit().beep(); //Notepad++ beeps i think
                    }
                    for (int row = rowIndex+1; row < t.getRowCount(); row++) { //Start checking all rows
                        Component cc = t.prepareRenderer(t.getCellRenderer(row, 0), row, 0);
                        if (cc instanceof MyTextFieldRenderer) {
                            MyTextFieldRenderer textField = (MyTextFieldRenderer) cc; //Grab the text of the renderer
                            if (textField.getText().contains(f.getText())) { //We got a match!
                                textForSearch = f.getText();
                                rowIndex = row;
                                int selRow = t.getSelectedRow();
                                //Selection code taken from here:
                                //https://stackoverflow.com/questions/853020/jtable-scrolling-to-a-specified-row-index/6229040#6229040
                                t.getSelectionModel().setSelectionInterval(row, row); //Scroll to the value
                                t.scrollRectToVisible(new Rectangle(t.getCellRect(row, 0, true)));
                                if (selRow!=-1) //Something was selected
                                    t.setRowSelectionInterval(selRow, selRow); //Restore selection
                                break;
                            }
                        }
                    }
                    if (rowIndex == tempRow) //Index didn't change, means there is no value for this search
                    {
                        Toolkit.getDefaultToolkit().beep();
                    }
                    t.repaint();
                }
            });
            c.gridy++;
            add(b,c);
        }
    }
    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                new Form().setVisible(true);
            }
        });
    }
}

关于java - JTable 移动屏幕/指针来搜索文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50325546/

相关文章:

java - 如何在java中将字符串(例如0d-2或9.9d-1)转换为 float 0.00或0.99

java - 我所有的 java 应用程序现在都会抛出 java.awt.headlessException

java - 如何给jtable设置值?

java - 如何关闭后窗

java - 编辑单元格时刷新行

java - 获取 ID 并在 Jtable 上显示详细信息

java - 传统的开源 Java 应用程序

java - 数组内存泄漏

java - 在 CoolBar 中添加自定义小部件?

java - 如何在jtable中添加列值