Лентата за превъртане на JScrollPane не се появява, докато не се извика rowSorter.toggleSortOrder()

Забелязах, че когато имам JTable с TableRowSorter, съдържащ се от JScrollPane, вертикалната лента за превъртане не се появява, докато не създам SortKeys за сортирача (което се прави чрез извикване на toggleSortOrder() за една от колоните).

Въпросът ми е наистина защо? Какво общо имат SortKeys с вертикалната лента за превъртане?

Актуализация: Добавен е SSCCE, който отваря JFrame с JTable в JScrollPane, който се намира в контейнер заедно с бутон „Попълване“. Когато таблицата е първоначално нарисувана, няма данни и следователно няма нужда от лента за превъртане. След като го попълня с 20 реда, има нужда от лента за превъртане, но не се появява.

Има два начина да направите лентата за превъртане да се показва:

  • Щракнете върху някоя от клетките на заглавката, за да предизвикате сортиране.
  • Премахнете коментираното извикване toggleSortOrder() в метода refresh() на контейнера.

    // table.getRowSorter().toggleSortOrder(0);

toggleSortOrder() извиквания setSortKeys() извиквания sort() извиквания fireRowSorterChanged() и в крайна сметка нещо хваща събитието и добавя лентата за превъртане.

package test;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.WindowConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;

@SuppressWarnings("serial")
public class TestFrame extends JFrame
{
    class MyTableModel extends AbstractTableModel
    {
        public List<String> names = new ArrayList<String>();

        public int getRowCount ()
        {
            return names.size();
        }

        public int getColumnCount ()
        {
            return 2;
        }

        public String getColumnName (int columnIndex)
        {
            return columnIndex > 0 ? "Name" : "Number";
        }

        public Class<?> getColumnClass (int columnIndex)
        {
            return String.class;
        }

        public Object getValueAt (int row, int col)
        {

            return row < names.size() ? col == 0 ? Integer.toString(row) : names.get(row) : "";
        }

        public void refresh (List<String> names)
        {
            this.names = names;
        }
    }

    class MyContainer extends java.awt.Container implements ActionListener
    {
        JTable                               table;
        MyTableModel                         model = new MyTableModel();
        private TableRowSorter<MyTableModel> sorter;

        public MyContainer()
        {
        }

        public void init ()
        {
            sorter = new TableRowSorter<MyTableModel>(model);
            table = new JTable(model);
            table.setBorder(BorderFactory.createEmptyBorder());
            table.setRowHeight(35);
            table.getTableHeader().setPreferredSize(new Dimension(200, 35));
            table.setRowSorter(sorter);
            table.setPreferredScrollableViewportSize(new Dimension(200, 70));
            table.setFillsViewportHeight(true);
            table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            //Create the scroll pane and add the table to it.
            JScrollPane scrollPane = new JScrollPane(table);
            scrollPane.setBounds(10, 10, 200, 210);

            //Add the scroll pane to this panel.
            add(scrollPane);
            JButton btn = new JButton("Populate");
            btn.setActionCommand("populate");
            btn.addActionListener(this);
            btn.setBounds(10, 220, 200, 35);
            add(btn);
        }

        public void refresh (List<String> rows)
        {
            model.refresh(rows);
            try
            {
                // Notify sorter that model data (possibly number of rows) has changed.
                // Without this call, the sorter assumes the number of rows is the same.
                table.getRowSorter().allRowsChanged();
                // Do we really want to toggle the sort order every time we refresh?
                // User can toggle the sort order himself by clicking on the 
                // appropriate header cell.
                List<?> keys = table.getRowSorter().getSortKeys();
                if (null == keys || keys.isEmpty())
                {
//                    table.getRowSorter().toggleSortOrder(0);
                }
            } catch (Exception e)
            {
                e.printStackTrace();
            }
            table.repaint();
        }

        public void actionPerformed(ActionEvent e)
        {
            if ("populate".equals(e.getActionCommand()))
            {
                List<String> rows = new ArrayList<String>();
                for (int ii = 0; ii < 20; ii++)
                {
                    rows.add(String.format("%02d", new Integer(ii)));
                }
                refresh(rows);
            }
        }

        MyTableModel getModel ()
        {
            return model;
        }
    }

    public static void main (String args[])
    {
        new TestFrame();
    }

    MyContainer myContainer = new MyContainer();

    TestFrame() 
    {
        myContainer.init();
        myContainer.table.getSelectionModel().clearSelection();
        add(myContainer);
        this.setSize(240, 310);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //pack();
        setVisible(true);
    }

}

person Robert White    schedule 24.07.2014    source източник
comment
споделете вашия примерен код за ясна картина, защото проблемът е скрит някъде в самия ви код.   -  person Braj    schedule 24.07.2014
comment
My question is really why? имате грешка в кода си. RowSorter няма нищо общо с лентата за превъртане. Публикувайте своя SSCCE, който демонстрира проблема.   -  person camickr    schedule 24.07.2014


Отговори (1)


Е, това всъщност не е SSCCE, защото използвате персонализиран TableModel. Ако сте създали подходящ SSCCE, ще използвате DefaultTableModel, така че да тествате кода си със стандартни JDK класове. Ако сте направили това, щяхте да забележите, че кодът ще работи.

Тогава следващата ви стъпка ще бъде да опитате кода с вашия персонализиран TableModel и ще забележите, че кодът не работи.

Тогава вашият въпрос във форума ще бъде защо кодът не работи с моя персонализиран TableModel? Целта на SSCCE е да извърши основно отстраняване на грешки, за да изолира къде се случва грешката, така че да имаме информация, с която да работим. В първоначалния ви въпрос нямахме представа къде използвате персонализирани класове.

Както и да е, проблемът е, че вашият персонализиран TableModel не уведомява таблицата, когато се направи промяна в данните. Във вашия refresh(...) метод трябва да добавите следното, след като нулирате списъка, съдържащ данните:

  fireTableRowsInserted(0, names.size()-1);

Няма нужда от table.repaint() във вашия код.

person camickr    schedule 25.07.2014
comment
Според връзката, която предоставихте по-рано, SSCCE трябва да се увери, че примерът е правилен. Или примерът се компилира чисто, или предизвиква точното съобщение за грешка, което трябва да бъде разрешено. Би било безсмислено да включвам пример, който решава проблема, за чието разрешаване ми трябваше вашият опит. Остава въпросът какво общо имат SortKeys с вертикалната лента за превъртане? Методите sort() и sortExistingData() извикват fireRowSorterChanged(), а не fireTableRowsInserted(), което беше по-добрият метод, който се използваше. Заключавам, че JScrollPane е TableModelListener и RowSorterListener. - person Robert White; 25.07.2014
comment
It would have been pointless to include an example that solved the problem, - НЕ казах това. Казах, че трябва да научите как да правите някои основни отстраняване на грешки, ПРЕДИ да публикувате въпрос. След това заявявате какво сте забелязали, вместо широко отворен въпрос, който пита какво може да не е наред. Така че въпросът ви трябваше да бъде нещо като: When I use my custom TableModel the code doesn't work и вие включвате кода с вашия персонализиран TableModel. Така че сега прекарваме по-малко време в разглеждане на целия ви друг код и се концентрираме върху TableModel. - person camickr; 26.07.2014
comment
which was the better method to have used - използвате подходящия метод, който отговаря на ситуацията. В кода, който сте публикували тук, вие добавяте нови редове от данни към модела. Когато използвате RowSorter, вие сортирате съществуващи редове. - person camickr; 26.07.2014