JavaFX : Paint program with Canvas

标签 java canvas javafx-8 fxml

我需要使用 Canvas 场景创建一个 JavaFX 8 Paint 程序,但问题是当我在 Canvas 中拖动鼠标时尝试创建一个正方形或圆形时,我用 gcs[fig].clearRect(startX, startY, bufferX, bufferY); 使用缓冲区,但这会删除下面的图形。我不想要那样,它必须像 Windows 画图一样。也许一层可以帮助我,但我不知道该怎么做。

我使用一个 GraphicsContext 数组在数组的每个位置绘制图形。

我正在使用 NetBeans IDE

JavaFX FXML 应用程序

MicroPaint.java

package micropaint;

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


public class MicroPaint extends Application {

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene = new Scene(root);

    stage.setScene(scene);
    stage.show();
}

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

}

FXMLDocument.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.canvas.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="micropaint.FXMLDocumentController">
    <children>
      <ToolBar orientation="VERTICAL" prefHeight="453.0" prefWidth="107.0">
        <items>
          <Button fx:id="rectButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#setRectangleAsCurrentShape" text="Rectangulo" />
            <Button fx:id="lineButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#setLineAsCurrentShape" text="Linea" />
            <Button fx:id="ovlButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#setOvalAsCurrentShape" text="Ovalo" />
            <Button fx:id="pencButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#setFreeDesign" text="Lapiz" />
            <MenuButton mnemonicParsing="false" prefWidth="78.0" text="Borrador">
              <items>
                <MenuItem fx:id="eraser" mnemonicParsing="false" onAction="#setErase" text="Borrador" />
                <MenuItem fx:id="clean" mnemonicParsing="false" onAction="#clearCanvas" text="Limpiar" />
              </items>
            </MenuButton>
            <ColorPicker fx:id="colorPick" prefHeight="25.0" prefWidth="78.0" />
            <RadioButton fx:id="strokeRB" mnemonicParsing="false" selected="true" text="Stroke">
               <toggleGroup>
                  <ToggleGroup fx:id="shapes" />
               </toggleGroup>
            </RadioButton>
            <RadioButton fx:id="fillRB" mnemonicParsing="false" text="Fill" toggleGroup="$shapes" />
            <Slider fx:id="sliderSize" prefHeight="14.0" prefWidth="38.0" />          
        </items>
      </ToolBar>
      <Canvas fx:id="TheCanvas" height="453.0" layoutX="107.0" onMouseDragged="#onMouseDraggedListener" onMouseExited="#onMouseExitedListener" onMousePressed="#onMousePressedListener" onMouseReleased="#onMouseReleaseListener" width="512.0" />          
   </children>
</AnchorPane>

FXMLDocumentController.java

    package micropaint;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.MenuItem;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;

public class FXMLDocumentController implements Initializable {

    private GraphicsContext[] gcs;
    private GraphicsContext gc;
    private int fig=0;
    private boolean drawline = false,drawoval = false,drawrectangle = false,erase = false,freedesign = true;
    double startX, startY, lastX,lastY, bufferX,bufferY;
    double hg;

    @FXML private RadioButton strokeRB,fillRB;
    @FXML private Slider sliderSize;
    @FXML private ColorPicker colorPick;
    @FXML private Canvas TheCanvas;
    @FXML private Button rectButton,lineButton,ovlButton,pencButton;
    @FXML private MenuItem eraser;



    @FXML 
    private void clearCanvas(ActionEvent e){
        gc.setFill(Color.WHITE);
        gc.fillRect(0, 0, 515, 453);
    }

    //private int bufferFig=0;

    @FXML
    private void onMousePressedListener(MouseEvent e){

        sliderSize.setMin(0);
        sliderSize.setMax(300);
        this.hg = sliderSize.getValue();

        gcs[fig]=TheCanvas.getGraphicsContext2D();

        this.startX = e.getX();
        this.startY = e.getY();
        System.err.println("mousePressed at" + startX + ", "+ startY);
        /*if(drawoval)  
            this.dibujaOValo();
        if(drawrectangle)
            this.dibujaRect();*/
        bufferX = startX;
        bufferY = startY;
    }

    @FXML
    private void onMouseReleaseListener(MouseEvent e){
        //this.lastX = e.getX();
        //this.lastY = e.getY();
        //if(drawline)
        //    this.dibujarLinea();
        fig++;

        System.err.println(fig);
    }

    @FXML
    private void onMouseDraggedListener(MouseEvent e){
        this.lastX = e.getX() - startX;
        this.lastY = e.getY() - startY;

        if(drawoval)  
            this.dibujaOValo();
        if(drawrectangle)
            this.dibujaRect();
    }

