2016-05-05 12 views
4

Ich möchte eine benutzerdefinierte Schaltfläche, die aus einem großen und einem kleinen Quadrat, die jeweils diese Farben haben: #2980b9#3498db. Das kleine Quadrat würde innerhalb des großen sein, und es würde seine Größe erhöhen, wenn der Cursor über oder wenn es angeklickt wird, und gleichzeitig würde sich die Farbe zu einem klareren ändern (#4AA3DF).Probleme beim Ausdrucken einer benutzerdefinierten Schaltfläche und Erstellen von MouseListener

Das Problem ist, dass nur der kleinere ausgedruckt wird, und es ist nicht einmal gut ausgedruckt; wie es in der oberen linken Ecke des Fensters erscheint. Außerdem werden die MouseListener Funktionen überhaupt nicht verwendet. Diese

ist die Button Klasse:

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 
} 

Und das ist die StartingPoint Klasse:

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(); 
     } 
    } 
} 
} 

Dies ist, was die Konsole sagt:

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

Für soweit ich kann verstehen, das Problem hat etwas mit derzu tun 0, aber ich weiß nicht, wie ich es lösen soll. Ich suchte nach der java.lang.NullPointerException Ausnahme, aber was ich verstanden habe ist, dass es passiert, wenn Sie nicht die setSize() Methode oder eine ähnliche anrufen, aber ich tat.

Was ist das Problem und was ist der beste Weg, es zu lösen?

EDITED: Ich fand heraus, dass was die Konsole zu sagen, was es sagte, war die mouseEvent. Jetzt jedes Mal, wenn ich auf den Cursor verweisen möchte, bleibe ich bei der Definition der Methode mit dem e zwischen den Klammern. Es gibt keinen Fehler in der Konsole; Die Dinge werden jedoch auf die gleiche Weise gedruckt und MouseListener funktioniert immer noch nicht.

EDIT: Ich habe keine Ausnahmen mehr, weil es wegen der MouseEvent mouseEvent gab, aber die anderen Probleme sind immer noch da.

+0

Wie lautet der Code in Zeile 62 der Button-Klasse? – Bohemian

+0

Ich habe keine Ausnahmen mehr, weil es wegen des 'MouseEvent mouseEvent' gab, aber Dinge werden auf die gleiche Weise ausgedruckt und MouseListener funktioniert nicht. – SpaceCore186

Antwort

1

Das Problem ist, dass Ihre MouseEvent mouseEvent; Variable nie initialisiert wird. Sie könnten es initialisieren und es dann jedes Mal an Ihre insideArea weiterleiten, oder Sie könnten es komplett entfernen und das Ereignis direkt wie unten gezeigt verwenden.

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

Und hier

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

und hier

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

Ich habe das gerade herausgefunden (wahrscheinlich während du deine Antwort eingegeben hast) hahaha! Wissen Sie, warum die Dinge so ausgedruckt werden, wie sie gedruckt werden? Es ist, als würde ich nicht die Größe meines Rahmens einstellen, aber ich mache es. – SpaceCore186

+0

Sie meinen die Tatsache, dass Ihre Schaltfläche nicht neu streichen? – Kalenda

2

Es gibt ein paar Probleme.

Diese Zeilen sollten in der Farbe Methode:

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

Wie es aussieht, werden diese Werte einmal bei der Initialisierung des Objekts zugewiesen.Ihre Malmethode erwartet jedoch, dass sie dynamisch sind, da sich Ihr Ereignis-Listener smallSquareXSize und smallSquareXSize ändert.

Da diese Variablen nur aus der Farbe Methode zugegriffen werden, bewegen sich alle sch Variablendeklarationen in der paint-Methode:

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);  
} 

Dies ergibt sich auch eine gute allgemeine Codierung der Praxis von Variablen deklarieren, so dass sie eine möglichst geringe Umfang. In diesem Fall reduzieren Sie den Bereich von allen Methoden auf die Methode, die sie verwendet. Obwohl dies in diesem Fall nicht zutrifft, sollten Sie den Umfang auf einen Block (z. B. innerhalb der Schleife oder if Block usw.) reduzieren, wenn möglich.


Das andere Problem ist subtiler. Es ist eine der Parallelität, dh in einer Multi-Thread-Umgebung ausgeführt wird. Der Thread, der das Mausereignis sendet, ist ein anderer Thread als der Hauptthread. Außerdem kann es bei jedem Mausereignis ein anderer Thread sein (bin mir nicht sicher). Eine der Auswirkungen von gleichzeitigen Threads besteht darin, dass Änderungen an Instanzvariablen, die in einem Thread vorgenommen wurden, von anderen Threads möglicherweise nicht "gesehen" werden. Insbesondere dieses Feld:

boolean clicked = false; 

und diese Linie:

clicked = !clicked; 

Dieses „Problem“ ist aufgrund des Java-Speichermodell, das einfach sagen setzen, dass jeder Thread eine Kopie des Wertes des Feldes Cache kann Das bedeutet, wenn ein Thread ihm einen neuen Wert zuweist, kann ein anderer Thread diese Änderung sehen oder nicht.

Aber keine Panik - es gibt eine einfache Lösung:

volatile boolean clicked = false; 

Das volatile Stichwort sagt java nie den Wert zwischenspeichern - immer den Wert der von dem Thread verwalteten Speicher überprüfen, die das Objekt erstellt hat.

Ich bin mir nicht sicher, ob das von Ihnen verwendete Framework möglicherweise verschiedene Threads für die verschiedenen Arten von Mausereignissen verwendet, aber wenn dies der Fall ist, benötigen Sie volatile. Wenn nicht, wird es nicht schaden, es zu volatile zu machen, wenn es nicht sein muss.

+0

Jetzt wird nicht einmal der Rahmen ausgedruckt. Ich habe gerade meine Frage bearbeitet, damit Sie den neuen Quellcode sehen können. – SpaceCore186

+0

Sollte ich etwas mit der 'update' Methode machen? – SpaceCore186

+0

Machen Sie aus den gleichen Gründen 'Farbe' flüchtig. – Bohemian