Java 如何在文本区域上绘制?
我正在使用的程序只是在Java 如何在文本区域上绘制?,java,user-interface,javafx,layout-manager,Java,User Interface,Javafx,Layout Manager,我正在使用的程序只是在堆栈窗格上使用画布层在文本或图像上绘制。我想完成的是,当我释放鼠标时,MouseEvent.mouse\u RELEASED处理程序将自动获取画布的快照,将图像添加到ImageView封面,并将其显示在文本区域的顶部,但它无法将更改添加到类堆栈窗格,即图像视图 我这里有一个程序,我将把它添加到我正在开发的另一个程序中,我计划将主类textcavas中的所有内容从主项目导入到menu controller类中 主类TextCanvas.java: import java.io
堆栈窗格
上使用画布层在文本或图像上绘制。我想完成的是,当我释放鼠标时,MouseEvent.mouse\u RELEASED
处理程序将自动获取画布的快照,将图像添加到ImageView封面
,并将其显示在文本区域
的顶部,但它无法将更改添加到类堆栈窗格
,即图像视图
我这里有一个程序,我将把它添加到我正在开发的另一个程序中,我计划将主类textcavas
中的所有内容从主项目导入到menu controller类中
主类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);
}
}
import java.io.ByteArrayInputStream;
导入java.io.ByteArrayOutputStream;
导入java.io.File;
导入java.io.IOException;
导入java.io.InputStream;
导入java.util.logging.Level;
导入java.util.logging.Logger;
导入javafx.application.application;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.embed.swing.SwingFXUtils;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.scene.scene;
导入javafx.scene.Snapshot参数;
导入javafx.scene.canvas.canvas;
导入javafx.scene.canvas.GraphicsContext;
导入javafx.scene.control.Button;
导入javafx.scene.control.ScrollPane;
导入javafx.scene.control.TextArea;
导入javafx.scene.control.Toggle;
导入javafx.scene.control.ToggleButton;
导入javafx.scene.control.ToggleGroup;
导入javafx.scene.image.image;
导入javafx.scene.image.ImageView;
导入javafx.scene.image.PixelReader;
导入javafx.scene.image.PixelWriter;
导入javafx.scene.image.WritableImage;
导入javafx.scene.layout.BorderPane;
导入javafx.scene.layout.StackPane;
导入javafx.scene.layout.VBox;
导入javafx.scene.paint.Color;
导入javafx.stage.Screen;
导入javafx.stage.stage;
导入javax.imageio.imageio;
公共类TextCanvas扩展了应用程序
{
private ScrollPane Scroll=新建ScrollPane();
帆布罐=新帆布(800400);
GraphicsContext GG=Can.getGraphicsContext2D();
TextArea TA=新TextArea();
ImageView封面=新ImageView();
VBox ButtonBox=新的VBox();
WordCanvas WC=新的WordCanvas(Can、TA、GG);
@凌驾
公共无效开始(阶段PrimaryStage)
{
ToggleGroup抽屉SE=新的ToggleGroup();
ToggleButton Draw=新的ToggleButton(“Draw”);
ToggleButton擦除=新的ToggleButton(“擦除”);
按钮清除=新按钮(“清除”);
Draw.setToggleGroup(抽屉式);
擦除。设置切换组(抽屉);
double dotsprinch=Screen.getPrimary().getDpi();
双W=DotsPerInch*8.5;
双H=DotsPerInch*11.0;
StackPane堆栈=新的WordCanvas(W,H);
WC.GetArea().setMaxWidth(W);
WC.GetArea().setMaxHeight(H);
WC.GetCan().setWidth(W);
WC.GetCan().setHeight(H);
DroperASE.selectedToggleProperty().addListener(新的ChangeListener())
{
public void changed(ObservalEvalue不清楚为什么每次绘制时都要创建画布,与家长的孩子一起玩,以及为什么每次都要捕获屏幕并创建图像
您只需在文本区域上绘制,因此在其上绘制一个画布。画布的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命名约定:局部变量、(非常量)字段名和方法参数应该以小写开头。不清楚为什么每次绘制都要创建画布,为什么要与父对象的子对象一起玩,为什么每次都要捕获屏幕并创建图像
您只需在文本区域上绘制,因此在其上绘制一个画布。画布的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命名约定:局部变量(非常量)字段名和方法参数应以小写开头。使用Java命名约定:字段、局部变量、方法参数和方法名称使用camelCase。IDE可以帮助您重命名,一旦您这样做,我建议您使用此更改提问。为什么您的发布操作中有2个WorldCanvas
s你每次都创建一个新的,然后不使用它?为什么每次都要写图像?你只是想在文本区域上画画吗?是的,我想在它上面画画并保持它在那里。我已经解决了一些问题,但是我仍然不知道如何从不同的类文件正确更改GUI元素。发送示例通过构造函数的TextArea允许我添加和获取文本,但不能更改其maxwidth或将其从StackPane中删除。使用Java命名约定:字段、局部变量、方法参数和方法名称使用camelCase。IDE可以帮助您重命名,一旦您这样做,我建议您使用此更改提问。为什么您有2个WorldCanvas
s,在您的发布操作处理程序中,您每次都创建一个新的,然后不使用它?为什么每次都要编写图像?您只想在文本区域上绘画吗?是的,我想在其上绘画,并将其保留在那里。我已经修复了其中一些问题,但我仍然不知道如何解决