    private void dibujaOValo(){
        gcs[fig].setFill(colorPick.getValue());
        gcs[fig].setStroke(colorPick.getValue());

        if(strokeRB.isSelected() == true){

            gcs[fig].strokeOval(startX, startY, lastX, lastY);
        }else
            gcs[fig].fillOval(startX, startY, lastX, lastY);
    }

    private void dibujaRect(){
        gcs[fig].setStroke(colorPick.getValue());
        gcs[fig].setFill(colorPick.getValue());

        if(strokeRB.isSelected() == true){
            gcs[fig].clearRect(startX, startY, bufferX, bufferY);
            gcs[fig].strokeRect(startX, startY, lastX, lastY);
        }else{
            gcs[fig].clearRect(startX, startY, bufferX, bufferY);
            gcs[fig].fillRect(startX, startY, lastX, lastY);
        }
        System.err.println(fig);
        bufferX = lastX;
        bufferY = lastY;
    }

    private void dibujarLinea(){
        gcs[fig].setFill(colorPick.getValue());
        gcs[fig].setStroke(colorPick.getValue());
        gcs[fig].setLineWidth(5);
        gcs[fig].strokeLine(startX, startY, lastX, lastY);
    }

   @FXML
    private void onMouseExitedListener(MouseEvent event){
        System.out.println("No puedes dibujar fuera del canvas");
    }

    @FXML
    private void setOvalAsCurrentShape(ActionEvent e){
        drawline = false;
        drawoval = true;
        drawrectangle = false;
        freedesign = false;
        erase = false;

    }

     @FXML
    private void setLineAsCurrentShape(ActionEvent e){
        drawline = true;
        drawoval = false;
        drawrectangle = false;
        freedesign = false;
        erase = false;
    }
     @FXML
    private void setRectangleAsCurrentShape(ActionEvent e){
        drawline = false;
        drawoval = false;
        freedesign = false;
        erase=false;
        drawrectangle = true;
    }

    @FXML
    private void setErase(ActionEvent e){
        drawline = false;
        drawoval = false;
        drawrectangle = false;    
        erase = true;
        freedesign= false;
    }

    @FXML
    private void setFreeDesign(ActionEvent e){
        drawline = false;
        drawoval = false;
        drawrectangle = false;    
        erase = false;
        freedesign = true;
    }



    @Override
    public void initialize(URL url, ResourceBundle rb) {
        gcs = new GraphicsContext[100];
        gc = TheCanvas.getGraphicsContext2D();
        gc.fillRect(100, 100, 100, 100);

        //////////////////////////////////
        Image imageRect = new Image(getClass().getResourceAsStream("Stop-32.png"));
        ImageView icR = new ImageView(imageRect);
        icR.setFitWidth(32);
        icR.setFitHeight(32);
        rectButton.setGraphic(icR);  

        Image imageLinea = new Image(getClass().getResourceAsStream("Ruler-32.png"));
        ImageView icLin = new ImageView(imageLinea);
        icLin.setFitWidth(32);
        icLin.setFitHeight(32);
        lineButton.setGraphic(icLin);

        Image imageOvalo = new Image(getClass().getResourceAsStream("Chart-32.png"));
        ImageView icOval = new ImageView(imageOvalo);
        icOval.setFitWidth(32);
        icOval.setFitHeight(32);
        ovlButton.setGraphic(icOval);

        Image imageLapiz = new Image(getClass().getResourceAsStream("Pencil-32.png"));
        ImageView icLapiz = new ImageView(imageLapiz);
        icLapiz.setFitWidth(32);
        icLapiz.setFitHeight(32);
        pencButton.setGraphic(icLapiz);
    }    

}

最佳答案

使用 JavaFX 8 绘画 - JavaFXML Canvas

这是我做的

MicroPaint.java

package micropaint;

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


public class MicroPaint extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

FXMLDocument.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.canvas.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="453.0" prefWidth="652.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="micropaint.FXMLDocumentController">
    <children>
      <ToolBar orientation="VERTICAL" prefHeight="453.0" prefWidth="107.0">
        <items>
          <Button fx:id="rectButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#setRectangleAsCurrentShape" text="Rectangulo" />
            <Button fx:id="lineButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#setLineAsCurrentShape" text="Linea" />
            <Button fx:id="ovlButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#setOvalAsCurrentShape" text="Ovalo" />
            <Button fx:id="pencButton" contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#setFreeDesign" text="Lapiz" />
            <MenuButton mnemonicParsing="false" prefWidth="78.0" text="Borrador">
              <items>
                <MenuItem fx:id="eraser" mnemonicParsing="false" onAction="#setErase" text="Borrador" />
                <MenuItem fx:id="clean" mnemonicParsing="false" onAction="#clearCanvas" text="Limpiar" />
              </items>
            </MenuButton>
            <ColorPicker fx:id="colorPick" prefHeight="25.0" prefWidth="78.0" />
            <RadioButton fx:id="strokeRB" mnemonicParsing="false" selected="true" text="Stroke">
               <toggleGroup>
                  <ToggleGroup fx:id="shapes" />
               </toggleGroup>
            </RadioButton>
            <RadioButton fx:id="fillRB" mnemonicParsing="false" text="Fill" toggleGroup="$shapes" />
            <Slider fx:id="sizeSlider" prefHeight="14.0" prefWidth="59.0" />          
        </items>
      </ToolBar>
      <Canvas fx:id="TheCanvas" height="453.0" layoutX="107.0" width="546.0" />
      <Canvas fx:id="canvasGo" height="453.0" layoutX="107.0" onMouseDragged="#onMouseDraggedListener" onMouseExited="#onMouseExitedListener" onMousePressed="#onMousePressedListener" onMouseReleased="#onMouseReleaseListener" width="546.0" />          
   </children>
