JTable с динамическим JPopupMenu - PullRequest
0 голосов
/ 15 ноября 2018

Я пытаюсь кодировать контекстное меню, которое меняет свои пункты в зависимости от строки. Проблема в том, что я не могу его обновить. Вот рабочий пример:

package jframe.jTable;

import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class TestTableRightClick {
    JPopupMenu popupMenu;

    protected void initUI() {
        final JFrame frame = new JFrame(TestTableRightClick.class.getSimpleName());
        Vector<String> columns = new Vector<String>(Arrays.asList("Name", "Age"));
        Vector<Vector<String>> data = new Vector<Vector<String>>();
        for (int i = 0; i < 50; i++) {
            Vector<String> row = new Vector<String>();
            for (int j = 0; j < columns.size(); j++) {
                row.add("Cell " + (i + 1) + "," + (j + 1));
            }
            data.add(row);
        }
        JTable table = new JTable(data, columns);
        popupMenu = new JPopupMenu();

        popupMenu.addPopupMenuListener(new PopupMenuListener() {

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                //int rowAtPoint = table.rowAtPoint(SwingUtilities.convertPoint(popupMenu, new Point(0, 0), table));
                //generateTablePopupMenu(rowAtPoint);

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        int rowAtPoint = table.rowAtPoint(SwingUtilities.convertPoint(popupMenu, new Point(0, 0), table));
                        generateTablePopupMenu(rowAtPoint);
                        if (rowAtPoint > -1) {
                            table.setRowSelectionInterval(rowAtPoint, rowAtPoint);
                        }
                    }
                });
            }

            private void generateTablePopupMenu(int rowAtPoint) {
                System.out.println(rowAtPoint);
                popupMenu.removeAll();
                if ( (rowAtPoint & 1) == 0 ) {
                 System.out.println("even");
                 JMenuItem item = new JMenuItem("Even Row");
                 popupMenu.add(item);}
                 else {
                     System.out.println("odd");
                     //popupMenu = new JPopupMenu();
                     JMenuItem item = new JMenuItem("Odd Row");
                     popupMenu.add(item);}

            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                // TODO Auto-generated method stub

            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
                // TODO Auto-generated method stub

            }


        });


        table.setComponentPopupMenu(popupMenu);
        frame.add(new JScrollPane(table), BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }

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

            @Override
            public void run() {
                new TestTableRightClick().initUI();
            }
        });
    }
}

Когда код выполняется, JPopupMenu остается и остается пустым, даже несмотря на то, что правильная строка возвращается в generateTablePopupMenu, и добавляется новый JMenuItem. Я также пытался заставить код работать до .invokelater следующим образом:

public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                int rowAtPoint = table.rowAtPoint(SwingUtilities.convertPoint(popupMenu, new Point(0, 0), table));
                generateTablePopupMenu(rowAtPoint);

                SwingUtilities.invokeLater(new Runnable() {...

Но тогда возвращаемое целое число строки всегда равно -1. Как я могу заставить это работать? И ПОЧЕМУ это работает, почему мой код не работает? Я искал в сети ответ на свою проблему, но, как ни странно, ничего не нашел.

1 Ответ

0 голосов
/ 15 ноября 2018

Всякий раз, когда вы добавляете / удаляете компоненты из видимого контейнера, вам нужно сообщить контейнеру, что вы закончили добавление компонентов, чтобы можно было вызывать менеджер компоновки.

Ваша логика должна быть:

private void generateTablePopupMenu(int rowAtPoint)
{
    popupMenu.removeAll();

    if ( (rowAtPoint & 1) == 0 )
    {
        JMenuItem item = new JMenuItem("Even Row");
        popupMenu.add(item);}
    else
    {
        JMenuItem item = new JMenuItem("Odd Row");
        popupMenu.add(item);
    }

    popupMenu.revalidate();
}
...