2013-05-04 105 views
0

有點上下文 - 我正在創建Scrabble的基本實現,GUI依賴於Java Swing和AWT。下面的代碼摘錄包含Cell類的構造函數(Scrabble板上的獨立空間)。我處於概念證明階段,正在測試向單個單元格添加和刪除硬編碼的字母圖標。每個單元格都是帶有JLabel的單個JPanel(其中包含該字母的ImageIcon)。代碼看起來好像沒有任何錯誤,但每增加5-6個添加/刪除(通過鼠標點擊)都會導致類別轉換異常。具體的例外是:類拋出異常 - 鼠標事件

異常在線程「AWT-EventQueue的-0」 java.lang.ClassCastException:細胞不能轉換到javax.swing.JLabel中

我不能看到這個異常會引起,但更具體地說,爲什麼它只發生在多次成功的添加和清除之後。任何見解都非常感謝;我是Java GUI的初學者。

public class Cell extends JPanel { 

/*Tile Colors*/ 
public static Color twColor = new Color(255, 0, 0); 
public static Color dwColor = new Color(255, 153, 255); 
public static Color tlColor = new Color(0, 51, 255); 
public static Color dlColor = new Color(102, 204, 255); 
public static Color defaultColor = new Color(255, 255, 255); 

private JLabel selected = null; 
private JLabel clicked = null; 
private JLabel letterIcon; 
private ImageIcon defaultIcon; 
private ImageIcon testImg; 

public Cell(int xPos, int yPos, int premiumStatus) { 

    defaultIcon = new ImageIcon ("img/transparent.png"); 
    testImg = new ImageIcon ("img/test.jpg"); // Letter image hard-coded for testing 
    letterIcon = new JLabel("", defaultIcon, JLabel.CENTER); 
    add(letterIcon); 

    letterIcon.addMouseListener(new MouseAdapter() { 
     public void mouseClicked(MouseEvent e) { 
     JLabel clicked = (JLabel) getComponentAt(e.getPoint()); 
     System.out.println(clicked); 
     if (clicked == null) { 
      return; 
     } 
     if (selected != null) { 
      selected.removeAll(); 
      selected.revalidate(); 
      selected.setIcon(defaultIcon); 
      selected.repaint(); 
      System.out.println("Test"); 
      selected = null; 
      return; 
     } 
     if (selected == null) { 
      selected = clicked; 
      selected.setIcon(testImg); 
      selected.revalidate(); 
      selected.repaint(); 
     } 
     } 
    }); 
} 

回答

2

問題是通過調用CellgetComponentAt(e.getPoint());,當鼠標座標已經轉換爲letterIcon的座標空間是原因。

單擊組件時,MouseEvent的點將自動轉換爲偵聽器註冊到的組件的座標空間。

就你而言,那就是letterIcon。這意味着在0x0處的點是letterIcon的頂部/左邊角落(儘管它可能在物理位置上)。

因此,呼籲getComponentAt(e.getPoint())是要求Cell返回對應於這實際上是相對於只對letterIcon,這將(在大多數情況下)返回Cell本身的位置的組件。

相反,你應該簡單地使用MouseEvent#getComponent返回觸發事件,這將是letterIcon

更新一個簡單的例子組件

這是一個簡單的例子,設置了一個作爲鼠標目標的JLabel。單擊鼠標時,標籤和它的父容器都會根據鼠標點擊的座標繪製一個小點。

父容器還會將點擊點轉換爲其座標空間並繪製第二個點,這應該與標籤處於同一點擊位置。

enter image description here

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.GridBagLayout; 
import java.awt.Point; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class TestMouseClicked { 

    public static void main(String[] args) { 
     new TestMouseClicked(); 
    } 

    public TestMouseClicked() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private JLabel clickMe; 
     private Point clickPoint; 

     public TestPane() { 
      setLayout(new GridBagLayout()); 
      clickMe = new JLabel("Click me") { 
       @Override 
       protected void paintComponent(Graphics g) { 
        super.paintComponent(g); 
        g.setColor(Color.MAGENTA); 
//     paintPoint(g, clickPoint); 
       } 
      }; 
      add(clickMe); 
      clickMe.addMouseListener(new MouseAdapter() { 
       @Override 
       public void mouseClicked(MouseEvent e) { 
        clickPoint = e.getPoint(); 
        repaint(); 
       } 
      }); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(200, 200); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      g.setColor(Color.RED); 
      paintPoint(g, clickPoint); 
      if (clickPoint != null) { 
       g.setColor(Color.BLUE); 
       // Convert the point from clickMe coordinate space to local coordinate space 
       paintPoint(g, SwingUtilities.convertPoint(clickMe, clickPoint, this)); 
      } 
     } 

     protected void paintPoint(Graphics g, Point clickPoint) { 
      if (clickPoint != null) { 
       int size = 4; 
       g.fillOval(clickPoint.x - size, clickPoint.y - size, size * 2, size * 2); 
      } 
     } 
    } 
} 
+0

謝謝你的體貼響應!這種改變不僅有效,而且我現在對MouseEvent的行爲有了更好的理解。 – 2013-05-04 07:53:58

+0

我已經添加了一個簡單的例子來說明我一直在說什麼,希望它有幫助 – MadProgrammer 2013-05-04 07:57:57

+0

感謝您的好例子!我希望我能兩次上癮。 – 2013-05-04 08:03:48