在Gridpane中的“画布中绘图”选择工具

时间:2018-08-07 18:02:43

标签: multithreading canvas javafx

在附件中,我放置了项目的图像,从本质上讲,我想在画布上绘制其他形状的图形,例如线条,圆形,矩形,三角形等,当我单击相对按钮时,我是新手javafx编程,现在我了解的是,画布只能在GUI的主线程中进行修改,这就是问题所在,因为当我处理按钮事件“ SetonAction”时,我需要主画布的引用画线或曲线我尝试使用新的线程,但没有成功。 如果有人知道如何做到这一点,我真的很高兴。感谢您的建议enter image description here

对我来说,解决这个问题很困难,因此我做了一些简单的代码来了解事情的原理,请看一下:

 public class TE1 extends Application {

private Pane root;
private Pane left;
private StackPane right;
private StackPane drawcontainer;
private CustomizedButton btn;
private CustomizedButton btn1;
private Canvas Drawtable;
private SplitPane divisor;
private double x;
private double y;
private double to_x = 0;
private double to_y = 0;
private int line_no = 1;

@Override
public void start(Stage primaryStage) {
            root = new StackPane();

    Drawtable = new Canvas(400,400);
    Drawtable.setWidth(400);
    Drawtable.setHeight(400);
    GraphicsContext gc = Drawtable.getGraphicsContext2D();
    gc.setFill(Color.CADETBLUE);
    gc.fillRect(0, 0, 800, 850);



    left = new Pane();
    left.setMinSize(400,400);
    left.setStyle("-fx-background-color:#d7d6d5;");
    right= new StackPane();
    right.setAlignment(Pos.CENTER);
   // right.setStyle("-fx-background-color: #FFFFFF;");
    right.setMinSize(400, 400);


    divisor = new SplitPane();


    //root.addEventFilter(DrawEvent.DRAW_TYPE,new DrawEventHandler());
    //root.addEventHandler(DrawEvent.DRAW_TYPE,new DrawEventHandler());
    Drawtable.addEventFilter(DrawEvent.DRAW_TYPE,new DrawEventHandler());
    // right.getChildren().add(Drawtable);

    btn = new CustomizedButton();
    btn1= new CustomizedButton();
    btn.Set_identity("linea");
    btn1.setMinSize(50,50);
    btn.setMinSize(50,50);
    btn.setMaxSize(50, 50);
    btn.setLayoutX(100);
    btn.setLayoutY(100);
    btn1.setLayoutX(100);
    btn1.setLayoutY(180);

    btn.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {

            this.fireEvent();

        }

          public void fireEvent()
         {  
             Runnable task = ()-> runTask();
             Thread background = new Thread(task);
             background.setDaemon(true);
             background.start();




         }


         public void runTask()
         {      


             while(btn.isFocused()){
                 System.out.println("SONO ATTIVO ");
                 Drawtable.setOnMousePressed((event) ->setFromPos(event));
                 System.out.println("x vale :"+x+"y vale: "+y);

                 Drawtable.setOnMouseDragged((event)->
                 {
                     right.getChildren().remove(0);

                     Canvas temp_canvas = new Canvas(400, 400);
                     GraphicsContext gc =  temp_canvas.getGraphicsContext2D();
                      gc.setFill(Color.BLUEVIOLET);
                    // setToPos(event);
                    // drawLine(gc);
                     right.getChildren().add(0,temp_canvas);


                 });

                 Drawtable.setOnMouseReleased((event) -> {
                     final Canvas new_line = new Canvas(400, 400);
                     final GraphicsContext gc = new_line.getGraphicsContext2D();
                     setToPos(event);
                     drawLine(gc);
                    //final new stright line
                    right.getChildren().add(line_no++,new_line);             
                 });

             }

         }






    });




    right.getChildren().addAll( new Canvas(), Drawtable);
    left.getChildren().add(btn);
    left.getChildren().add(btn1);
    divisor.getItems().addAll(left,right);

    root.getChildren().addAll(divisor);



    Scene scene = new Scene(root, 800, 850);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}




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

 private void setFromPos(MouseEvent event) {
    this.x = event.getX();
    this.y = event.getY();
}
  private void setToPos(MouseEvent event) {
    this.to_x = event.getX();
    this.to_y = event.getY();
}  


