【问题标题】:Force JTable row selection if clicking outside visible JPopupMenu如果在可见的 JPopupMenu 外部单击,则强制选择 JTable 行
【发布时间】:2016-10-26 22:55:29
【问题描述】:

我已将JPopupMenu 添加到JTablesetComponentPopupMenu。问题是,虽然JPopupMenu 是打开/可见的,但当我左键单击弹出菜单外的一行时,菜单关闭但未选择该行,因此我必须再次单击它以突出显示它。有什么办法可以解决吗?

编辑

我添加了示例代码。

顺便说一下,这种行为只发生在 Windows LaF 中。我刚刚对其进行了测试,似乎默认的 Java LaF 允许在 JPopupMenu 打开时左键单击行选择。

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class TableSTACK {

    private static void createAndShowGUI() {

        String[] headers = {"Column 1", "Column 2"};

        Object[][] data = { {"Row",   "1"}, {"Row",   "2"},
                {"Row",   "3"}, {"Row",   "4"}, {"Row",   "5"},
                {"Row",   "6"}, {"Row",   "7"}, {"Row",   "8"}, };

        JTable table = new JTable(data, headers);
        table.setFillsViewportHeight(true);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());        

        final JMenuItem item1 = new JMenuItem();
        item1.setText("Menu Item 1");       
        final JMenuItem item2 = new JMenuItem();
        item2.setText("Menu Item 2");
        final JMenuItem item3 = new JMenuItem();
        item3.setText("Menu Item 3");

        final JPopupMenu popupMenu = new JPopupMenu();
        popupMenu.add(item1);
        popupMenu.addSeparator();
        popupMenu.add(item2);
        popupMenu.add(item3);
        table.setComponentPopupMenu(popupMenu);

        popupMenu.addPopupMenuListener(new PopupMenuListener() {
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        // force selection of row upon right-click (it works)
                        int rowAtPoint = table.rowAtPoint(SwingUtilities.convertPoint(popupMenu, new Point(0, 0), table));
                        if (rowAtPoint > -1) {
                            table.setRowSelectionInterval(rowAtPoint, rowAtPoint);
                        }
                    }
                });
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        // force row selection upon exiting popup menu
                        // does not work; rowAtPoint always returns -1
                        int rowAtPoint = table.rowAtPoint(SwingUtilities.convertPoint(null, new Point(0, 0), table));
                        //int rowAtPoint = table.rowAtPoint(SwingUtilities.convertPoint(popupMenu, new Point(0, 0), table));
                        if (rowAtPoint > -1) {
                            table.setRowSelectionInterval(rowAtPoint, rowAtPoint);
                        }
                    }
                });
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
                // TODO
            }
        });


        GridBagConstraints gbc = new GridBagConstraints();
        gbc.anchor = GridBagConstraints.NORTHWEST;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridx = 0;

        JScrollPane scrollPane = new JScrollPane(table);

        JPanel contentPane = new JPanel();
        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
        contentPane.setLayout(new GridBagLayout());
        contentPane.add(scrollPane, gbc);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(contentPane);
        frame.pack();
        frame.setMinimumSize(new Dimension(500, 400));
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    //UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (UnsupportedLookAndFeelException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                createAndShowGUI();
            }
        });
    }
}

【问题讨论】:

  • 使用像TablePopupEditor这样的单元格编辑器。如果这不是重复的,请编辑您的问题以包含 minimal reproducible example,以显示您修改后的方法。
  • 这最初是作为副本关闭的:stackoverflow.com/questions/3590897/…。我不认为这个问题是关于弹出编辑器的。问题是关于使用“JPopupMenu”并在菜单打开时单击表格。我重新打开了这个问题。
  • 我已经编辑了我的问题。

标签: java swing jtable jpopupmenu


【解决方案1】:

这是一个 LAF 问题。

当我使用默认 LAF 时它适用于我,但当我使用平台 LAF(对我来说是 Windows)时它不起作用。

Windows 上的一个潜在解决方案是使用MouseListener 来选择行。请注意,代码已添加到 mouseReleased 事件中。由于某种原因,即使根据AWTEventListener 表是mousePressed 事件的来源,表也没有收到mousePressed 事件。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TablePopupListener extends JPanel
{
    public TablePopupListener()
    {
        JTable table = new JTable(10, 5);
        add( new JScrollPane( table ) );

        JPopupMenu popup = new JPopupMenu();
        popup.add( new JMenuItem("Do Something1") );
        popup.add( new JMenuItem("Do Something2") );

        table.setComponentPopupMenu( popup );

        table.addMouseListener( new MouseAdapter()
        {
            public void mousePressed(MouseEvent e)
            {
                System.out.println("Pressed JTable");
            }

            public void mouseReleased(MouseEvent e)
            {
                System.out.println("Released JTable");

                int row = table.rowAtPoint( e.getPoint() );

                if (row != -1
                && !table.isRowSelected(row))
                {
                   table.setRowSelectionInterval(row, row);
                }
            }
        });
    }

    private static void createAndShowGUI()
    {
        try
        {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch (Exception ex) { System.out.println(ex); }

        JFrame frame = new JFrame("TablePopupListener");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new TablePopupListener());
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );

        Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
        {
            public void eventDispatched(AWTEvent e)
            {
                String event = null;

                switch (e.getID())
                {
                    case MouseEvent.MOUSE_PRESSED:  event = "Pressed: " ; break;
                    case MouseEvent.MOUSE_RELEASED:  event = "Released: " ; break;
                    case MouseEvent.MOUSE_ENTERED:  event = "Entered: " ; break;
                    case MouseEvent.MOUSE_EXITED:  event = "Exited: " ; break;
                    default: event = null; break;
                }

                if (event != null)
                {
                    System.out.println();
                    System.out.println(event + e.getSource().getClass());
                }
            }
        },  AWTEvent.MOUSE_EVENT_MASK);
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }
}

【讨论】:

  • 所以我想我会保留PopupMenuListener 用于在右键单击时强制选择表格行,我将添加一个MouseListener 以在左键单击时强制选择行,而JPopupMenu可见。太糟糕了,它必须那么复杂......谢谢
猜你喜欢
  • 1970-01-01
  • 2014-07-04
  • 2014-05-05
  • 2020-11-20
  • 2018-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多