如何使用鼠标拖动事件在java小程序上绘制矩形

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/880753/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:36:26  来源:igfitidea点击:

how to draw rectangle on java applet using mouse drag event

javaappletdrawingawt

提问by Rohini Kumar

i am using java. i want to draw rectangle based on mousedrag event. if user dragging the mouse, then the rectangle on the applet should increase or decrease basing on current mouse coordinates. i have the following code.

我正在使用Java。我想根据 mousedrag 事件绘制矩形。如果用户拖动鼠标,则小程序上的矩形应根据当前鼠标坐标增加或减少。我有以下代码。

in the following code i am using [b]SelectionArea[/b] class which extends a canvas on which i am performing drawing operation. i am using [b]image[/b] variable in this class for double buffering to reduce flickering and to save the applet's previous state(i.e drawing content of applet)

在下面的代码中,我使用了 [b]SelectionArea[/b] 类,它扩展了我正在执行绘图操作的画布。我在这个类中使用 [b]image[/b] 变量进行双缓冲以减少闪烁并保存小程序的先前状态(即小程序的绘图内容)

but the code is working fine if i draw first rectangle. if i start to draw second rectangle the previously drawn rectangle is disappearing. i want the previously drawn rectangle to be on the screen

但是如果我绘制第一个矩形,代码就可以正常工作。如果我开始绘制第二个矩形,之前绘制的矩形就会消失。我希望之前绘制的矩形出现在屏幕上

can any one tell me how to solve this.

谁能告诉我如何解决这个问题。

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

/* 
 * This displays a framed area.  When the user drags within
 * the area, this program displays a rectangle extending from
 * where the user first pressed the mouse button to the current
 * cursor location.
 */

public class RectangleDemo extends Applet {
SelectionArea drawingPanel;
Label label;

public void init() {
    GridBagLayout gridBag = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();

    setLayout(gridBag);

    drawingPanel = new SelectionArea(this);
    c.fill = GridBagConstraints.BOTH;
    c.weighty = 1.0;
    c.gridwidth = GridBagConstraints.REMAINDER; //end row
    gridBag.setConstraints(drawingPanel, c);
    add(drawingPanel);

    label = new Label("Drag within the framed area.");
    c.fill = GridBagConstraints.HORIZONTAL;
    c.weightx = 1.0;
    c.weighty = 0.0;
    gridBag.setConstraints(label, c);
    add(label);
    drawingPanel.setVisible(true);

    validate();
}

public void paint(Graphics g){
    drawingPanel.repaint();
}

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

}

}

class SelectionArea extends Canvas implements ActionListener, MouseListener,    MouseMotionListener{
Rectangle currentRect;
RectangleDemo controller;
//for double buffering
Image image;
Graphics offscreen;
public SelectionArea(RectangleDemo controller) {
    super();
    this.controller = controller;
    addMouseListener(this);
    addMouseMotionListener(this);        
}

public void actionPerformed(ActionEvent ae){
    repaintoffscreen();
}

public void repaintoffscreen(){
    image = createImage(this.getWidth(), this.getHeight());
    offscreen = image.getGraphics();
    Dimension d = getSize();
    if(currentRect != null){
        Rectangle box = getDrawableRect(currentRect, d);            

        //Draw the box outline.
        offscreen.drawRect(box.x, box.y, box.width - 1, box.height - 1);  
        //repaint();
    }
}

public void mouseEntered(MouseEvent me) {}
public void mouseExited(MouseEvent me){ }
public void mouseClicked(MouseEvent me){}
public void mouseMoved(MouseEvent me){}

public void mousePressed(MouseEvent me) {        
    currentRect = new Rectangle(me.getX(), me.getY(), 0, 0);
    repaintoffscreen();        
}

public void mouseDragged(MouseEvent me) {
    System.out.println("here in dragged()");
    currentRect.setSize(me.getX() - currentRect.x, me.getY() - currentRect.y);
    repaintoffscreen();    
    repaint();
}

public void mouseReleased(MouseEvent me) {
    currentRect.setSize(me.getX() - currentRect.x, me.getY() - currentRect.y);
    repaintoffscreen();  
    repaint();
}

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

public void paint(Graphics g) {
    g.drawImage(image, 0, 0, this);
}

Rectangle getDrawableRect(Rectangle originalRect, Dimension drawingArea) {
    int x = originalRect.x;
    int y = originalRect.y;
    int width = originalRect.width;
    int height = originalRect.height;

    //Make sure rectangle width and height are positive.
    if (width < 0) {
        width = 0 - width;
        x = x - width + 1;
        if (x < 0) {
            width += x;
            x = 0;
        }
    }
    if (height < 0) {
        height = 0 - height;
        y = y - height + 1;
        if (y < 0) {
            height += y;
            y = 0;
        }
    }

    //The rectangle shouldn't extend past the drawing area.
    if ((x + width) > drawingArea.width) {
        width = drawingArea.width - x;
    }
    if ((y + height) > drawingArea.height) {
        height = drawingArea.height - y;
    }

    return new Rectangle(x, y, width, height);
}

}

}

