Pick up Jtable’s line after Filtering Data

Asked

Viewed 1,100 times

2

I’m wearing a TableModel(not the DefaultTableModel) which I populate with data from banco (MySQL), I also use a Class to filter through what I type into a JTextField. It is working correctly, but I would like to, after performing the filtering through the data entered in JTextField be able to select only the data that "remained" in the JTable. Because until now I select the first line after the filter,and I have as return the first line of the original model ( through the event mouseClicked). The image below illustrates perhaps more clearly:

inserir a descrição da imagem aqui

I believe you must somehow "create a new modelo with the resulting data after the filter". Can anyone help adapt this same class, or with information so that I can achieve my goal? Thank you very much!

Class to make the filter:

package Converter;

import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.table.TableRowSorter;
import org.jdesktop.beansbinding.Converter;


public class RowSorterToStringConverter extends Converter {

    private JTable table;

    public JTable getTable() {
        return table;
    }

    public void setTable(JTable table) {
        this.table = table;
    }

    @Override
    public Object convertForward(Object value) {
        return value.toString();
    }

    @Override
    public Object convertReverse(Object mask) {
        TableRowSorter sorter = new TableRowSorter(table.getModel());

        String m = mask.toString();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < m.length(); i++) {
            char c = m.charAt(i);
            sb.append('[').append(Character.toLowerCase(c)).append(Character.toUpperCase(c)).append(']');
        }
        sorter.setRowFilter(RowFilter.regexFilter(".*" + sb + ".*"));
        return sorter;
    }
}

Linking of JTextField with the Classe RowSorter

inserir a descrição da imagem aqui

Mouse event:

private void jtableCLicked() {
        saveButton.setEnabled(false);
        Condutor condutor = modelo.getCondutor(jTableCondutor.getSelectedRow());
        condutorIdField.setText((String.valueOf(condutor.getId())));
        condutorNomeField.setText(condutor.getNome());
        jCSetorDescr.setSelectedItem(condutor.getSetor());
        jCPessoaDescr.setSelectedItem(condutor.getPessoa());
        jCEmpresaDescr.setSelectedItem(condutor.getEmpresa());
        jCStatusDescr.setSelectedItem(condutor.getStatus());
        botoesEdicao();

    }

Update:

I’ve made the following changes:

 private void jTextFieldBuscaKeyReleased(java.awt.event.KeyEvent evt) {                                            
        String stringBusca = jTextFieldBusca.getText();
        filter(stringBusca);
    }                                           
    private void filter(String stringBusca) {
        TableRowSorter<TableModel> tr = new TableRowSorter<TableModel>(modelo);
        jTableCondutor.setRowSorter(tr);
        tr.setRowFilter(RowFilter.regexFilter(stringBusca));
    }

    private void jtableCLicked() {
        if (jTableCondutor.getRowSorter() != null) {
            try {
                int rowSel = jTableCondutor.getSelectedRow();
                int indexRowModel = jTableCondutor.getRowSorter().convertRowIndexToModel(rowSel);
                Condutor condutor = modelo.getCondutor(indexRowModel);
                condutorIdField.setText((String.valueOf(condutor.getId())));
                condutorNomeField.setText(condutor.getNome());
                jCSetorDescr.setSelectedItem(condutor.getSetor());
                jCPessoaDescr.setSelectedItem(condutor.getPessoa());
                jCEmpresaDescr.setSelectedItem(condutor.getEmpresa());
                jCStatusDescr.setSelectedItem(condutor.getStatus());
                botoesEdicao();
            } catch (Exception e) {
                System.out.println("Erro " + e.getMessage());
            }

        }
        else{
            try{
             Condutor condutor = modelo.getCondutor(jTableCondutor.getSelectedRow());
                condutorIdField.setText((String.valueOf(condutor.getId())));
                condutorNomeField.setText(condutor.getNome());
                jCSetorDescr.setSelectedItem(condutor.getSetor());
                jCPessoaDescr.setSelectedItem(condutor.getPessoa());
                jCEmpresaDescr.setSelectedItem(condutor.getEmpresa());
                jCStatusDescr.setSelectedItem(condutor.getStatus());
                botoesEdicao();
            } catch (Exception e) {
                System.out.println("Erro " + e.getMessage());
            }
        }
    }

Now it’s all the way I needed it, except that after performing a filter, in this case only "a few lines in the JTable ,"if I edit a row (a objeto Conductor) occurs to Exception:

java.lang.IndexOutOfBoundsException:invalid range

After editing call these two methods:

 public void limpaLista() {
        if (condutores.size() > 0) {
            int i = condutores.size();
            condutores.clear();
            fireTableRowsDeleted(0, i - 1);
        }
    }

public void preencherTabela() {
        CondutorDao condutorDao = new CondutorDao();
        modelo.adicionaLista(condutorDao.consultarCondutores());
    }

Update 2:

