JList 对象中的 MouseEvents
MouseEvents inside JList objects
我对自己的情况有点困惑。我创建了一个扩展 DefaultListModel 的 ListModel 和实现 ListCellRenderer 的 ListRenderer,用于在 JList 中显示自定义单元格。这些单元格是一些从 class 扩展 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();
}
此处,class 的构造函数采用 JButton 并向其添加鼠标侦听器,这会触发 JPopupMenu 的出现,它只有一个组件,即保存全部数据的 JList。此外,将带有数据项的 ArrayList 链接到 ListModel。
public void initializeTestVariables() {
for (int i = 0; i <= 10; i++) {
WifiItem item = new WifiItem("Connection number " + i + ".", i);
connectionsHolder.add(item);
}
}
设置数据项。
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);
}
});
}
这就是混乱产生的地方。我从鼠标事件 location/point 中正确获取了数据项 (WifiItem),但是当我单击 WifiItem 的 JButton 时,它不会触发该方法,就像它似乎没有检测到 JButton 实际上在那儿。我还设置了打印件,奇怪的是,JButton 的 Point 总是相同的,即使它实际上是不同的,这似乎是问题所在。更确切地说,从程序的输出来看:
Button of Connection number 2. is at location :java.awt.Point[x=137,y=33]
Button has the bounds : java.awt.Rectangle[x=137,y=33,width=90,height=26]
MouseEvent detected on : java.awt.Point[x=172,y=125]
Button of Connection number 3. is at location :java.awt.Point[x=137,y=33]
Button has the bounds : java.awt.Rectangle[x=137,y=33,width=90,height=26]
MouseEvent detected on : java.awt.Point[x=172,y=125]
上面的鼠标事件点实际上位于 JButton 本身,只是它没有得到。另一个奇怪的事实是,只有当我单击列表中第一个元素的 JButton 时,它才会触发所需的鼠标操作。
另一个打印显示所有的 JButton 都有相同的点和矩形,但我不明白。 JList 中有 10 个项目,每个项目都正常显示,它们的 JButtons 怎么可能都位于相同的位置?我一定在这里遗漏了一些关键要素。我查看了其他帖子并尝试了其他建议:使用 SwingUtilities 转换点,从 JList 中删除所有鼠标侦听器并将它们添加到数据项中。
总而言之,问题是列表触发了其中正确数据项的事件(意思是,我确实得到了位于那里的项目的正确索引),但是如果鼠标事件发生在列表中任何数据项的 JButton,它不会触发所需的效果(该点不在按钮的边界内,即使它应该在)。
More exactly, I added a mouse listener for the list, but I want it to trigger something if the mouse point is located inside the bounds of the JButton, and another action if it's on the data item.
一个更简单的解决方案是使用 JTable
。数据分为几列,JTable
有一个 API 让您知道选择了哪个 row/column。
您可以使用 Table Button Column 作为按钮的 renderer/editor。
编辑:
only if I click the JButton of the FIRST element of the list does it trigger the required mouse action
听起来您的鼠标点转换已关闭。
, how can all their JButtons have the same location?
同样,按钮位置与渲染器面板相关。面板本身是相对于 JList 中的行的。所以我猜你需要行索引并将前面每一行的高度添加到你的计算中。
我对自己的情况有点困惑。我创建了一个扩展 DefaultListModel 的 ListModel 和实现 ListCellRenderer 的 ListRenderer,用于在 JList 中显示自定义单元格。这些单元格是一些从 class 扩展 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();
}
此处,class 的构造函数采用 JButton 并向其添加鼠标侦听器,这会触发 JPopupMenu 的出现,它只有一个组件,即保存全部数据的 JList。此外,将带有数据项的 ArrayList 链接到 ListModel。
public void initializeTestVariables() {
for (int i = 0; i <= 10; i++) {
WifiItem item = new WifiItem("Connection number " + i + ".", i);
connectionsHolder.add(item);
}
}
设置数据项。
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);
}
});
}
这就是混乱产生的地方。我从鼠标事件 location/point 中正确获取了数据项 (WifiItem),但是当我单击 WifiItem 的 JButton 时,它不会触发该方法,就像它似乎没有检测到 JButton 实际上在那儿。我还设置了打印件,奇怪的是,JButton 的 Point 总是相同的,即使它实际上是不同的,这似乎是问题所在。更确切地说,从程序的输出来看:
Button of Connection number 2. is at location :java.awt.Point[x=137,y=33]
Button has the bounds : java.awt.Rectangle[x=137,y=33,width=90,height=26]
MouseEvent detected on : java.awt.Point[x=172,y=125]
Button of Connection number 3. is at location :java.awt.Point[x=137,y=33]
Button has the bounds : java.awt.Rectangle[x=137,y=33,width=90,height=26]
MouseEvent detected on : java.awt.Point[x=172,y=125]
上面的鼠标事件点实际上位于 JButton 本身,只是它没有得到。另一个奇怪的事实是,只有当我单击列表中第一个元素的 JButton 时,它才会触发所需的鼠标操作。
另一个打印显示所有的 JButton 都有相同的点和矩形,但我不明白。 JList 中有 10 个项目,每个项目都正常显示,它们的 JButtons 怎么可能都位于相同的位置?我一定在这里遗漏了一些关键要素。我查看了其他帖子并尝试了其他建议:使用 SwingUtilities 转换点,从 JList 中删除所有鼠标侦听器并将它们添加到数据项中。
总而言之,问题是列表触发了其中正确数据项的事件(意思是,我确实得到了位于那里的项目的正确索引),但是如果鼠标事件发生在列表中任何数据项的 JButton,它不会触发所需的效果(该点不在按钮的边界内,即使它应该在)。
More exactly, I added a mouse listener for the list, but I want it to trigger something if the mouse point is located inside the bounds of the JButton, and another action if it's on the data item.
一个更简单的解决方案是使用 JTable
。数据分为几列,JTable
有一个 API 让您知道选择了哪个 row/column。
您可以使用 Table Button Column 作为按钮的 renderer/editor。
编辑:
only if I click the JButton of the FIRST element of the list does it trigger the required mouse action
听起来您的鼠标点转换已关闭。
, how can all their JButtons have the same location?
同样,按钮位置与渲染器面板相关。面板本身是相对于 JList 中的行的。所以我猜你需要行索引并将前面每一行的高度添加到你的计算中。