</AnchorPane>

FXMLDocumentController.java

package micropaint;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;

/**
 *
 * @author CarlosA.
 */
public class FXMLDocumentController implements Initializable {
    //>>>>>>>>>>>>>>>>>>>>>>>Other variables<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    private GraphicsContext gcB,gcF;
    private boolean drawline = false,drawoval = false,drawrectangle = false,erase = false,freedesign = true;
    double startX, startY, lastX,lastY,oldX,oldY;
    double hg;
    //>>>>>>>>>>>>>>>>>>>>>>>FXML Variables<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    @FXML private RadioButton strokeRB,fillRB;
    @FXML private ColorPicker colorPick;
    @FXML private Canvas TheCanvas,canvasGo;
    @FXML private Button rectButton,lineButton,ovlButton,pencButton;
    @FXML private Slider sizeSlider;
    //////////////////////////////////////////////////////////////////////////////


    @FXML
    private void onMousePressedListener(MouseEvent e){
        this.startX = e.getX();
        this.startY = e.getY();
        this.oldX = e.getX();
        this.oldY = e.getY();
    }

    @FXML
    private void onMouseDraggedListener(MouseEvent e){
        this.lastX = e.getX();
        this.lastY = e.getY();

        if(drawrectangle)
            drawRectEffect();
        if(drawoval)
            drawOvalEffect();
        if(drawline)
            drawLineEffect();
        if(freedesign)
            freeDrawing();
    }

    @FXML
    private void onMouseReleaseListener(MouseEvent e){
        if(drawrectangle)
            drawRect();
        if(drawoval)
            drawOval();
        if(drawline)
            drawLine();
    }

    @FXML
    private void onMouseExitedListener(MouseEvent event)
    {
        System.out.println("No puedes dibujar fuera del canvas");
    }

    //>>>>>>>>>>>>>>>>>>>>>>>>>>>Draw methods<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    private void drawOval()
    {
        double wh = lastX - startX;
        double hg = lastY - startY;
        gcB.setLineWidth(sizeSlider.getValue());

        if(fillRB.isSelected()){
            gcB.setFill(colorPick.getValue());
            gcB.fillOval(startX, startY, wh, hg);
        }else{
            gcB.setStroke(colorPick.getValue());
            gcB.strokeOval(startX, startY, wh, hg);
        }
    }

    private void drawRect()
    {
        double wh = lastX - startX;
        double hg = lastY - startY;
        gcB.setLineWidth(sizeSlider.getValue());

        if(fillRB.isSelected()){
            gcB.setFill(colorPick.getValue());
            gcB.fillRect(startX, startY, wh, hg);
        }else{
            gcB.setStroke(colorPick.getValue());
            gcB.strokeRect(startX, startY, wh, hg);
        }
    }

    private void drawLine()
    {
        gcB.setLineWidth(sizeSlider.getValue());
        gcB.setStroke(colorPick.getValue());
        gcB.strokeLine(startX, startY, lastX, lastY);
    }

    private void freeDrawing()
    {
        gcB.setLineWidth(sizeSlider.getValue());
        gcB.setStroke(colorPick.getValue());
        gcB.strokeLine(oldX, oldY, lastX, lastY);
        oldX = lastX;
        oldY = lastY;
    }

    //////////////////////////////////////////////////////////////////////
    //>>>>>>>>>>>>>>>>>>>>>>>>>>Draw effects methods<<<<<<<<<<<<<<<<<<<<<<<

    private void drawOvalEffect()
    {
        double wh = lastX - startX;
        double hg = lastY - startY;
        gcF.setLineWidth(sizeSlider.getValue());

        if(fillRB.isSelected()){
            gcF.clearRect(0, 0, canvasGo.getWidth(), canvasGo.getHeight());
            gcF.setFill(colorPick.getValue());
            gcF.fillOval(startX, startY, wh, hg);
        }else{
            gcF.clearRect(0, 0, canvasGo.getWidth(), canvasGo.getHeight());
            gcF.setStroke(colorPick.getValue());
            gcF.strokeOval(startX, startY, wh, hg );
        }
       }

