JavaFX проблема с вводом мышью при рисовании фигур? - PullRequest
0 голосов
/ 05 апреля 2020

Я недавно перешел на JavaFX для создания программы рисования с использованием мыши. Я столкнулся с проблемой, пытаясь наложить прямоугольник на свой холст - он, кажется, не go, где я хочу. Я потратил часы, пытаясь взломать это, и я думаю, что мне нужна помощь. Код ниже:

Кажется, проблема в том, что координаты продолжают обновляться, пока я двигаю мышью, чего я не хочу, чтобы это происходило. Я хочу, чтобы пользователь щелкнул мышью и перетащил ее, а затем в конце прямоугольник будет создан на основе координат движения мыши. То же самое происходит и с инструментом линии, так как он будет работать точно так же, как инструмент bru sh, и все больше и больше фигур опускаются при перемещении мыши по экрану. Все это относится к классу контроллеров.

Основной класс

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(FXMLLoader.load(getClass().getResource("sample.fxml"))));
        stage.setTitle("Paint");
        stage.show();
    }


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

Контроллер

package sample;

import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.image.Image;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.File;

public class Controller {
    int prevX, prevY, startX, startY, x , y;
    boolean dragging;

    @FXML
    private Canvas canvas;

    @FXML
    private ColorPicker colorPicker;

    @FXML
    private TextField brushSize;

    @FXML
    private ToggleButton eraser;

    @FXML
    private ToggleButton line;

    @FXML
    private ToggleButton rectangle;

    public void initialize() {
        GraphicsContext g = canvas.getGraphicsContext2D();

        canvas.setOnMousePressed(e -> {
            startX = prevX = x = (int) e.getX();
            startX = prevY = y = (int) e.getY();
            dragging = true;
        });

        canvas.setOnMouseReleased(e -> {
            dragging = false;
        });

        canvas.setOnMouseDragged(e -> {
            double size = Double.parseDouble(brushSize.getText());
            if(!dragging)
                return;
            double x = e.getX();
            double y = e.getY();
            if(eraser.isSelected()) {
                g.clearRect(x, y, size, size);
            } else if(line.isSelected()) {
                g.strokeLine(prevX, prevY, x, y);  //                 also experiencing issues
            } else if(rectangle.isSelected()) {
                putRect(g, false, startX, startY, x, y); //           this puts the rectangle on the canvas
            } else {
                g.setStroke(colorPicker.getValue());
                g.setLineWidth(size);
                g.strokeLine(prevX, prevY, x, y);
            }
            prevX = (int) x;
            prevY = (int) y;
        });
    }

    public void putRect(GraphicsContext g, boolean filled, int x1, int y1, int x2, int y2) { // to create the rectangle
        if(x1 == x2 || y1 == y2) {
            return;
        } else {
            int x = Math.min(x1,x2);    // get upper left corner, (x,y)
            int y = Math.min(y1,y2);
            int w = Math.abs(x1 - x2);  // get width and height
            int h = Math.abs(y1 - y2);
            if (filled) {
                g.fillRect(x, y, w, h);
            } else {
                g.strokeRect(x, y, w, h);
            }
        }
    }

    public void onSave() {
        try{
            Image snapshot = canvas.snapshot(null, null);

            ImageIO.write(SwingFXUtils.fromFXImage(snapshot, null), "png", new File("paintsave.png"));
        } catch (Exception e) {
            System.out.println("Failed to save: " + e);
        }
    }

    public void onExit() {
        Platform.exit();
    }
}

F XML

<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ColorPicker?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.control.ToggleButton?>
<BorderPane fx:controller="sample.Controller"
            xmlns:fx="http://javafx.com/fxml"
            prefHeight="600.0" prefWidth="600.0">

    <top>
        <VBox>
            <MenuBar>
                <Menu text="file">
                    <MenuItem text="Save" onAction="#onSave"/>
                    <MenuItem text="Exit" onAction="#onExit"/>
                </Menu>
            </MenuBar>

            <ToolBar>
                <HBox alignment="CENTER" spacing="5">
                    <TextField fx:id="brushSize" text="18"/>
                    <ColorPicker fx:id="colorPicker"/>
                    <ToggleButton fx:id="eraser" text="Eraser"/>
                    <ToggleButton fx:id="line" text="Line"/>
                    <ToggleButton fx:id="rectangle" text="Rectangle"/>
                </HBox>
            </ToolBar>
        </VBox>
    </top>

    <center>
        <Canvas fx:id="canvas" width="600" height="600"/>
    </center>

</BorderPane>

1 Ответ

0 голосов
/ 05 апреля 2020

Следующая часть кода проблематична c:

canvas.setOnMouseDragged(e -> {
  double size = Double.parseDouble(brushSize.getText());
  if(!dragging)
    return;         
  double x = e.getX();
  double y = e.getY();      
  if(eraser.isSelected()) {
    g.clearRect(x, y, size, size);
  } else if(line.isSelected()) {
    g.strokeLine(prevX, prevY, x, y);  // also experiencing issues
  } else if(rectangle.isSelected()) {
    putRect(g, false, startX, startY, x, y); // this puts the rectangle on the canvas
  } else {
    g.setStroke(colorPicker.getValue());
    g.setLineWidth(size);
    g.strokeLine(prevX, prevY, x, y);
  }
  prevX = (int) x;
  prevY = (int) y;
});

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

Я предлагаю два разных подхода к решению этой проблемы:

  1. Сохранение координат, где была мышь, когда эта функция была вызвана в последний раз. Таким образом, каждый раз, когда вызывается функция, вы должны перерисовывать объект с прошлого раза, но заполняя его цветом фона. Это должно действовать как «удаление» объекта, который вы рисуете в прошлый раз. Это должно работать, если ваши объекты не перекрываются. Если они это сделают, это может удалить их часть.
  2. Создание копии холста перед началом рисования. Поэтому каждый раз, когда вызывается функция, сбрасывайте холст в состояние копии, а затем рисуйте свой объект.

Надеюсь, что-нибудь из этого сработает для вас.

...