java - 鼠标拖动时画线问题

标签 java graphics applet awt java-2d

我正在开发一个绘制不同形状的绘图小程序。我想在拖动鼠标的同时画线。问题是当线条出现时,它们如下图所示。

enter image description here

我有一个使用一个点(起点)构造的类线 它有一个名为 setDragPoint 的方法,该方法采用鼠标拖动点来绘制线条,同时拖动 drawingImage 在拖动模式下绘制时也会产生太多闪烁。为什么会这样?

import java.applet.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;

public class PaintBrush extends Applet implements MouseListener, MouseMotionListener {

Shape shape;
Point startPoint;
Point dragPoint;
ArrayList<Shape> shapes;
Choice shapeChoice;
Choice colorChoice;
Choice fillChoice;
Image drawingImage;
Graphics drawGraphics;
String shapeString, colorString, fillString;
boolean isDragMode;

public void init() {
    shapes = new ArrayList<Shape>();
    shapeChoice = new Choice();
    shapeChoice.addItem("Line");
    shapeChoice.addItem("Rectangle");
    shapeChoice.addItem("RoundRect");
    shapeChoice.addItem("Oval");
    shapeChoice.addItem("FreeHand");

    add(shapeChoice);

    colorChoice = new Choice();
    colorChoice.addItem("Red");
    colorChoice.addItem("Green");
    colorChoice.addItem("Blue");

    add(colorChoice);

    fillChoice = new Choice();
    fillChoice.addItem("Filled");
    fillChoice.addItem("Hollow");
    add(fillChoice);

    shapeString = shapeChoice.getSelectedItem();
    colorString = colorChoice.getSelectedItem();
    fillString = fillChoice.getSelectedItem();

    drawingImage = createImage(getSize().width, getSize().height);
    drawGraphics = drawingImage.getGraphics();
    System.out.println("set up image");
    drawGraphics.setColor(Color.black);
    drawGraphics.fillRect(0, 0, getSize().width, getSize().height);
    drawGraphics.setColor(Color.orange);
    drawGraphics.drawRect(0, 0, getSize().width - 1, getSize().height - 1);
    drawGraphics.drawRect(1, 1, getSize().width - 3, getSize().height - 3);
    startPoint = new Point(0, 0);
    dragPoint = new Point(0, 0);
    addMouseListener(this);
    addMouseMotionListener(this);
}

public void mouseEntered(MouseEvent e) {
}

public void mouseExited(MouseEvent e) {
}

public void mouseClicked(MouseEvent e) {
}

public void mousePressed(MouseEvent e) {

    System.out.println("Pressed");

    startPoint.x = e.getX();
    startPoint.y = e.getY();
    repaint();

    switch (shapeString) {
        case "Line":
            shape = new Line(startPoint.x, startPoint.y);  //step 1 here i construct a new line using the start point (the point at which the mouse is pressed)

            break;
        case "FreeHand":
            shape = new FreeShape();
            break;
    }


    }

public void mouseReleased(MouseEvent e) {
    if (isDragMode) {
        shapes.add(shape);
        isDragMode = false;
     }
    repaint();

}

public void mouseMoved(MouseEvent e) {
}

public void mouseDragged(MouseEvent e) {
    System.out.println("Dragged");
    isDragMode = true;
    dragPoint.x = e.getX();
    dragPoint.y = e.getY();

    switch (shapeString) {
        case "Line":
            shape.setDragPoint(dragPoint.x, dragPoint.y);  //here i set the drag points to the already created line at step 1 
              break;
        case "FreeHand":
            shape = new FreeShape();
            break;
    }

    shape.drawWhileDragging(drawGraphics); // i call this method to draw while mouse is dragging

    repaint();


}

public void paint(Graphics g) {

  update(g);
}
 public void update(Graphics g) {

  // create an off-screen graphics drawing environment if none
  //existed
  // or if the user resized the applet drawing area to a different
 // size
   if (drawingImage == null)
{

System.out.println("Image is Null");
    drawingImage = createImage(getSize().width,getSize().height);
drawGraphics = drawingImage.getGraphics();
}



  // erase the previous image
  drawGraphics.setColor(Color.black);
  drawGraphics.fillRect(0,0,getSize().width,getSize().height);
  drawGraphics.setColor(Color.orange);
  drawGraphics.drawRect(0,0,getSize().width-1,getSize().height-1);
  drawGraphics.drawRect(1,1,getSize().width-3,getSize().height-3);  

   for(Shape s:shapes)
         s.draw(drawGraphics);

  // paint the offscreen image to the applet viewing window
  g.drawImage(drawingImage,0,0,this);

   }
 }


