Java Графика и события Swing - PullRequest
1 голос
/ 12 июля 2020

Я пытаюсь сделать простую игру, которая отображает круги в рамке, и при нажатии круг должен исчезать. Я изучаю, как работает Java Swing, и мне удалось нарисовать круг (вау, такое достижение) и выяснить, как работают события. Я добавил mouseListener в круг, и при щелчке на данный момент я хочу получить консольный журнал о том, что он был нажат, но конечный результат не такой, как ожидалось. Независимо от того, где я щелкаю, я всегда получаю журнал консоли "щелчок". Когда я пытаюсь добавить слушателя, например, к JButton, я получаю конечный результат. Отличаются ли события для графики?


import javax.swing.*;
import javax.swing.event.MouseInputListener;
import java.awt.*;
import java.awt.event.*;
import java.sql.SQLOutput;

public class CirclePop {

    JFrame frame;
    Circle circle;

    public static void main(String[] args) {
        CirclePop circlePop = new CirclePop();
        circlePop.drawFrame();
    }

    public void drawFrame() {
        frame = new JFrame();
        circle  = new Circle();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(circle);

        circle.addMouseListener(new Click());

        frame.setSize(300, 300);
        frame.setVisible(true);
    }

    class Click implements MouseListener {

        @Override
        public void mouseClicked(MouseEvent e) {

        }

        @Override
        public void mousePressed(MouseEvent e) {
            System.out.println("Pressed");
        }

        @Override
        public void mouseReleased(MouseEvent e) {

        }

        @Override
        public void mouseEntered(MouseEvent e) {

        }

        @Override
        public void mouseExited(MouseEvent e) {

        }
    }
}


import java.awt.*;
import javax.swing.*;

class Circle extends JPanel {

    public void paintComponent(Graphics g) {

        g.setColor(Color.red);
        g.fillOval(150, 140, 30, 30);
    }
}

Ответы [ 3 ]

2 голосов
/ 12 июля 2020

Прежде всего, вы можете захотеть extend MouseAdapter вместо реализации MouseListener. Таким образом, вам не придется «реализовывать» все эти пустые методы.

Затем в вашем методе mousePressed вам просто нужно вычислить, произошел ли щелчок внутри круга. По сути, это просто Пифагор:

static class ClickListener extends MouseAdapter {
    private final Circle circle;

    public ClickListener(Circle circle) {
        this.circle = circle;
    }


    @Override
    public void mousePressed(MouseEvent e) {
        int centerX = circle.getCenterX();
        int centerY = circle.getCenterY();
        int radius = circle.getRadius();
        int clickX = e.getX();
        int clickY = e.getY();

        // inside circle: (clickX - centerX)^2 + (clickY - centerY)^2 < radius^2
        double xSquare = Math.pow(clickX - centerX, 2);
        double ySquare = Math.pow(clickY - centerY, 2);

        if (xSquare + ySquare < radius * radius) {
            System.out.println("pressed");
        }
    }
}

Я добавил несколько полей в класс Circle, чтобы получить доступ к свойствам, которые вам нужны для вычислений:

class Circle extends JPanel {
    private final int radius = 30;
    private final int centerX = 150;
    private final int centerY = 140;

    public void paintComponent(Graphics g) {
        g.setColor(Color.red);
        g.fillOval(centerX, centerY, radius, radius);
    }
    // getter, etc.
}
1 голос
/ 12 июля 2020

Ладно, это не будет коротким

Начнем с ....

    frame = new JFrame();
    circle  = new Circle();

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(circle);

    circle.addMouseListener(new Click());

    frame.setSize(300, 300);
    frame.setVisible(true);

Хорошо, кажется достаточно простым, но одно, что вы упущен тот факт, что JFrame по умолчанию использует BorderLayout - это означает, что он заставит дочерний компонент (и центральную / стандартную позицию) заполнить все доступное пространство видимого пространства фреймов

Вы можете увидеть это, если сделаете что-то вроде ...

    frame = new JFrame();
    circle  = new Circle();
    circle.setBackground(Color.RED);

Теперь вы увидите, что компонент Circle занимает весь фрейм, поэтому, когда вы нажимаете на него, вы нажимаете Circle сам компонент.

Это неплохо, но вы можете немного изменить такт. Вместо того, чтобы добавлять MouseListener независимо от Circle, пусть компонент Circle использует свой собственный MouseListener, например ...

class Circle extends JPanel {

    public Circle() {
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                // More to come...
            }
        });
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.setColor(Color.red);
        g.fillOval(150, 140, 30, 30);
    }
}

Это означает, что вы можете многое контролировать. логики c внутри класса, упрощает доступ к более важной информации без необходимости делать кучу потенциально опасных приведений.

Итак, теперь нам просто нужно добавить logi c in, чтобы определить, была ли нажата мышь в желаемом месте или нет ...

public void mouseClicked(MouseEvent e) {
    Point point = e.getPoint();
    if (point.x >= 150 && point.x <= 150 + 30 && point.y >= 140 && point.y <= 140 + 30) {
        System.out.println("You clicked me :(");
    }
}

Хорошо, это ... basi c

Мы можем упростить немного и использовать доступные функции в более широком API, используя API "фигур", например ...

class Circle extends JPanel {
    
    private Ellipse2D dot = new Ellipse2D.Double(150, 140, 30, 30);

    public Circle() {
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                Point point = e.getPoint();
                if (dot.contains(point)) {
                    System.out.println("You clicked me :(");
                }
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();

        g2d.setColor(Color.red);
        g2d.fill(dot);
        g2d.dispose();
    }
}

Преимущество этого, помимо contains, заключается в том, что мы может относительно легко изменить положение формы, и наш оператор if содержит для работы ?

Я, очень, рекомендую также взглянуть на

1 голос
/ 12 июля 2020

Вы действительно должны реализовать интерфейс MouseListener, и после щелчка мыши вы должны проверить, находится ли позиция мыши в области вашего круга. Вы можете сделать это вручную, сравнив координаты, но это может быть слишком много работы.
Я думаю, что проще создать объект Shape (на самом деле, сейчас хорошее время, чтобы узнать об этом, так как вы только начинаете), который вы заполняете соответствующим цветом, а затем просто проверяете, содержит ли круг мышь позиция.
Также просмотрите документацию класса Shape , когда у вас появится свободное время.

Я пошел дальше и внес изменения в ваш код, теперь он использует экземпляр класса Shape для создания круга.
Кроме того, вместо реализации интерфейса MouseListener я рекомендую расширить MouseAdapter, поскольку на самом деле вы не обеспечиваете какой-либо значимой реализации для любого метода интерфейса, кроме метода mousePressed().
Наконец, обратите внимание на shape.contains(event.getPoint()) в методе mousePressed(), это то, что делает трюк для проверки координат.
Остальная часть кода должна быть вам знакома.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;

public class CirclePop {

    JFrame frame;
    Circle circle;
    public static void main(String[] args) {
        CirclePop circlePop = new CirclePop();
        circlePop.drawFrame();
    }

    public void drawFrame() {
        frame = new JFrame();
        circle  = new Circle();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(circle);

        circle.addMouseListener(new Click());

        frame.setSize(300, 300);
        frame.setVisible(true);
    }

    class Click extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            if (circle.shape.contains(e.getPoint())) {
                System.out.println("Pressed");
            }
        }
    }
}
class Circle extends JPanel {
    Shape shape;
    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        shape = new Ellipse2D.Double(150, 140, 30, 30);
        g2.setColor(Color.red);
        g2.fill(shape);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...