2017-10-31 17 views
0

私が取り組んでいるプログラムは、StackPane上にキャンバスレイヤーを使用して、テキストやイメージを塗りつぶすだけです。私が達成したいのは、MouseEvent.MOUSE_RELEASEDハンドラをマウスで放すと自動的にキャンバスのスナップショットが取得され、画像はImageView Coverに追加され、TextAreaの上に表示されますが、変更はクラスStackPaneに追加できませんすなわち、ImageViewです。テキスト領域での描画方法は?

ここで私が取り組んでいるのは、私が取り組んでいる別のプログラムに追加するプログラムです。メインクラスのTextCanvasのすべてをメインプロジェクトのメニューコントローラクラスに取り込む予定です。

メインクラスTextCanvas.java:

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.File; 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javafx.application.Application; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.embed.swing.SwingFXUtils; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.SnapshotParameters; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.control.Button; 
import javafx.scene.control.ScrollPane; 
import javafx.scene.control.TextArea; 
import javafx.scene.control.Toggle; 
import javafx.scene.control.ToggleButton; 
import javafx.scene.control.ToggleGroup; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 
import javafx.scene.image.PixelReader; 
import javafx.scene.image.PixelWriter; 
import javafx.scene.image.WritableImage; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.StackPane; 
import javafx.scene.layout.VBox; 
import javafx.scene.paint.Color; 
import javafx.stage.Screen; 
import javafx.stage.Stage; 
import javax.imageio.ImageIO; 

public class TextCanvas extends Application 
{ 
    private ScrollPane Scroll = new ScrollPane(); 

    Canvas Can = new Canvas(800, 400); 
    GraphicsContext GG = Can.getGraphicsContext2D(); 

    TextArea TA = new TextArea(); 

    ImageView Cover = new ImageView(); 

    VBox ButtonBox = new VBox(); 

    WordCanvas WC = new WordCanvas(Can, TA, GG); 