    private void drawRectEffect()
    {
        double wh = lastX - startX;
        double hg = lastY - startY;
        gcF.setLineWidth(sizeSlider.getValue());

        if(fillRB.isSelected()){
            gcF.clearRect(0, 0, canvasGo.getWidth(), canvasGo.getHeight());
            gcF.setFill(colorPick.getValue());
            gcF.fillRect(startX, startY, wh, hg);
        }else{
            gcF.clearRect(0, 0, canvasGo.getWidth(), canvasGo.getHeight());
            gcF.setStroke(colorPick.getValue());
            gcF.strokeRect(startX, startY, wh, hg );
        }
    }

    private void drawLineEffect()
    {
        gcF.setLineWidth(sizeSlider.getValue());
        gcF.setStroke(colorPick.getValue());
        gcF.clearRect(0, 0, canvasGo.getWidth() , canvasGo.getHeight());
        gcF.strokeLine(startX, startY, lastX, lastY);
    }
    ///////////////////////////////////////////////////////////////////////

    @FXML 
    private void clearCanvas(ActionEvent e)
    {
        gcB.clearRect(0, 0, TheCanvas.getWidth(), TheCanvas.getHeight());
        gcF.clearRect(0, 0, TheCanvas.getWidth(), TheCanvas.getHeight());
    }


    //>>>>>>>>>>>>>>>>>>>>>Buttons control<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    @FXML
    private void setOvalAsCurrentShape(ActionEvent e)
    {
        drawline = false;
        drawoval = true;
        drawrectangle = false;
        freedesign = false;
        erase = false;
    }

     @FXML
    private void setLineAsCurrentShape(ActionEvent e)
    {
        drawline = true;
        drawoval = false;
        drawrectangle = false;
        freedesign = false;
        erase = false;
    }
     @FXML
    private void setRectangleAsCurrentShape(ActionEvent e)
    {
        drawline = false;
        drawoval = false;
        freedesign = false;
        erase=false;
        drawrectangle = true;
    }

    @FXML
    private void setErase(ActionEvent e)
    {
        drawline = false;
        drawoval = false;
        drawrectangle = false;    
        erase = true;
        freedesign= false;
    }

    @FXML
    private void setFreeDesign(ActionEvent e)
    {
        drawline = false;
        drawoval = false;
        drawrectangle = false;    
        erase = false;
        freedesign = true;
    }

    //////////////////////////////////////////////////////////////////


    @Override
    public void initialize(URL url, ResourceBundle rb) {
        gcB = TheCanvas.getGraphicsContext2D();
        gcF = canvasGo.getGraphicsContext2D();

        sizeSlider.setMin(1);
        sizeSlider.setMax(50);

        //////////////////////////////////
        Image imageRect = new Image(getClass().getResourceAsStream("Stop-32.png"));
        ImageView icR = new ImageView(imageRect);
        icR.setFitWidth(32);
        icR.setFitHeight(32);
        rectButton.setGraphic(icR);  

        Image imageLinea = new Image(getClass().getResourceAsStream("Ruler-32.png"));
        ImageView icLin = new ImageView(imageLinea);
        icLin.setFitWidth(32);
        icLin.setFitHeight(32);
        lineButton.setGraphic(icLin);

        Image imageOvalo = new Image(getClass().getResourceAsStream("Chart-32.png"));
        ImageView icOval = new ImageView(imageOvalo);
        icOval.setFitWidth(32);
        icOval.setFitHeight(32);
        ovlButton.setGraphic(icOval);

        Image imageLapiz = new Image(getClass().getResourceAsStream("Pencil-32.png"));
        ImageView icLapiz = new ImageView(imageLapiz);
        icLapiz.setFitWidth(32);
        icLapiz.setFitHeight(32);
        pencButton.setGraphic(icLapiz);
    }    

}

我在 FXML 文档中使用了两个 Canvas,所以我使用一个用于效果,另一个用于最终图形。 橡皮擦还不行,可以改进一下

关于JavaFX : Paint program with Canvas,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33466871/

相关文章:

java - JavaFX 中的桌面类

java - 如何在 JDBC 中设置游标类型?

java - 值图不是模型的成员

javascript - DrawImage 不会在第一帧加载

javascript - 对象与 Canvas 上对象矩阵之间的碰撞

javafx - 为TreeView设置两个根节点

java - 在 JavaFX 游戏中使用 Node 对象作为 GameObject 是否高效?

java - Java 中 LTRIM 和 RTRIM 的一个好的替代方案是什么?

java - 如何按角色限制对 Spring Data REST 投影的访问?

javascript - Konva从点击事件中获取图像ID