循环内的MouseListener未使用更新后的变量值问题
问题分析与解决方案
嘿,我一眼就揪出你遇到的问题啦!这是Java里匿名内部类捕获外部变量的经典陷阱,我给你拆解清楚:
为什么所有点击都输出相同文本?
你循环里的title变量每次迭代都会被重新赋值,而匿名的MouseAdapter捕获的是这个变量的引用,不是当前迭代的具体值。等循环跑完,title已经变成最后一次迭代的"Title 9"了,所以所有监听器触发时,都会输出这个最终值。
Java要求匿名内部类访问的外部变量必须是final或者等效final(初始化后不再修改),你的title显然不满足这个条件,才会出现这种奇怪的统一输出现象。
两种实用修复方案
方案1:用临时final变量存储当前迭代的title
在循环内部创建一个final临时变量,把当前的title赋值给它,这样每个监听器都会捕获对应迭代的临时变量引用:
for(int i = 0; i<NUM_OF_RESULTS; i++){ title = "Title "+i; resume = "Description "+i ; // 添加临时final变量存储当前title final String currentTitle = title; titles[i]= new JLabel(); descriptions[i]= new JLabel(); panels[i]= new JPanel(); panels[i].setPreferredSize(new Dimension(250, 50)); panels[i].setLayout(new FlowLayout()); titles[i].setText(title); descriptions[i].setText(resume.substring(0, Math.min(resume.length(), 100))+"..."); titles[i].setForeground(Color.blue); descriptions[i].setForeground(Color.black); titles[i].addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent me) { // 使用临时变量输出 System.out.println(currentTitle); } }); panels[i].add(titles[i]); panels[i].add(descriptions[i]); bigPanel.add(panels[i],i, 0); }
方案2:给JLabel绑定自定义属性存储title
利用JComponent的客户端属性功能,把title直接存在对应的JLabel里,点击时再取出来:
for(int i = 0; i<NUM_OF_RESULTS; i++){ title = "Title "+i; resume = "Description "+i ; titles[i]= new JLabel(); descriptions[i]= new JLabel(); panels[i]= new JPanel(); panels[i].setPreferredSize(new Dimension(250, 50)); panels[i].setLayout(new FlowLayout()); titles[i].setText(title); descriptions[i].setText(resume.substring(0, Math.min(resume.length(), 100))+"..."); titles[i].setForeground(Color.blue); descriptions[i].setForeground(Color.black); // 把title存入JLabel的客户端属性 titles[i].putClientProperty("targetTitle", title); titles[i].addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent me) { // 从触发事件的JLabel里取出存储的title JLabel clickedLabel = (JLabel) me.getSource(); String targetTitle = (String) clickedLabel.getClientProperty("targetTitle"); System.out.println(targetTitle); } }); panels[i].add(titles[i]); panels[i].add(descriptions[i]); bigPanel.add(panels[i],i, 0); }
两种方案都能解决问题,方案1简单直接,方案2适合需要给组件绑定更多额外信息的场景~
内容的提问来源于stack exchange,提问作者Ares
相关产品推荐
相关产品推荐