also if i run this code on full screen mode then i am seeing that the rectangle is appering on screen only after i released the mouse. but i want the rectangle to be on the screen while dragging the mouse and it should change it's dimension according to the current mouse coordinates. can any one help me pls.

此外,如果我在全屏模式下运行此代码,那么我会看到矩形仅在我松开鼠标后才出现在屏幕上。但我希望在拖动鼠标时将矩形显示在屏幕上,并且它应该根据当前鼠标坐标更改其尺寸。任何人都可以帮助我。

采纳答案by Omry Yadan

homework?

在家工作?

basically what you need to do is:

基本上你需要做的是:

  1. on mouse down keep the mouse-down coordinates and repaint
  2. on mouse move keep current mouse coordinates and repaint
  3. on mouse up, nullify the mouse-down coordinates to indicate there is no rect, and repaint.
  4. on paint, draw background and then rect between mousedown and cur-mouse coordinates.
  1. 在鼠标按下时保持鼠标按下坐标并重新绘制
  2. 鼠标移动时保持当前鼠标坐标并重新绘制
  3. 在鼠标向上时,取消鼠标向下坐标以指示没有矩形,然后重新绘制。
  4. 在油漆上,绘制背景,然后在 mousedown 和 cur-mouse 坐标之间矩形。

if you don't want to keep a background image, you can do a trick with the Graphics xor function, drawing the same rect twice will erase the old rect, so you can use it to restore the old image straight on the graphics object.

如果您不想保留背景图像,您可以使用 Graphics xor 函数做一个技巧,绘制相同的 rect 两次将擦除旧的 rect,因此您可以使用它直接在图形对象上恢复旧图像。

Edit: code xor usage sample:

编辑:代码异或用法示例:

public void paint(Graphics g)
{
   g.setXORMode(Color.black);
   // draw old rect if there is one. this will erase it
   // draw new rect, this will draw xored
   g.setDrawMode(); // restore normal draw mode
}

Xor has the an interesting property:

Xor 有一个有趣的特性:

xor(xor(x)) = x

so xoring the same pixel twice restores it's original color.

所以对同一个像素进行两次异或运算可以恢复它的原始颜色。

回答by coobird

There are a couple issues that need to be addressed.

有几个问题需要解决。

First, regarding only one rectangle can be drawn, this is due to the design of your program. In your code, whenever the repaintoffscreenmethod is called, the currectRectfield is used to draw a rectangle. However, there is no provision to keep holding onto rectangles which were made in the past.

首先,关于只能绘制一个矩形,这是由于您的程序设计。在您的代码中,无论何时repaintoffscreen调用该方法,该currectRect字段都用于绘制一个矩形。但是,没有规定继续保持过去制作的矩形。

