- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在开发的程序只是通过在 StackPane
上使用 Canvas 层来绘制文本或图像。我想要完成的是,当我释放鼠标时,MouseEvent.MOUSE_RELEASED
处理程序会自动获取Canvas的快照,将图像添加到ImageView Cover
并将其显示在TextArea
之上,但它无法将更改添加到StackPane
类,即ImageView
。
我这里有一个程序,我将把它添加到我正在开发的另一个程序中,我计划将主类 TextCanvas
中的所有内容都放入主项目的菜单 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);
}
}
包含 TextArea 和 Canvas 的辅助类:
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 文件时,它们并不透明。
最佳答案
目前尚不清楚为什么您要在每次绘制时创建 Canvas ,与父级的子级一起玩,以及为什么每次都需要捕获屏幕并创建图像。
您只想在文本区域上绘图,因此在其上绘制一个 Canvas 。 Canvas 的 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);
}
}
编辑:我添加了一个复选框来切换 Canvas 的可见性。您必须明确每个用户操作在每种模式下的用途的使用要求。无论如何,这应该足够玩了。
此外,使用正确的 Java 命名约定:局部变量、(非常量)字段名称和方法参数应以小写字母开头。
关于java - 如何在文本区域上绘图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47028769/
表架构 DROP TABLE bla; CREATE TABLE bla (id INTEGER, city INTEGER, year_ INTEGER, month_ INTEGER, val I
我需要拆分字符串/或从具有以下结构的字符串中获取更容易的子字符串。 字符串将来自 window.location.pathname 或 window.location.href,看起来像 text/n
每当将对象添加到数组中时,我都会尝试更新 TextView ,并在 TextView 中显示该文本,如下所示: "object 1" "object 2" 问题是,每次将新对象添加到数组时,它都会覆盖
我目前正在寻找使用 Java 读取网站可见文本并将其存储为纯文本字符串的方法。 换句话说,我想转换成这样: Hello stupid World进入“ Hello World ” 或者类似的东西 Un
我正在尝试以文本和 HTML 格式发送电子邮件,但无法正确发送正确的 header 。特别是,我想设置 Content-Type header ,但我找不到如何为 html 和文本部分单独设置它。 这
我尝试了上面的代码,但我无法绑定(bind)文本,我怎样才能将资源内部文本 bloc
我刚刚完成了 Space Shooter 教程,由于没有 GUIText 对象,所以我创建了 UI.Text 对象并进行了相应的编码。它在统一播放器中有效,但在构建 Web 应用程序后无效。我花了一段
我有这个代码: - (IBAction)setButtonPressed:(id)sender { NSUserDefaults *sharedDefaults = [[NSUserDefau
抱歉标题含糊不清,但我想不出我想在标题中做什么。无论如何,对于图像上的文本,我使用了 JLabel 文本并将其添加到图标中。 JLabel icon = new JLabel(new Imag
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我在将 Twitter 嵌入到我从 HTML 5 转换的 wordpress 运行网站时遇到问题。 我遇到的问题是推文不是我的自定义字体... 这是我无法使用任何 css 定位的 HTML 代码,我正
我正在尝试找到解决由于使用以下形式的代码而导致的冗余字符串连接问题的最佳方法: logger.debug("Entering loop, arg is: " + arg) // @1 在大多数情况下,
我写了这个测试 @Test public void removeRequestTextFromRouteError() throws Exception { String input = "F
我目前正在创建一个正则表达式来拆分所有匹配以下格式的字符串:&[文本],并且需要获取文本。字符串可能类似于:something &[text] &[text] everything &[text] 等
有没有办法将标题文本从一个词变形为另一个词,同时保留两个词中使用的字母?我看过的许多 css 文本动画大多是视觉的,很少有旋转整个单词的。 我想要做的是从一个词过渡,例如“BEACH”到“CHANGE
总结matplotlib绘图如何设置坐标轴刻度大小和刻度。 上代码: ?
我在容器 (1) 中创建了容器 (2)。你能帮忙如何向容器(1)添加文本吗?下面是我的代码 return Scaffold( body: Padding( padding: c
我似乎找不到任何人或任何人这样做过。我试图限制我们使用的图像数量,并想创建一个带有渐变作为其“颜色”的文本,并在其周围设置渐变轮廓/描边 到目前为止,我还没有看到任何将两者结合在一起的东西。 我可以自
我正在为视频游戏暗黑破坏神 2 使用 discord.py 构建一个不和谐机器人。其中一项功能要求机器人从暗黑破坏神 2 屏幕截图中提取项目的名称和属性。我目前正在为此使用 pytesseract,但
我很难弄清楚如何旋转 strip.text theme 中的属性来自 ggplot2 .我使用的是 R 版本 3.4.2 和 ggplot2 版本 2.2.1。 以下是 MWE 的数据。 > dput
我是一名优秀的程序员,十分优秀!