Java JList对象中的MouseEvents

Java JList对象中的MouseEvents,java,swing,location,mouseevent,jlist,Java,Swing,Location,Mouseevent,Jlist,我对自己的处境有点困惑。我创建了一个扩展DefaultListModel的ListModel和实现ListCellRenderer的ListRenderer,用于在JLList中显示自定义单元格。单元格是从扩展JPanel的类创建的一些对象,其中包含一个JLabel和一个JButton 我的问题与鼠标事件有关:我想在单击JList单元格内的JButton时触发某个事件,但我无法从相应的索引中找出如何将鼠标源点与JButton的源点相匹配。更确切地说,我在列表中添加了一个鼠标侦听器,但如果鼠标点位

我对自己的处境有点困惑。我创建了一个扩展DefaultListModel的ListModel和实现ListCellRenderer的ListRenderer,用于在JLList中显示自定义单元格。单元格是从扩展JPanel的类创建的一些对象,其中包含一个JLabel和一个JButton

我的问题与鼠标事件有关:我想在单击JList单元格内的JButton时触发某个事件,但我无法从相应的索引中找出如何将鼠标源点与JButton的源点相匹配。更确切地说,我在列表中添加了一个鼠标侦听器,但如果鼠标点位于JButton的边界内,我希望它触发一些内容,如果它位于数据项上,则希望它触发另一个操作。我添加了一些打印以找出原因,但在此之前,我添加了一些代码以突出显示结构:

 public WifiGuiHandler(JButton reference) {
    btnReference = reference;
    wifiListener = new WifiListener();
    wifiPopupContainer = new JScrollPopupMenu("Connections.");
    wifiPopupContainer.setMaximumVisibleRows(7);
    connectionsHolder = new ArrayList<>();
    listOfConnections = new JList();
    listOfConnectionsModel = new ListModel(connectionsHolder);
    listOfConnectionsRenderer = new ListRenderer();
    listOfConnections.setModel(listOfConnectionsModel);
    listOfConnections.setCellRenderer(listOfConnectionsRenderer);
    wifiPopupContainer.add(listOfConnections);
    wifiPopupContainer.pack();
    initializeTestVariables();
    initializeListeners();
}
这就是产生混淆的地方。我正确地从鼠标事件位置/点获取数据项(WifiItem),但是当我单击WifiItem的JButton时,它不会触发该方法,就像它似乎没有检测到JButton实际上在那里一样。我还设置了打印,奇怪的是,JButton的点总是相同的,尽管它实际上是不同的,这似乎就是问题所在。更确切地说,从程序的输出:

连接2号的按钮。位于以下位置:java.awt.Point[x=137,y=33]

按钮具有边界:java.awt.Rectangle[x=137,y=33,width=90,height=26]

在以下位置检测到鼠标事件:java.awt.Point[x=172,y=125]

3号接头的按钮。位于以下位置:java.awt.Point[x=137,y=33]

按钮具有边界:java.awt.Rectangle[x=137,y=33,width=90,height=26]

在以下位置检测到鼠标事件:java.awt.Point[x=172,y=125]

上面的鼠标事件点实际上位于JButton本身,只是它没有得到。另一个奇怪的事实是,只有单击列表第一个元素的JButton,它才会触发所需的鼠标操作

另一张照片显示所有的JButton都有相同的点和矩形,我不明白。JList中有10个项目,每个项目都正确显示,它们的所有JButton如何具有相同的位置?我一定是遗漏了一些关键因素。我查看了其他帖子并尝试了其他建议:使用SwingUtilities转换该点,从JList中删除所有鼠标侦听器,并将它们添加到数据项中