One way to keep a hold of past rectangles would be perhaps to make another field which is, for example, a List<Rectangle>which is used to store past rectangles. Then, when the mouse is released, addthe current rectangle to that list.

保留过去矩形的一种方法可能是创建另一个字段,例如,List<Rectangle>用于存储过去矩形的 a 。然后,当鼠标被释放时,add当前矩形到那个列表。

Then, in order for all rectangles, currentRectand past rectangles to appear, repaintoffscreenwill need to not only perform getDrawableRectand offscreen.drawRectusing the currentRectbut also with the past rectangles which are stored in the List<Rectangle>. (Hint, use a forloop to iterate through the list.)

然后,为了让所有矩形currentRect和过去的矩形出现,repaintoffscreen不仅需要执行getDrawableRectoffscreen.drawRect使用 ,currentRect而且还需要使用存储在List<Rectangle>. (提示,使用for循环遍历列表。)

Second, regarding the rectangle not appearing until after releasing the mouse button, rather than using the mouseDraggedmethod, maybe using the mouseMovedmethod along with a check to see that the mouse button is depressed may be a workaround. (I think I've also had trouble dealing with the mouseDraggedmethod in the past.)

其次,关于直到释放鼠标按钮后才出现的矩形,而不是使用该mouseDragged方法,也许使用该mouseMoved方法以及检查鼠标按钮是否被按下可能是一种解决方法。(我想我过去在处理这种mouseDragged方法时也遇到了麻烦。)

The MouseEventpassed into the mouseMovedmethod can be used to check if a button is depressed by the getButtonmethod:

MouseEvent传递到mouseMoved方法可用于检查一个按钮被按下getButton的方法:

public void mouseMoved(MouseEvent e)
{
    // Check if button1 is pressed.
    if (e.getButton() == MouseEvent.BUTTON1)
    {
        // Perform sizing of rectangle and off-screen drawing, and repaint.
    }
}

回答by Marcus Becker

My question was about create a select rectangle invert mouse click position, but, in the end I got make this with this method:

我的问题是关于创建一个选择矩形反转鼠标单击位置,但是,最后我用这个方法做了这个:

...     //to set the selection area
    private int iniSelX;
    private int iniSelY;
    private int endSelX;
    private int endSelY;

    private JPanel myJPanel = new JPanel() {

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());

            g.setColor(Color.red);
            g.drawLine(260, 5, 260, 260);

            g.setColor(Color.BLUE);

            //verify if go draw the rectangle
            if (iniSelX != 0 || endSelX != 0) {
                boolean revertX = iniSelX < endSelX;
                boolean revertY = iniSelY < endSelY;

                //Simple way
                //g.drawRect(iniSelX, iniSelY, endSelX - iniSelX, endSelY - iniSelY);

                //reverse way
                g.drawRect(revertX ? iniSelX : endSelX, revertY ? iniSelY : endSelY,
                        revertX ? endSelX - iniSelX : iniSelX - endSelX, revertY ? endSelY - iniSelY : iniSelY - endSelY);
            }
        }
    }; ...
        addMouseMotionListener(new MouseMotionListener() {

            @Override
            public void mouseDragged(MouseEvent m) {
                //update selection area
                endSelX = m.getX();
                endSelY = m.getY();

                repaint();
            }

            @Override
            public void mouseMoved(MouseEvent m) {
                repaint();
            }
        });

        addMouseListener(new MouseListener() {

 ...
            @Override
            public void mousePressed(MouseEvent e) {
               //start  drawing the selection
                iniSelX = e.getX() - 15;
                iniSelY = e.getY() - 20;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                //start  drawing the selection
                iniSelX = 0;
                iniSelY = 0;
                endSelX = 0;
                endSelY = 0;
            }

...
        });

    }

    public void log() {
        System.out.println("iniSelX" + iniSelX);
        System.out.println("iniSelY" + iniSelY);
        System.out.println("endSelX" + endSelX);
        System.out.println("endSelY" + endSelY);
    } ...

I hope this is useful.

我希望这是有用的。