abstract class Shape {

Color shapeColor;
boolean filled;

abstract void draw(Graphics g);

void drawWhileDragging(Graphics g) {
}

void setDragPoint(int x, int y) {
}
}

 class Line extends Shape {

private Point startPoint;
private Point currentPoint;

public Point getStartPoint() {
    return startPoint;
}

public Point getCurrentPoint() {
    return currentPoint;
}

public void setStartPoint(Point point) {
    this.startPoint = point;
}

public void setCurrentPoint(Point point) {
    this.currentPoint = point;
}

void drawWhileDragging(Graphics g) {
    g.drawLine(startPoint.x, startPoint.y, currentPoint.x, currentPoint.y); 
}

public void draw(Graphics g) {
    g.drawLine(startPoint.x, startPoint.y, currentPoint.x, currentPoint.y);
}

Line() {
    startPoint = new Point(0, 0);
    currentPoint = new Point(0, 0);
}

Line(int x1, int y1) {
    this();
    this.startPoint.x = x1; 
    this.startPoint.y = y1;
}

void setDragPoint(int x, int y) {
    this.currentPoint.x = x;
    this.currentPoint.y = y;
    System.out.println("Current-X:" + currentPoint.x + " currentPoint-Y" + currentPoint.y);
    System.out.println("start-X:" + startPoint.x + " startPoint-Y" + startPoint.y);
  }

 }

class FreeShape extends Shape {

private ArrayList<Point> dragPoints = new ArrayList<Point>();

public ArrayList<Point> getDragPoints() {
    return dragPoints;
}

public void setDragPoints(Point point) {
    dragPoints.add(point);
}

public void draw(Graphics g) {
}

public FreeShape() {
  }
}


class Rectangle extends Shape {

public void draw(Graphics g) {
   }
 }


class Oval extends Shape {

public void draw(Graphics g) {
   }
 }

最佳答案

我最近写了一个类似类型的应用程序。这是屏幕截图。如您所见,它还没有完全开发。 enter image description here

现在,我也遇到了和你现在面临的类似问题。你要做的是。

  • 双缓冲所有绘画操作
  • 不要通过调用 repaint 来清除屏幕。 Repaint 实际上首先用背景色填充屏幕 & 这就是您看到的闪烁。

您可以在 Image 中复制当前屏幕 Canvas 。 Image 将在每次绘图操作后更新。因此,不是通过调用 repaint 来清除屏幕,而是在 Canvas 上绘制 Image。这就像双缓冲。

在您的代码中,每次拖动鼠标时都会调用 repaint。这就是闪烁的原因。


更新

我在您新更新的代码中发现的三个主要问题

  • drawWhileDragging 方法中,您没有更改线条图形上下文绘制颜色。所以这条线实际上是用黑色画的,你的背景也是黑色的。因此,您什么也看不到。
  • 在相同的方法中,您将传递 drawingImage 的图形上下文(即引用)。因此,这条线实际上是在屏幕外的图像上绘制的,而不是在屏幕上。
  • mouseDragged 方法中,您在每次拖动后调用重绘。结果实际上什么都没有画

我已经在我的机器上运行了您的代码并进行了必要的更改。为了简短起见,我只发布更改后的方法。

这是更新后的 mouseDragged 方法

    public void mouseDragged(MouseEvent e) {
        System.out.println("Dragged");
        isDragMode = true;
        dragPoint.x = e.getX();
        dragPoint.y = e.getY();

        switch (shapeString) {
            case "Line":
                shape.setDragPoint(dragPoint.x, dragPoint.y);  //here i set the drag points to the already created line at step 1
                break;
            case "FreeHand":
                shape = new FreeShape();
                break;
        }

        getGraphics().drawImage(drawingImage, 0,0,null); //Added this line
        shape.drawWhileDragging(getGraphics()); // i call this method to draw while mouse is dragging
    }

这是更新后的 drawWhileDragging 方法

    void drawWhileDragging(Graphics g) {
        g.setColor(Color.ORANGE);
        g.drawLine(startPoint.x, startPoint.y, currentPoint.x, currentPoint.y);
        g.setColor(Color.BLACK);
    }

好吧,我已经将颜色设置为橙色。你要做的就是根据Choice菜单设置颜色。

您也可以对绘制其他形状实现类似的类比。

关于java - 鼠标拖动时画线问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14078882/

相关文章:

java - 将 "45,978"解析为双值

java - 使用 webflux bean 验证时出现不明确的异常(WebExchangeBindException 与 ConstraintViolationException)

r - 如何修复 R postscript 函数的剪切输出?

java - 无法在 Openshift v3 上部署基于 Java 的应用程序

java - 将所有字段名称从 firestore 文档获取到 arraylist

r - 使用 ggplot2 和plotly 绘制 3D 棱镜

java - GUI 使用 JFrame 和 JPanel 绘制自定义形状

详细 View 中的 java 卡小程序部署

java - 是否可以将 OutputStream 从 java applet 连接到浏览器的下载窗口?

java - Java Applet 中 JPopupMenu 上的警告锥和不可编辑的文本字段