private void drawLine(GraphicsContext gc) {
    gc.setFill(Color.RED);
    gc.setStroke(Color.BLACK);
    gc.setLineWidth(1);
    gc.strokeLine(x, y, to_x, to_y);      
     }

  }

感谢您的咨询

2 个答案:

答案 0 :(得分:0)

我以某种方式成功完成了,我修改了这样的代码:

   public class TE1 extends Application {

           private Pane root;
           private Pane left;
           private StackPane right;
           private StackPane drawcontainer;
           private CustomizedButton btn;
           private CustomizedButton btn1;
           private Canvas Drawtable;
           private SplitPane divisor;
           private double x;
           private double y;
           private double to_x = 0;
           private double to_y = 0;
           private int line_no = 1;
           private Thread background;

@Override
public void start(Stage primaryStage) {
            root = new StackPane();

    Drawtable = new Canvas(400,400);
    Drawtable.setWidth(400);
    Drawtable.setHeight(400);
    GraphicsContext gc = Drawtable.getGraphicsContext2D();




    left = new Pane();
    left.setMinSize(400,400);
    left.setStyle("-fx-background-color:#d7d6d5;");
    right= new StackPane();
    right.setAlignment(Pos.CENTER);
    right.setStyle("-fx-background-color: #FFFFFF;");
    right.setMinSize(400, 400);


    divisor = new SplitPane();


    btn = new CustomizedButton();
    btn1= new CustomizedButton();
    btn.Set_identity("linea");
    btn1.setMinSize(50,50);
    btn.setMinSize(50,50);
    btn.setMaxSize(50, 50);
    btn.setLayoutX(100);
    btn.setLayoutY(100);
    btn1.setLayoutX(100);
    btn1.setLayoutY(180);

    btn.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {

            this.fireEvent();

        }

          public void fireEvent()
         {  
             Runnable task = ()-> runTask();
             Thread background = new Thread(task);
             background.setDaemon(true);
             background.start();

         }


         public void runTask() 
         {      


             while(btn.isFocused()){
                 System.out.println("SONO ATTIVO ");
                 Drawtable.setOnMousePressed((event) ->setFromPos(event));
                 System.out.println("x vale :"+x+"y vale: "+y);

                 Drawtable.setOnMouseDragged((event)->
                 {

                     right.getChildren().remove(0);

                     Canvas temp_canvas = new Canvas(400, 400);
                     GraphicsContext gc = temp_canvas.getGraphicsContext2D();

                     setToPos(event);
                     drawLine(gc);
                     right.getChildren().add(0,temp_canvas);


                 });

                 Drawtable.setOnMouseReleased((event) -> {
                     final Canvas new_line = new Canvas(400, 400);
                     final GraphicsContext gc = new_line.getGraphicsContext2D();
                     setToPos(event);
                     drawLine(gc);
                    //final new stright line
                    right.getChildren().add(line_no++,new_line);             
                 });

             }
           System.out.println("Focused btn state :"+btn.isFocused());

            background.interrupt();
         }






    });




    right.getChildren().addAll( new Canvas(), Drawtable);
    left.getChildren().add(btn);
    left.getChildren().add(btn1);
    divisor.getItems().addAll(left,right);

    root.getChildren().addAll(divisor);



    Scene scene = new Scene(root, 800, 850);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}




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

 private void setFromPos(MouseEvent event) {
    this.x = event.getX();
    this.y = event.getY();
}
  private void setToPos(MouseEvent event) {
    this.to_x = event.getX();
    this.to_y = event.getY();
}  


private void drawLine(GraphicsContext gc) {
    gc.setFill(Color.RED);
    gc.setStroke(Color.BLACK);
    gc.setLineWidth(1);
    gc.strokeLine(x, y, to_x, to_y);      
    }

 }

但是现在我不明白为什么按钮没有对准焦点不会停止的原因 在画布上画线。任何建议?

答案 1 :(得分:0)

这里没有必要使用多线程,也不是一个好主意。

