Java 正确地画在图像上
我正在创建一个小的图像编辑器,现在我正试图让用户通过拖动鼠标(就像MS Paint中的铅笔工具一样)在图像上画图 我遇到了一些困难,因为当我移动光标太快时,应用程序无法绘制所有应该着色的像素,只有一小部分正确着色 我尝试了两种添加彩色像素的解决方案:首先,我创建了一个列表,存储调用Java 正确地画在图像上,java,swing,mouseevent,bufferedimage,paintcomponent,Java,Swing,Mouseevent,Bufferedimage,Paintcomponent,我正在创建一个小的图像编辑器,现在我正试图让用户通过拖动鼠标(就像MS Paint中的铅笔工具一样)在图像上画图 我遇到了一些困难,因为当我移动光标太快时,应用程序无法绘制所有应该着色的像素,只有一小部分正确着色 我尝试了两种添加彩色像素的解决方案:首先,我创建了一个列表,存储调用mouseDragged时添加的所有点。 之后,我决定在BufferedImage对象上简单地使用setRGB,因为它看起来并不慢 我还做了一个测试,以了解mouseMoved方法是否能够检测到光标悬停的所有点,如果我
mouseDragged
时添加的所有点。
之后,我决定在BufferedImage
对象上简单地使用setRGB
,因为它看起来并不慢
我还做了一个测试,以了解mouseMoved
方法是否能够检测到光标悬停的所有点,如果我创建一个列表并将每个点添加到列表中,当我打印列表时,列表中只有一些点,我的结果是否定的
我想我可以再次使用ImagePanel类上的列表,在列表中包含的点之间使用drawLine
方法,试图填补空白,但我认为这不是一个好的解决方案,因为如果图像被放大,我需要重新发明drawLine方法,并且我还需要找到最佳时机来绘制图像的所有点
有更好的解决办法吗?感谢您的帮助
下面我发布了我的MVCE(我从图像编辑器中删除了所有工具,而且应用程序的设计非常糟糕):
ImagePanel类:
class ImagePanel extends JPanel
{
private int zoomLevel;
private BufferedImage image;
private int rgb = Color.YELLOW.getRGB ();
private Point lastPoint;
public ImagePanel () {
super (new FlowLayout (FlowLayout.LEFT, 0, 0));
zoomLevel = 1;
}
protected void addPoint (int scaledX, int scaledY) {
int x = scaledX / zoomLevel, y = scaledY / zoomLevel;
if (x >= 0 && y >= 0 && x < image.getWidth () && y < image.getHeight ()) {
if (lastPoint == null) image.setRGB (x, y, rgb);
else {
Graphics2D g = image.createGraphics ();
g.setColor (Color.YELLOW);
g.drawLine (lastPoint.x, lastPoint.y, x, y);
g.dispose ();
}
lastPoint = new Point (x, y);
refresh ();
}
}
protected int getImageHeight () {
if (image == null) return 0;
return image.getHeight ();
}
protected int getImageWidth () {
if (image == null) return 0;
return image.getWidth ();
}
@Override public Dimension getPreferredSize () {
if (image == null) return new Dimension (0, 0);
return new Dimension (image.getWidth () * zoomLevel, image.getHeight () * zoomLevel);
}
public int getZoomLevel () {
return zoomLevel;
}
@Override protected void paintComponent (Graphics g) {
super.paintComponent (g);
g.drawImage (image, 0, 0, image.getWidth () * zoomLevel, image.getHeight () * zoomLevel, this);
}
private void refresh () {
Container parent = getParent ();
parent.revalidate ();
parent.repaint ();
}
protected void setImage (BufferedImage image) {
this.image = image;
refresh ();
}
protected void setPixelColor (int scaledX, int scaledY) {
int x = scaledX / zoomLevel, y = scaledY / zoomLevel;
if (x >= 0 && y >= 0 && x < image.getWidth () && y < image.getHeight ()) {
lastPoint = null;
image.setRGB (x, y, rgb);
refresh ();
}
}
protected boolean zoom (int zoomLevel) {
if (image == null || zoomLevel < 1 || zoomLevel > 8) return false;
this.zoomLevel = zoomLevel;
refresh ();
return true;
}
protected boolean zoomIn () {
return image != null && zoom (zoomLevel + 1);
}
protected boolean zoomOut () {
return image != null && zoom (zoomLevel - 1);
}
}
class ImagePanel扩展了JPanel
{
私人国际zoomLevel;
私有缓冲图像;
private int rgb=Color.YELLOW.getRGB();
私人点;
公共图像面板(){
super(新的FlowLayout(FlowLayout.LEFT,0,0));
zoomLevel=1;
}
受保护的空添加点(int scaledX,int scaledY){
int x=scaledX/zoomLevel,y=scaledY/zoomLevel;
如果(x>=0&&y>=0&&x=0&&y>=0&&x8)返回false;
this.zoomLevel=zoomLevel;
刷新();
返回true;
}
受保护的布尔缩放(){
返回图像!=null&缩放(zoomLevel+1);
}
受保护的布尔zoomOut(){
返回图像!=null&缩放(zoomLevel-1);
}
}
现在它工作得很好 鼠标移动的每一个像素都不会出现鼠标事件,如果移动得非常快,这一点尤其重要。我试图找到一些很好的文档来说明为什么会这样,但无法马上找到。你可能会在那里找到一些东西 要解决这个问题,我要做的是使用
java.awt.Graphics
方法提供的方法,从以前的位置到新的位置画一条线。在你的图像或某个图层上做这个。这里有一些代码可以做到这一点:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
public class SO46085131 extends JPanel {
private final Dimension LAYER_SIZE = new Dimension(300, 300);
private Point prevPoint = null;
private BufferedImage paintLayer;
private Graphics paintLayerGraphics;
public SO46085131(){
setBackground(Color.black);
// create our layer that we will paint onto
paintLayer = new BufferedImage(LAYER_SIZE.width, LAYER_SIZE.height, BufferedImage.TYPE_INT_ARGB);
// get our graphics for the painting layer and fill in a background cause thats cool
paintLayerGraphics = paintLayer.getGraphics();
paintLayerGraphics.setColor(Color.red);
paintLayerGraphics.fillRect(0, 0, paintLayer.getWidth(), paintLayer.getHeight());
setBackground(Color.WHITE);
// listen for drag events, then draw
// TODO: You should listen for mouse up and down events instead of dragging so you can clear your previous point
// TODO: Big boy bugs here! for you to fix
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
// if we moved the mouse previously draw a line from our prev point to our current position
if(prevPoint != null) {
paintLayerGraphics.setColor(Color.black);
paintLayerGraphics.drawLine(prevPoint.x, prevPoint.y, e.getX(), e.getY());
repaint();
}
// store previous point
prevPoint = e.getPoint();
}
});
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// draw our sweet painting layer ontop of our component.
g.drawImage(paintLayer, 0, 0, this);
}
public static void main(String [] args) {
// just new up a sample jframe to display our stuff on
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SO46085131());
frame.setSize(500, 400);
frame.setVisible(true);
}
}
与其尝试单独绘制所有像素,不如在每个像素之间画一条线,这将补偿操作系统不会为“移动的每个像素”生成事件的情况,因为它不会。如果你移动鼠标的速度足够快,操作系统将删除事件,以利于速度和剩余时间responsive@MadProgrammer谢谢你的帮助,我编辑了我的问题,现在效果很好。谢谢你的回答,我使用你的prevPoint方法编辑了我的问题,以避免列出要提取的分数
class ImagePanel extends JPanel
{
private int zoomLevel;
private BufferedImage image;
private int rgb = Color.YELLOW.getRGB ();
private Point lastPoint;
public ImagePanel () {
super (new FlowLayout (FlowLayout.LEFT, 0, 0));
zoomLevel = 1;
}
protected void addPoint (int scaledX, int scaledY) {
int x = scaledX / zoomLevel, y = scaledY / zoomLevel;
if (x >= 0 && y >= 0 && x < image.getWidth () && y < image.getHeight ()) {
if (lastPoint == null) image.setRGB (x, y, rgb);
else {
Graphics2D g = image.createGraphics ();
g.setColor (Color.YELLOW);
g.drawLine (lastPoint.x, lastPoint.y, x, y);
g.dispose ();
}
lastPoint = new Point (x, y);
refresh ();
}
}
protected int getImageHeight () {
if (image == null) return 0;
return image.getHeight ();
}
protected int getImageWidth () {
if (image == null) return 0;
return image.getWidth ();
}
@Override public Dimension getPreferredSize () {
if (image == null) return new Dimension (0, 0);
return new Dimension (image.getWidth () * zoomLevel, image.getHeight () * zoomLevel);
}
public int getZoomLevel () {
return zoomLevel;
}
@Override protected void paintComponent (Graphics g) {
super.paintComponent (g);
g.drawImage (image, 0, 0, image.getWidth () * zoomLevel, image.getHeight () * zoomLevel, this);
}
private void refresh () {
Container parent = getParent ();
parent.revalidate ();
parent.repaint ();
}
protected void setImage (BufferedImage image) {
this.image = image;
refresh ();
}
protected void setPixelColor (int scaledX, int scaledY) {
int x = scaledX / zoomLevel, y = scaledY / zoomLevel;
if (x >= 0 && y >= 0 && x < image.getWidth () && y < image.getHeight ()) {
lastPoint = null;
image.setRGB (x, y, rgb);
refresh ();
}
}
protected boolean zoom (int zoomLevel) {
if (image == null || zoomLevel < 1 || zoomLevel > 8) return false;
this.zoomLevel = zoomLevel;
refresh ();
return true;
}
protected boolean zoomIn () {
return image != null && zoom (zoomLevel + 1);
}
protected boolean zoomOut () {
return image != null && zoom (zoomLevel - 1);
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
public class SO46085131 extends JPanel {
private final Dimension LAYER_SIZE = new Dimension(300, 300);
private Point prevPoint = null;
private BufferedImage paintLayer;
private Graphics paintLayerGraphics;
public SO46085131(){
setBackground(Color.black);
// create our layer that we will paint onto
paintLayer = new BufferedImage(LAYER_SIZE.width, LAYER_SIZE.height, BufferedImage.TYPE_INT_ARGB);
// get our graphics for the painting layer and fill in a background cause thats cool
paintLayerGraphics = paintLayer.getGraphics();
paintLayerGraphics.setColor(Color.red);
paintLayerGraphics.fillRect(0, 0, paintLayer.getWidth(), paintLayer.getHeight());
setBackground(Color.WHITE);
// listen for drag events, then draw
// TODO: You should listen for mouse up and down events instead of dragging so you can clear your previous point
// TODO: Big boy bugs here! for you to fix
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
// if we moved the mouse previously draw a line from our prev point to our current position
if(prevPoint != null) {
paintLayerGraphics.setColor(Color.black);
paintLayerGraphics.drawLine(prevPoint.x, prevPoint.y, e.getX(), e.getY());
repaint();
}
// store previous point
prevPoint = e.getPoint();
}
});
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// draw our sweet painting layer ontop of our component.
g.drawImage(paintLayer, 0, 0, this);
}
public static void main(String [] args) {
// just new up a sample jframe to display our stuff on
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SO46085131());
frame.setSize(500, 400);
frame.setVisible(true);
}
}