I created these code snippets:

 private void jTBuscarRegistroKeyReleased(java.awt.event.KeyEvent evt) {                                             
        tr.setRowFilter(RowFilter.regexFilter("(?i)" + jTBuscarRegistro.getText()));
    }                                            

    class MyListSelectionListener implements ListSelectionListener {

        @Override
        public void valueChanged(ListSelectionEvent e) {
            ListSelectionModel lsm = (ListSelectionModel) e.getSource();
            if (!lsm.isSelectionEmpty()) {

                try {
                    int rowSel = jTableCondutor.getSelectedRow();
                    int indexRowModel = jTableCondutor.getRowSorter().convertRowIndexToModel(rowSel);
                    Condutor condutor = modelo.getCondutor(indexRowModel);
                    condutorIdField.setText((String.valueOf(condutor.getId())));
                    condutorNomeField.setText(condutor.getNome());
                    jCSetorDescr.setSelectedItem(condutor.getSetor());
                    jCPessoaDescr.setSelectedItem(condutor.getPessoa());
                    jCEmpresaDescr.setSelectedItem(condutor.getEmpresa());
                    jCStatusDescr.setSelectedItem(condutor.getStatus());
                    botoesEdicao();
                } catch (Exception ee) {
                    System.out.println("Erro Ao Carregar Dados " + ee.getMessage());
                }

            }
        }
    ;

    }

And at the builder:

jTableCondutor.setRowSorter(tr);
        jTableCondutor.getSelectionModel().addListSelectionListener(new MyListSelectionListener());

Now it worked properly, without Exception, can select after the filter, and when cleaning the JTextField of the search, returns the original model with the changes made in the lines.

  • In this answer I’ll explain something similar, see if you can understand and adapt. If you can’t, add a [mcve] so you can try to create something testable for the posted code.

  • Just to see if I understood you, in this post you indicated deals with the case of selecting the line after doing the filter, because in my code is doing the search correctly, I just can’t select the data after the filter, always selects data according to the model loaded the first time. Thank you.

1 answer

0


To recover the selected line in a JTable, you need to call the method convertRowIndexToModel, passing the index of the row selected in the table as parameter, something like this:

int rowSel = suaTable.getSelectedRow();//pega o indice da linha na tabela
int indexRowModel = suaTable.getRowSorter().convertRowIndexToModel(rowSel);//converte pro indice do model

This way you avoid problems with IndexOfBoundException when trying to manipulate table row indices.

Supposing modelo.getCondutor be some method of your TableModel retrieving an object from the index passed, pass the indexRowModel as a parameter:

private void jtableCLicked() {
        ...

        int rowSel = suaTable.getSelectedRow();
        int indexRowModel = suaTable.getRowSorter().convertRowIndexToModel(rowSel);
        Condutor condutor = modelo.getCondutor(indexRowModel);

        ...
    }

How you want to pick the selected row as long as one is selected in the table, rather than using a Listener of mouse clicks that may not work if the user changes the selected line via the keyboard, a better solution is to override the method valueChanged, adding a ListSelectionlistener at your table:

suaTable.getSelectionModel().addListSelectionListener(new ListSelectionListener(){

    @Override
    public void valueChanged(ListSelectionEvent e) {

        ListSelectionModel lsm = (ListSelectionModel) e.getSource(); 

        if(!lsm.isSelectionEmpty()){

        //aqui você insere a ação que quer fazer quando
        //uma linha for selecionada ou uma seleção for
        //alterada na tabela
        }
    }
}

This way, if a selection is made or changed, regardless of whether it was performed by mouse click or by the arrow keys, it will call this method.

Reference:

How to Write a List Selection Listener(oracle)

  • I get it, I need to create a rowSorteror do I continue to use the class I was already using? I get paid null here: int indexRowModel = jTableCondutor.getRowSorter().convertRowIndexToModel(rowSel);while trying to execute.

  • @Rodrigo in his code, the method convertReverse returns a Tablerowsorter, are you assigning to your table this rowsorter? If it has not assigned, it will return null even.

  • @ diegofm , I did so: I have the class rowSorterToStringConverter, dragged into the form, linked the jTextfield to that rowSorterpara poder fazer o "filter". Nas propriedades dorowSorterStringConverterna opçãotablevinculei a jTableConducer`.

  • I made some progress, could you please review my update above? Thanks.

  • @Rodrigo why Else? If you apply a Rowsorter and when you click a line, return null, it is because there is some other problem in your code. Without converting the Index as I explained in the answer, this type of error is subject to happening, since the Index of the view(table) is not always the same as the model. Not counting the risk of you editing an object totally different from the selected one. If possible, enter a [mcve] so that it is possible to test and reproduce the problem.

  • @ diegofm added code snippets, I think it’s solved unless I’ve done it in an unwise way.

  • @Rodrigo inside the selectionListener works without the range error? I think the problem was in Else even, because there, you were taking information from the view, and going to the model. When you filter, the Dice changes to view, hence the error. Apply rowsorter always at table startup, then when filter is done rowsorter will not return null. Note that, using click event, until you click the table header, you will enter the method (which may be the cause of the previous problem), but in Lection, you will only enter if a line is selected.

  • @ diegofm Yes, without the Range error. I also changed the jTBuscarRegistro of keyReleased for jTBuscarRegistro.getDocument().addDocumentListener(new DocumentListener());, because with the evento did not recharge the modelin jTable when I pressed the button "limparjTBuscarRegistro". Now everything is working correctly (of course you still have a lot to do in this project). Thank you

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.