【问题标题】:JTable move screen/pointer to search textJTable 移动屏幕/指针以搜索文本
【发布时间】:2018-10-23 19:58:12
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: java swing jtable


    【解决方案1】:

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

    ✓ 每次搜索 1 次(此外只有 1 次突出显示)。

    ✓ 滚动找到的值。

    ✓ 没有搜索时会发出哔哔声。

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

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

    预览:

    代码中有一些额外的 cmets。

    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);
                }
            });
        }
    }
    

    【讨论】:

    • 我没有选择,我正在使用 mac。
    • @Prajitha 你的意思是什么?当您选择了第 4 行,但您搜索在第 100 行中找到的内容时,选择停留在第 4 行,但您会看到第 100 行。
    • @Prajitha 如果要选择搜索到的值,删除 selRow 变量,以及 t.setRowSelectionInterval(selRow, selRow) 行;选择将停留在搜索的文本上。
    • 对不起,我的错误,它工作正常。快速提问,一旦到达表格底部并继续搜索,我如何动态添加 1000 多条记录?只是想在这里复制分页...
    • @Prajitha 我不明白你到底在问什么。我在表的模型中添加了 500 多条记录,然后继续搜索。
    猜你喜欢
    • 2018-08-12
    • 1970-01-01
    • 2012-07-31
    • 1970-01-01
    • 1970-01-01
    • 2015-11-08
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    相关资源
    最近更新 更多