2016-05-05 6 views
4

大きな正方形と小さな正方形からなるカスタムボタンを作成したいとします。これらのボタンの色はそれぞれ#2980b9#3498dbです。 小さい四角形は大きなものの内側にあり、カーソルが上に置かれたとき、またはクリックされたときにサイズが増加し、同時に色がより鮮明なものに変わります(#4AA3DF)。カスタムボタンを印刷してMouseListenerを作成する問題

問題は小さなものだけがプリントアウトされ、うまくプリントされないことです。ウィンドウの左上隅に表示されます。 さらに、MouseListener関数はまったく使用されていません。

この

Buttonクラスです:

public class Button extends JComponent implements MouseListener { 
private static final long serialVersionUID = 1L; 

JFrame frame = new JFrame(); 

public Button(JFrame frame) { 
    enableInputMethods(true); 
    addMouseListener(this); 
    this.frame = frame; 
} 

// Mouse activity  //DELETED 
MouseEvent mouseEvent; //DELETED 

// Window's width and height. 
int width = (int) frame.getWidth(); 
int height = (int) frame.getHeight(); 

// Squares's sizes. 
int bigSquareXSize = 200; 
int bigSquareYSize = 200; 
int smallSquareXSize = 180; 
int smallSquareYSize = 180; 

// smallSquare color. 
volatile String color = "#3498db"; 

//I think that I should do something with the update method, 
//but i'm not sure about what (sorry, I know this is stupid). 
public void update() { 

} 

@Override 
public void paintComponent(Graphics g) { 
    Graphics2D g2 = (Graphics2D) g; 

    // Squares's X and Y positions. 
    int bigSquareXPosition = width/2 - bigSquareXSize/2; 
    int bigSquareYPosition = height/2 - bigSquareYSize/2; 
    int smallSquareXPosition = width/2 - smallSquareXSize/2; 
    int smallSquareYPosition = height/2 - smallSquareYSize/2; 

    g.setColor(Color.decode("#2980b9")); 
    g2.setColor(Color.decode(color)); 
    g.fillRect(bigSquareXPosition, bigSquareYPosition, bigSquareXSize, bigSquareYSize); 
    g2.fillRect(smallSquareXPosition, smallSquareYPosition, smallSquareXSize, smallSquareYSize); 

} 

// Returns a true value if the cursor is placed over the smallSquare. 
public boolean insideArea(MouseEvent e) { 
    boolean value = false; 
    int smallSquareXPosition = width/2 - smallSquareXSize/2; 
    int smallSquareYPosition = height/2 - smallSquareYSize/2; 
    if (e.getX() > smallSquareXPosition && e.getX() < smallSquareXPosition + smallSquareXSize) { 
     if (e.getY() > smallSquareYPosition && e.getY() < smallSquareYPosition + smallSquareYSize) { 
      value = true; 
     } 
    } 
    return value; 
} 

volatile boolean clicked = false; 

@Override 
public void mouseClicked(MouseEvent e) { 
    if (insideArea(e)) { 
     clicked = !clicked; 
     if (clicked) { 
      color = "#4AA3DF"; 
      smallSquareXSize = 190; 
      smallSquareYSize = 190; 
     } 
    } else { 
     color = "#3498db"; 
     smallSquareXSize = 180; 
     smallSquareYSize = 180; 
    } 
    this.repaint(); 
} 

@Override 
public void mouseEntered(MouseEvent e) { 
    if (!clicked) { 
     if (insideArea(e)) { 
      color = "#4AA3DF"; 
      smallSquareXSize = 190; 
      smallSquareYSize = 190; 
     } 
    } 
    this.repaint(); 
} 

@Override 
public void mouseExited(MouseEvent e) { 
    if (!clicked) { 
     if (insideArea(e)) { 
      color = "#3498db"; 
      smallSquareXSize = 180; 
      smallSquareYSize = 180; 
     } 
    } 
    this.repaint(); 
} 

@Override 
public void mousePressed(MouseEvent e) { 
    // TODO Auto-generated method stub 
} 

@Override 
public void mouseReleased(MouseEvent e) { 
    // TODO Auto-generated method stub 
} 

そして、これはStartingPointクラスです:

public class StartingPoint implements Runnable { 

Thread thread = new Thread(this); 
static JFrame frame = new JFrame("BUTTON!"); 
static Button button = new Button(frame); 

public static void main(String[] args) { 

    //Frame creation 
    JFrame frame = new JFrame("BUTTON!"); 
    frame.setSize(600, 400); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setVisible(true); 

    JPanel panel = new JPanel(); 
    panel.setLayout(new FlowLayout()); 
    panel.add(button); 
    frame.add(panel); 

} 

@Override 
public void run() { 
    while (true) { 
     button.update(); 
     try { 
      Thread.sleep(17); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
} 

これは、コンソールはこう言われる、私の知る限りとしてのために

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException 
at Button.insideArea(Button.java:62) 
at Button.mouseEntered(Button.java:92) 

理解できる、問題はと関係があります0、しかし私はそれを解決する方法を知らない。 java.lang.NullPointerExceptionの例外を調べましたが、私が理解したことは、setSize()メソッドまたはそれに類するメソッドを呼び出さないと発生するということです。

問題は何ですか?問題を解決するにはどうすればよいですか?

EDITED:コンソールに何が起こったのかがわかったのは、mouseEventでした。カーソルを参照するたびに、メソッド定義の括弧の間にeを貼り付けます。 コンソールにエラーはありません。しかし、物事は同じ方法で印刷され、MouseListenerはまだ動作していません。

編集:MouseEvent mouseEventのために例外がありますが、その他の問題はまだあります。

+0

Buttonクラスの62行目のコードは何ですか? – Bohemian

+0

'MouseEvent mouseEvent'のために例外が発生したため、私はもう例外がありませんが、同じ方法で何かが出力され、MouseListenerは機能しません。 – SpaceCore186

答えて

1

問題は、MouseEvent mouseEvent;変数が決して初期化されないということです。それを初期化して毎回insideAreaに渡すか、完全に削除して、イベントを直接下のように使用することができます。

@Override 
public void mouseClicked(MouseEvent e) { 
    if (insideArea(e)) { 
    ... 

そしてここ

@Override 
public void mouseEntered(MouseEvent e) { 
    if (!clicked) { 
     if (insideArea(e)) { 
      ... 

、ここ

@Override 
public void mouseExited(MouseEvent e) { 
    if (!clicked) { 
     if (insideArea(e)) { 
     ... 
+0

私はちょうどあなたがあなたの答えを入力している間、それを考え出したhahaha! 物事が印刷される方法を印刷する理由を知っていますか?私のフレームのサイズを設定していなかったのと同じですが、私はそれをやっています。 – SpaceCore186

+0

ボタンが再描画されないという事実を意味しますか? – Kalenda

2

問題がいくつかあります。

これらの行はpaintメソッドの内部でなければならない:それは現状で

int smallSquareXPosition = width/2 - smallSquareXSize/2; 
int smallSquareYPosition = height/2 - smallSquareYSize/2; 

、これらの値は、オブジェクトの初期化時に一度割り当てられます。しかし、イベントリスナーがsmallSquareXSizesmallSquareXSizeのように変更されるため、ペイントメソッドでは、それらのイベントが動的であることが期待されます。

これらの変数のみ塗装方法からアクセスされるので、すべてのペイント法内部変数宣言をSCH移動:

public void paintComponent(Graphics g) { 
    int bigSquareXPosition = width/2 - bigSquareXSize/2; 
    int bigSquareYPosition = height/2 - bigSquareYSize/2; 
    int smallSquareXPosition = width/2 - smallSquareXSize/2; 
    int smallSquareYPosition = height/2 - smallSquareYSize/2; 

    Graphics2D g2 = (Graphics2D) g; 
    g.setColor(Color.decode("#2980b9")); 
    g2.setColor(Color.decode(color)); 
    g.fillRect(bigSquareXPosition, bigSquareYPosition, bigSquareXSize, bigSquareYSize); 
    g2.fillRect(smallSquareXPosition, smallSquareYPosition, smallSquareXSize, smallSquareYSize);  
} 

これはまた、彼らは可能な最小を有するように変数の宣言の良い一般的なコーディングプラクティスに従います範囲。この場合、すべてのメソッドからそのメソッドを使用するメソッドだけにスコープを縮小します。この場合は適用されませんが、可能であれば、コードのブロック(ループ内またはブロック内のブロックなど)にスコープをさらに減らす必要があります。


もう1つの問題はより微妙です。これは並行処理の1つです。つまり、マルチスレッド環境で実行されます。マウスイベントを送信するスレッドは、メインスレッドとは異なるスレッドです。さらに、それはマウスのイベントごとに異なるスレッドかもしれません(私はわかりません)。並行スレッドの意味の1つは、あるスレッドで行われたインスタンス変数の変更が、他のスレッドによって「認識」されない可能性があることです。具体的には、このフィールド:

boolean clicked = false; 

と、この行:

clicked = !clicked; 

この「問題」は簡単に言えばJavaのメモリモデルによるものであるが、各スレッドは、フィールドの値のコピーをキャッシュすることができると述べていますつまり、あるスレッドが新しい値を割り当てると、別のスレッドがこの変更を参照することも、表示しないこともあります。

しかし、慌てる必要はありません - 簡単な修正はあります:

volatile boolean clicked = false; 

volatileキーワードが値をキャッシュしないようにするJavaを伝えます - 常にオブジェクトを作成したスレッドが管理するメモリの値を確認してください。

使用しているフレームワークがさまざまな種類のマウスイベントに対して異なるスレッドを使用するかどうかはわかりませんが、そうであればvolatileが必要です。もしそうでなければ、それはvolatileである必要はないが、害はない。

+0

フレームも印刷されていません。 私は自分の質問を編集したので、新しいソースコードを見ることができます。 – SpaceCore186

+0

'update'メソッドで何かするべきですか? – SpaceCore186

+0

同じ理由で 'color'も揮発性にします。 – Bohemian