public void initializeListeners() {

    listOfConnections.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
            int index = listOfConnections.locationToIndex(e.getPoint());
            if (index >= 0) {
                WifiItem item = (WifiItem) ((ListModel) listOfConnections.getModel()).getElementAt(index);
                System.out.println("Button of " + item.getConnectionName() + " is at location :" + item.getButton().getLocation());
                System.out.println("Button has the bounds : " + item.getButton().getBounds());
                System.out.println("MouseEvent detected on : " + e.getPoint().getLocation());
                if (item.getButton().getBounds().contains(e.getPoint())) {
                    item.connectHere();
                }
                if (item.getButton().isVisible()) {
                    System.out.println("Set expanded on : " + item.getConnectionName());
                    item.setExpandedState(false);
                    listOfConnectionsModel.fireContentsChanged(item, index, index);
                    updateGui(false);
                } else {
                    System.out.println("Set expanded on : " + item.getConnectionName());
                    listOfConnectionsModel.fireContentsChanged(item, index, index);
                    item.setExpandedState(true);
                    updateGui(false);
                }
            }
        }

    });
    btnReference.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
            updateGui(true);
        }
    });

}
总而言之,问题在于列表触发了其中正确数据项的事件(也就是说,我确实获得了该项的正确索引),但是如果鼠标事件发生在列表中任何数据项的JButton上,它不会触发所需的效果(该点不在按钮的边界内,即使它应该在边界内)

更确切地说,我为列表添加了一个鼠标侦听器,但是如果鼠标点位于JButton的边界内,我希望它触发一些东西,如果它位于数据项上,则希望它触发另一个操作

一个更简单的解决方案是使用
JTable
。数据分为列,
JTable
有一个API,让您知道选择了哪一行/哪一列

可以使用作为按钮的渲染器/编辑器

编辑:

只有单击列表第一个元素的JButton,它才会触发所需的鼠标操作

听起来您的鼠标点转换已关闭

,它们的所有jbutton如何具有相同的位置


同样,按钮位置与渲染器面板相关。面板本身与JList中的行相关。因此,我猜您需要行索引,并将前面每行的高度添加到您的计算中。

我将尝试明天切换到JTable,我首先考虑使用它,但我不希望将数据分开在列中,由于在我的数据项类(WifiItem)中,出于设计目的(如团队成员所建议),按钮在显示文本的标签下方对齐。此外,如代码中所示,当您单击其中一个项目时,它将“最小化”(隐藏按钮并调整大小,以便仅显示标签)或“最大化”(显示按钮并扩展其大小)。谢谢你的建议,无论如何,我明天会再试一次,然后返回结果。@g0dzax,
按钮在显示文本的标签下方对齐,
-JTable对此不起作用。有关其他注释,请参阅编辑。将高度添加到计算中的想法非常棒。我会尝试。因此,我设置了一个方法来计算上一行的高度和索引(k)处的行的高度,它还计算按钮与面板顶部之间的距离,当用户单击大于0的行时,它会将包含按钮的矩形设置为默认的X(因为X永远不会更改),并将其Y设置为计算出的高度,然后执行检查。感谢您的帮助!@g0dzax,很高兴它成功了。
JList
有一个
getCellBounds(…)
方法来获取给定行的矩形。从那里,您只需调整固定数量的x/Y值。
public void initializeListeners() {

    listOfConnections.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
            int index = listOfConnections.locationToIndex(e.getPoint());
            if (index >= 0) {
                WifiItem item = (WifiItem) ((ListModel) listOfConnections.getModel()).getElementAt(index);
                System.out.println("Button of " + item.getConnectionName() + " is at location :" + item.getButton().getLocation());
                System.out.println("Button has the bounds : " + item.getButton().getBounds());
                System.out.println("MouseEvent detected on : " + e.getPoint().getLocation());
                if (item.getButton().getBounds().contains(e.getPoint())) {
                    item.connectHere();
                }
                if (item.getButton().isVisible()) {
                    System.out.println("Set expanded on : " + item.getConnectionName());
                    item.setExpandedState(false);
                    listOfConnectionsModel.fireContentsChanged(item, index, index);
                    updateGui(false);
                } else {
                    System.out.println("Set expanded on : " + item.getConnectionName());
                    listOfConnectionsModel.fireContentsChanged(item, index, index);
                    item.setExpandedState(true);
                    updateGui(false);
                }
            }
        }

    });
    btnReference.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
            updateGui(true);
        }
    });

}