    @Override 
    public void start(Stage PrimaryStage) 
    { 
     ToggleGroup DrawErase = new ToggleGroup(); 

     ToggleButton Draw = new ToggleButton("Draw"); 
     ToggleButton Erase = new ToggleButton("Erase"); 
     Button Clear = new Button("Clear"); 
     Draw.setToggleGroup(DrawErase); 
     Erase.setToggleGroup(DrawErase); 

     double DotsPerInch = Screen.getPrimary().getDpi(); 
     double W = DotsPerInch * 8.5; 
     double H = DotsPerInch * 11.0; 

     StackPane Stack = new WordCanvas(W, H); 

     WC.GetArea().setMaxWidth(W); 
     WC.GetArea().setMaxHeight(H); 
     WC.GetCan().setWidth(W); 
     WC.GetCan().setHeight(H); 

     DrawErase.selectedToggleProperty().addListener(new ChangeListener<Toggle>() 
     { 
      public void changed(ObservableValue<? extends Toggle> OV, Toggle TOld, Toggle TNew) 
      { 
       if(TNew == null) 
       { 
        GG.setStroke(Color.TRANSPARENT); 

        Stack.getChildren().remove(WC.GetCan()); 
       } 
       else if(DrawErase.getSelectedToggle().equals(Draw)) 
       { 
        GG.setStroke(Color.BLACK); 

        if(!Stack.getChildren().contains(WC.GetCan())) 
        { 
         Stack.getChildren().add(WC.GetCan()); 
        } 
       } 
       else if(DrawErase.getSelectedToggle().equals(Erase)) 
       { 
        GG.setStroke(Color.WHITE); 

        if(!Stack.getChildren().contains(WC.GetCan())) 
        { 
         Stack.getChildren().add(WC.GetCan()); 
        } 
       } 
      } 
     }); 

     Clear.setOnAction(new EventHandler<ActionEvent>() 
     { 
      @Override 
      public void handle(ActionEvent e) 
      { 
       WC.GetGC().clearRect(0, 0, W, H); 

       Stack.getChildren().remove(WC.GetCover()); 
      } 
     }); 

     Button Snap = new Button("Snap"); 

     Snap.setOnAction(new EventHandler<ActionEvent>() 
     { 
      @Override 
      public void handle(ActionEvent e) 
      { 
       Cover.setMouseTransparent(true); 

       WritableImage WImage = Can.snapshot(new SnapshotParameters(), null); 

       ByteArrayOutputStream Bos = new ByteArrayOutputStream(); 

       try 
       { 
        ImageIO.write(SwingFXUtils.fromFXImage(WImage, null), "png", Bos); 
       } 
       catch(IOException ex) 
       { 
        Logger.getLogger(WordCanvas.class.getName()).log(Level.SEVERE, null, ex); 
       } 

       InputStream Fis = new ByteArrayInputStream(Bos.toByteArray()); 
       Image Imos = new Image(Fis); 

       int IW = (int) Imos.getWidth(); 
       int IH = (int) Imos.getHeight(); 

       WritableImage OutputImage = new WritableImage(IW, IH); 
       PixelReader PReader = Imos.getPixelReader(); 
       PixelWriter PWriter = OutputImage.getPixelWriter(); 

       for (int y = 0; y < IH; y++) 
       { 
        for (int x = 0; x < IW; x++) 
        { 
         int argb = PReader.getArgb(x, y); 

         int r = (argb >> 16) & 0xFF; 
         int g = (argb >> 8) & 0xFF; 
         int b = argb & 0xFF; 

         if(r >= 0xCF && g >= 0xCF && b >= 0xCF) 
         { 
          argb &= 0x00FFFFFF; 
         } 

         PWriter.setArgb(x, y, argb); 
        } 
       } 

       if(!Stack.getChildren().contains(WC.GetCover())) 
       { 
        WC.GetCover().setImage(OutputImage); 

        Stack.getChildren().add(WC.GetCover()); 
       } 
       else 
       { 
        WC.GetCover().setImage(OutputImage); 
       } 
      } 
     }); 

     ButtonBox.getChildren().addAll(Draw, Erase, Clear, Snap); 

     BorderPane Border = new BorderPane(); 
     Border.setCenter(Stack); 
     Border.setBottom(ButtonBox); 

     Scroll.setContent(Border); 
     Scroll.setFitToWidth(true); 
     Scroll.setFitToHeight(true); 

     Scene MainScene = new Scene(Scroll); 

     PrimaryStage.setMaximized(true); 
     PrimaryStage.setTitle("Practice Canvas"); 
     PrimaryStage.setScene(MainScene); 
     PrimaryStage.show(); 
    } 

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

二のTextAreaとキャンバスを含むクラス:私はするつもりのようにスナップボタンハンドラが作業を行うメインクラスで

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.File; 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javafx.embed.swing.SwingFXUtils; 
import javafx.event.EventHandler; 
import javafx.geometry.Insets; 
import javafx.scene.Cursor; 
import javafx.scene.SnapshotParameters; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.control.TextArea; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 
import javafx.scene.image.PixelReader; 
import javafx.scene.image.PixelWriter; 
import javafx.scene.image.WritableImage; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.layout.Background; 
import javafx.scene.layout.BackgroundFill; 
import javafx.scene.layout.CornerRadii; 
import javafx.scene.layout.StackPane; 
import javafx.scene.paint.Color; 
import javax.imageio.ImageIO; 

public class WordCanvas extends StackPane 
{ 
    private Canvas Can = new Canvas(); 

    private GraphicsContext GC = Can.getGraphicsContext2D(); 

    private TextArea Area = new TextArea(); 

    private ImageView Cover = new ImageView(); 

    double Width; 
    double Height; 

    public WordCanvas() 
    { 
     CreateUI(); 
    } 

    public WordCanvas(double W, double H) 
    { 
     this.Width = W; 
     this.Height = H; 

     CreateUI(); 
    } 

    public WordCanvas(ImageView IV) 
    { 
     this.Cover = IV; 
    } 

    public WordCanvas(Canvas C, TextArea TA, GraphicsContext GG) 
    { 
     this.Can = C; 
     this.Area = TA; 
     this.GC = GG; 

     CreateUI(); 
    } 

    public void CreateUI() 
    { 
     Caligraphy(); 

     Imagination(); 

     Color C = Color.STEELBLUE; 

     BackgroundFill BFill = new BackgroundFill(C, CornerRadii.EMPTY, Insets.EMPTY); 

     Background BGround = new Background(BFill); 

     this.getChildren().addAll(Area); 

     this.setBackground(BGround); 
    } 

    public void Caligraphy() 
    { 
     Area.setMaxWidth(Width); 
     Area.setMaxHeight(Height); 
    } 

    public void Imagination() 
    { 
     double CanvasWidth = GC.getCanvas().getWidth(); 
     double CanvasHeight = GC.getCanvas().getHeight(); 

     GC.setFill(Color.TRANSPARENT); 
     GC.fillRect(0, 0, Can.getWidth(), Can.getHeight()); 
     GC.rect(0, 0, CanvasWidth, CanvasHeight); 
     GC.setLineWidth(3); 

     Can.addEventHandler(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() 
     { 
      @Override 
      public void handle(MouseEvent event) 
      { 
       Can.setCursor(Cursor.CROSSHAIR); 
      } 
     }); 

     Can.addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() 
     { 
      @Override 
      public void handle(MouseEvent event) 
      { 
       Can.setCursor(Cursor.DEFAULT); 
      } 
     }); 