注册事件处理程序不是一项长期运行的操作,并且一遍又一遍地重新分配具有相同逻辑的匿名类不会改变任何事情。此外,这些修改需要在JavaFX应用程序线程中进行。

应该提及的另一个问题是您在鼠标手势期间重新创建Canvas。您应该避免这样做,而应重用现有的Canvas。还应避免每行堆叠一个Canvas。如果您需要一个画布作为当前绘制的线条,而一个画布作为完整的线条,则为2 Canvas。使用Lines会更容易实现btw。

我也建议ToggleButton用于此类任务。这使您可以访问与焦点无关的状态。而不是重复查询状态,您应该侦听属性(无论您使用的是selected还是focused来添加/删除侦听器)

private Pane root;
private Pane left;
private StackPane right;
private Button btn1;
private Canvas Drawtable;

private Canvas drawingCanvas;
private GraphicsContext drawingContext;

private SplitPane divisor;

@Override
public void start(Stage primaryStage) {
    root = new StackPane();

    Drawtable = new Canvas(400, 400);
    Drawtable.setWidth(400);
    Drawtable.setHeight(400);

    // second Canvas for drawing stacked on top of the other canvas
    drawingCanvas = new Canvas(Drawtable.getWidth(), Drawtable.getHeight());
    drawingContext = drawingCanvas.getGraphicsContext2D();

    left = new Pane();
    left.setMinSize(400, 400);
    left.setStyle("-fx-background-color:#d7d6d5;");
    right = new StackPane(Drawtable, drawingCanvas);
    right.setAlignment(Pos.CENTER);
    right.setStyle("-fx-background-color: #FFFFFF;");
    right.setMinSize(400, 400);

    divisor = new SplitPane();

    ToggleButton btn = new ToggleButton();
    btn1 = new Button();
    btn.setText("linea");
    btn1.setMinSize(50, 50);
    btn.setMinSize(50, 50);
    btn.setMaxSize(50, 50);
    btn.setLayoutX(100);
    btn.setLayoutY(100);
    btn1.setLayoutX(100);
    btn1.setLayoutY(180);

    btn.selectedProperty().addListener(new ChangeListener<Boolean>() {

        private double x;
        private double y;

        private void drawLine(GraphicsContext gc, double endX, double endY) {
            gc.setStroke(Color.BLACK);
            gc.setLineWidth(1);
            gc.strokeLine(x, y, endX, endY);
        }

        private final EventHandler<MouseEvent> pressedHandler = (event) -> {
            x = event.getX();
            y = event.getY();
        };

        private final EventHandler<MouseEvent> draggedHandler = (event) -> {
            // remove old content & draw new content
            drawingContext.clearRect(0, 0, drawingCanvas.getWidth(), drawingCanvas.getHeight());
            drawLine(drawingContext, event.getX(), event.getY());
        };

        private final EventHandler<MouseEvent> releasedHandler = (event) -> {
            // clear canvas for line drawing
            drawingContext.clearRect(0, 0, drawingCanvas.getWidth(), drawingCanvas.getHeight());

            // draw line on background canvas
            final GraphicsContext gc = Drawtable.getGraphicsContext2D();
            drawLine(gc, event.getX(), event.getY());
        };

        @Override
        public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
            // add/remove event handlers based on toggle state of the button
            if (newValue) {
                drawingCanvas.addEventHandler(MouseEvent.MOUSE_PRESSED, pressedHandler);
                drawingCanvas.addEventHandler(MouseEvent.MOUSE_DRAGGED, draggedHandler);
                drawingCanvas.addEventHandler(MouseEvent.MOUSE_RELEASED, releasedHandler);
            } else {
                drawingCanvas.removeEventHandler(MouseEvent.MOUSE_PRESSED, pressedHandler);
                drawingCanvas.removeEventHandler(MouseEvent.MOUSE_DRAGGED, draggedHandler);
                drawingCanvas.removeEventHandler(MouseEvent.MOUSE_RELEASED, releasedHandler);
            }
        }

    });

    left.getChildren().add(btn);
    left.getChildren().add(btn1);
    divisor.getItems().addAll(left, right);

    root.getChildren().addAll(divisor);

    Scene scene = new Scene(root, 800, 850);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}