Обведите после положения мыши, пока не нажмете - PullRequest
0 голосов
/ 29 октября 2018

Я хочу сделать проект, который включает рисование круга в графическом интерфейсе Java. Если щелкнуть круг или область вокруг круга, круг должен «прилипать» к курсору и следовать ему до тех пор, пока не произойдет повторный щелчок мышью. Тогда круг должен остаться там, где вы нажали.

Я сделал все до того момента, когда программа обнаружит, что вы нажали на круг. Обведите кружком рисунок, сделанный g2 методом g2.fillOval.

Есть два класса:

MainClass.java

public class MainClass {

    public static void main(String[] args){

        ExampleGUI g = new ExampleGUI();

    }
}

ExampleGUI.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class ExampleGUI extends JFrame {

    Graphics2D g2;

    Point point = new Point(150,150);

    ExampleGUI() {
        MouseListener ml = new MouseListener() {

            @Override
            public void mouseClicked(MouseEvent e) {

            }

            @Override
            public void mousePressed(MouseEvent e) {
                Point clicked = new Point(e.getLocationOnScreen().x - getX(),e.getLocationOnScreen().y - getY());

                if(clickedaroundpoint(clicked)){
                    System.out.println("Clicked on Point");
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {

            }

            @Override
            public void mouseEntered(MouseEvent e) {

            }

            @Override
            public void mouseExited(MouseEvent e) {

            }
        };

        this.addMouseListener(ml);
        setTitle("FlamingoBall");
        setSize(300,300);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        this.setVisible(true);
    }

    private boolean clickedaroundpoint(Point clicked) {
        if(Point.distance(point.x+2,point.y+2,clicked.x,clicked.y)<=5){
            return true;
        }
        return false;
    }

    public void paint(Graphics g) {
        super.paintComponents(g);
        g2 = (Graphics2D) g;
        g2.setColor(Color.RED);
        g2.fillOval(point.x,point.y,7,7);
    }
}

Пожалуйста, дайте мне знать, как лучше идти дальше.

1 Ответ

0 голосов
/ 29 октября 2018

Вам нужно добавить MouseMotionListener и реализовать mouseMoved() или mouseDragged(), если хотите.

Есть несколько способов, как вы могли бы сделать это. Это зависит от того, хотите ли вы щелкнуть-переместить или перетащить. Разница:

  • click-move: нажмите, отпустите, переместите, нажмите, отпустите
  • перетаскивание: нажмите, переместите, отпустите

Click-ход

В этом случае вам нужно реализовать

  • Обработчик mouseClicked() наблюдателя MouseListener для переключения boolean и запоминания начальной позиции движения.
  • mouseMoved() наблюдателя MouseMotionListener для выполнения фактического движения.

Как это:

class Mover implements MouseListener, MouseMotionListener {
    private boolean moving;
    private Point movementOrigin;
    public void mouseClicked(MouseEvent e) {
        if (moving = !moving)
            movementOrigin = e.getPoint();
    }
    public void mouseMoved(MouseEvent e) {
        if (!moving) return;
        Point pos = e.getPoint();
        Point delta = new Point(pos.getX() - movementOrigin.getX(), pos.getY() - movementOrigin.getY());
        // TODO Relocate the circle with that delta
        repaint();
    }
}

Drag

В этом случае вам нужно реализовать * Обработчик mousePressed() наблюдателя MouseListener для начальной позиции перетаскивания. * Обработчик mouseDragged() наблюдателя MouseMotionListener для отслеживания перетаскивания.

Единственное отличие от предыдущего кода в том, что вам не нужен этот логический переключатель.

Примечание об оригинальном ответе

В своем первоначальном ответе я предложил динамически добавлять / удалять MouseMotionListener в соответствующем событии MouseListener. Я больше не думаю, что это хорошая идея, потому что не существует «дешевого» способа определить, был ли уже зарегистрирован наблюдатель, и, таким образом, в любом случае понадобится логическое значение.

Примечание о коде

Я не думаю, что хорошо иметь поле типа Graphics2D, инициализированное методом paint(). Действительность экранного объекта Graphics, вероятно, связана с деревом вызовов repaint(). Вызов его методов вне дерева вызовов repaint(), вероятно, приведет к неопределенному поведению. Время жизни объекта Graphics - это дерево вызовов repaint(), а не объект ExampleGUI, и код должен отражать это, не кэшируя его в поле.

Расширение классов пользовательского интерфейса (ваш extends JFrame) для использования является анти-паттерном и нарушает принцип подстановки Лискова. Наследование (все еще) чрезмерно используется. Попробуйте использовать делегирование вместо наследования.

...