     Can.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() 
     { 
      @Override 
      public void handle(MouseEvent event) 
      { 
       GC.beginPath(); 
       GC.lineTo(event.getX(), event.getY()); 
       GC.moveTo(event.getX(), event.getY()); 
       GC.stroke(); 
      } 
     }); 

     Can.addEventHandler(MouseEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() 
     { 
      @Override 
      public void handle(MouseEvent event) 
      { 
       GC.lineTo(event.getX(), event.getY()); 
       GC.stroke(); 
      } 
     }); 

     Can.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() 
     { 
      @Override 
      public void handle(MouseEvent event) 
      { 
       ImageView IV = new ImageView(); 

       WordCanvas Stack = new WordCanvas(IV); 

       Cover.setMouseTransparent(true); 

       WritableImage WImage = Can.snapshot(new SnapshotParameters(), null); 

       ByteArrayOutputStream Bos = new ByteArrayOutputStream(); 

       try 
       { 
        ImageIO.write(SwingFXUtils.fromFXImage(WImage, null), "png", Bos); 
       } 
       catch(IOException ex) 
       { 
        Logger.getLogger(WordCanvas.class.getName()).log(Level.SEVERE, null, ex); 
       } 

       InputStream Fis = new ByteArrayInputStream(Bos.toByteArray()); 
       Image Imos = new Image(Fis); 

       int IW = (int) Imos.getWidth(); 
       int IH = (int) Imos.getHeight(); 

       WritableImage OutputImage = new WritableImage(IW, IH); 
       PixelReader PReader = Imos.getPixelReader(); 
       PixelWriter PWriter = OutputImage.getPixelWriter(); 

       for (int y = 0; y < IH; y++) 
       { 
        for (int x = 0; x < IW; x++) 
        { 
         int argb = PReader.getArgb(x, y); 

         int r = (argb >> 16) & 0xFF; 
         int g = (argb >> 8) & 0xFF; 
         int b = argb & 0xFF; 

         if(r >= 0xCF && g >= 0xCF && b >= 0xCF) 
         { 
          argb &= 0x00FFFFFF; 
         } 

         PWriter.setArgb(x, y, argb); 
        } 
       } 

       if(!Stack.getChildren().contains(Cover)) 
       { 
        Cover.setImage(OutputImage); 

        Stack.getChildren().add(Cover); 
       } 
       else 
       { 
        Cover.setImage(OutputImage); 
       } 
      } 
     }); 
    } 

    public void SetCan(Canvas C) 
    { 
     this.Can = C; 
    } 

    public Canvas GetCan() 
    { 
     return Can; 
    } 

    public void SetGC(GraphicsContext GG) 
    { 
     this.GC = GG; 
    } 

    public GraphicsContext GetGC() 
    { 
     return GC; 
    } 

    public void SetArea(TextArea TA) 
    { 
     this.Area = TA; 
    } 

    public TextArea GetArea() 
    { 
     return Area; 
    } 

    public ImageView GetCover() 
    { 
     return Cover; 
    } 
} 

が、何私は、セカンダリクラスでMouseEvent.MOUSE_RELEASEDの偶数ハンドラが自動的にスナップショットを作成し、メインクラスのスナップボタンが何をしているかを確認したい。しかし、私は何も試したことがないし、this.getChildren().add(Cover)も受け付けません。

もう少し小さな問題ですが、私はWritableImageをより洗練されたソリューションで自動的に透明にしたいと考えています。ユーザー@jewelseaは完璧に機能する解決方法hereを提供しますが、私はすべてのピクセルを読み取る必要がない少し短いものを好むでしょう。既存のpngファイルは意図したとおりに動作しますが、自分のpngファイルを作成すると透過的ではありません。

+0

Javaの命名規則を使用:フィールド、ローカル変数、メソッド引数、メソッド名はcamelCaseを使用します。あなたのIDEは名前の変更を手助けすることができます。そしてあなたがそうしたら、この変更であなたの質問をお勧めします。 – user1803551

+0

なぜ2つの 'WorldCanvas'を持っていますか?あなたのリリースアクションハンドラで毎回新しいアクションハンドラを作成し、それを使用しないのですか? – user1803551

+0

なぜ毎回イメージを書きたいのですか?テキストエリアにペイントしたいだけですか? – user1803551

答えて

0

すべての描画でキャンバスを作成し、親の子供たちと遊んで、なぜ画面をキャプチャして毎回イメージを作成する必要があるのか​​は明らかではありません。

あなたは単にテキスト領域を描画したいので、描画する1つのキャンバスを上に置きます。キャンバスのmouseTransparentPropertyを使用して、入力を取得するレイヤを決定できます。

public class TextCanvas extends Application { 

    private GraphicsContext gc; 

    @Override 
    public void start(Stage primaryStage) { 
     TextArea textArea = new TextArea(); 
     Canvas canvas = createCanvas(); 

     ToggleButton draw = new ToggleButton("Draw"); 
     ToggleButton erase = new ToggleButton("Erase"); 
     ToggleGroup drawErase = new ToggleGroup(); 
     draw.setToggleGroup(drawErase); 
     erase.setToggleGroup(drawErase); 
     drawErase.selectedToggleProperty().addListener((ov, oldV, newV) -> { 
      if (newV == null) { 
       gc.setStroke(Color.TRANSPARENT); 
       canvas.setMouseTransparent(true); 
      } else if (drawErase.getSelectedToggle().equals(draw)) { 
       System.out.println("Fd"); 
       gc.setStroke(Color.BLACK); 
       canvas.setMouseTransparent(false); 
      } else if (drawErase.getSelectedToggle().equals(erase)) { 
       gc.setStroke(Color.WHITE); 
       canvas.setMouseTransparent(false); 
      } 
     }); 

     Button clear = new Button("Clear"); 
     clear.setOnAction(e -> gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight())); 

     CheckBox cb = new CheckBox("Show canvas"); 
     cb.setSelected(true); 
     canvas.visibleProperty().bind(cb.selectedProperty()); 

     VBox buttonBox = new VBox(draw, erase, clear, cb); 

     StackPane stack = new StackPane(textArea, canvas); 
     ScrollPane scrollPane = new ScrollPane(stack); 
     scrollPane.setFitToHeight(true); 

     canvas.widthProperty().bind(scrollPane.widthProperty()); 
     canvas.heightProperty().bind(scrollPane.heightProperty()); 

     stack.setBackground(new Background(new BackgroundFill(Color.STEELBLUE, CornerRadii.EMPTY, Insets.EMPTY))); 

     BorderPane border = new BorderPane(); 
     border.setCenter(scrollPane); 
     border.setBottom(buttonBox); 

     primaryStage.setMaximized(true); 
     primaryStage.setTitle("Practice Canvas"); 
     primaryStage.setScene(new Scene(border)); 
     primaryStage.show(); 
    } 

    private Canvas createCanvas() { 
     Canvas canvas = new Canvas(); 
     gc = canvas.getGraphicsContext2D(); 
     gc.setLineWidth(3); 

     canvas.setOnMouseEntered(event -> canvas.setCursor(Cursor.CROSSHAIR)); 
     canvas.setOnMouseExited(event -> canvas.setCursor(Cursor.DEFAULT)); 

     canvas.setOnMousePressed(event -> { 
      gc.beginPath(); 
      gc.lineTo(event.getX(), event.getY()); 
      gc.moveTo(event.getX(), event.getY()); 
      gc.stroke(); 
     }); 
     canvas.setOnMouseDragged(event -> { 
      gc.lineTo(event.getX(), event.getY()); 
      gc.stroke(); 
     }); 

     canvas.setMouseTransparent(true); 
     return canvas; 
    } 

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

編集:私は、キャンバスの表示を切り替えるために、チェックボックスを追加しました。それぞれのユーザー操作が各モードで何をするかについては、使用要件をクリアする必要があります。いずれにしても、これで十分であるはずです。

また、適切なJava命名規則を使用してください。ローカル変数、(定数ではない)フィールド名とメソッド引数は小文字で始まる必要があります。

+0

ありがとう、これは非常に良い、それを短縮するための良い方法に見えますが、それは私が欲しかった正確にはなかった。私は自由な描画プロセスを合理化し、キャンバスはユーザーの望みどおりに行き着くことができるワードパッドアプリケーションのようなものを作っています。私が描画しているときには、ブラシ機能が選択されたままになります。私は描いた。 ペイントのような透明な背景でイメージをカットアンドペーストするオプションを実装するときには、これを行う必要がありますが、これは白いライトグレーピクセルを透明にするよりも優れています。 –

+0

@FeChodes仕様を変更しています。私の答えは私の編集を参照してください。たとえそれがあなたが望んでいたものではなくても(あなたはそれで非常に正確である必要があります)、それはあなたが望む状態にそれを得るためのすべてのツールを与えるべきです。 – user1803551

+0

私はまだupvoteできないが、私はそれを受け入れた。正確には私が望んでいたものではありませんでしたが、それを短縮するのはとても素敵な答えと方法でした。 –

関連する問題