在现有图形页面上绘制矩形

发布于 2024-12-10 21:53:59 字数 1294 浏览 0 评论 0原文

我有一个绘制绘图的 Java 应用程序。我想让用户能够用鼠标标记一个区域(例如,为了放大它)。 为此,我使用 MouseMotionListener 类,当鼠标(单击然后)移动时,我保存当前选定的矩形的位置(它不是最终的,因为用户尚未释放鼠标),并使用 <代码>repaint()函数。我希望在原始绘图上显示该矩形,使其类似于 MSPaint 中的选择工具。

问题是,当我调用 repaint() 函数时,会调用方法 paintComponent (Graphics page),其中我使用方法 super.paintComponent(页) 这会删除我的绘图。但是,如果我在知道用户正在选择一个矩形时不使用该方法,我会发现所有选定的矩形都“打包”在另一个上方,这是一个不希望的结果 - 我希望显示当前选择的矩形仅矩形。

我认为我应该能够保存绘图的图形页面的副本,并在每次用户移动鼠标时以某种方式恢复它,但我找不到任何有用方法的文档。

非常感谢你,

罗恩。

编辑:这是我的代码的相关部分:

public class DrawingPanel extends JPanel
{
public FractalPanel()
   {
      addMouseListener (new MyListener());
      addMouseMotionListener (new MyListener());

      setBackground (Color.black);
      setPreferredSize (new Dimension(200,200));
      setFocusable(true);
   }

public void paintComponent (Graphics page)
   {
        super.paintComponent(page);
        //that's where the drawing takes place: page.setColor(Color.red), page.drawOval(..) etc
   }
   private class MyListener implements MouseListener, MouseMotionListener
   {
   ...
      public void mouseDragged (MouseEvent event) 
      {
          //saving the location of the rectangle
          isHoldingRectangle = true;
          repaint();
       }
   }
}

I have a Java application which draws a drawing. I want to give the user the possibility to mark an area with the mouse (in order to, for example, zoom into it).
For that I use the MouseMotionListener class, and when the mouse is (clicked and then) moved, I save the location of the currently selected (it isn't final since the user haven't released the mouse) rectangle, and use the repaint() function. I wish to display that rectangle over the original drawing, making it similar to the Selection tool in MSPaint.

The problem is that when I call the repaint() function, the method paintComponent (Graphics page) is invoked, in which I use the method super.paintComponent(page) which erases my drawing. However, if I don't use that method when I know the user is selecting a rectangle, I get that all the selected rectangles are "packed" one above the other, and this is an undesirable result - I wish to display the currently selected rectangle only.

I thought I should be able to save a copy of the Graphics page of the drawing and somehow restore it every time the user moves the mouse, but I could not find any documentation for helpful methods.

Thank you very much,

Ron.

Edit: Here are the relevant pieces of my code:

public class DrawingPanel extends JPanel
{
public FractalPanel()
   {
      addMouseListener (new MyListener());
      addMouseMotionListener (new MyListener());

      setBackground (Color.black);
      setPreferredSize (new Dimension(200,200));
      setFocusable(true);
   }

public void paintComponent (Graphics page)
   {
        super.paintComponent(page);
        //that's where the drawing takes place: page.setColor(Color.red), page.drawOval(..) etc
   }
   private class MyListener implements MouseListener, MouseMotionListener
   {
   ...
      public void mouseDragged (MouseEvent event) 
      {
          //saving the location of the rectangle
          isHoldingRectangle = true;
          repaint();
       }
   }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

羅雙樹 2024-12-17 21:53:59

我敢打赌,您将通过组件上的 getGraphics() 调用来获取 Graphics 对象,并且会不满意,因为这会获取一个不持久的 Graphics 对象。正是由于这个原因,您不应该这样做,而应该在 JPanel 的 PaintComponent 内部进行绘图。如果你做到了这一点,一切都会幸福。

顺便说一句 - 如果您告诉我们更多问题的相关细节,例如您如何获取 Graphics 对象以及如何尝试用它进行绘图,这里的关键问题,我们将能够更好地帮助您。否则我们只能对你想要做什么进行疯狂的猜测。

例如,

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

public class MandelDraw extends JPanel {
private static final String IMAGE_ADDR = "http://upload.wikimedia.org/" +
        "wikipedia/commons/thumb/b/b3/Mandel_zoom_07_satellite.jpg/" +
        "800px-Mandel_zoom_07_satellite.jpg";
private static final Color DRAWING_RECT_COLOR = new Color(200, 200, 255);
private static final Color DRAWN_RECT_COLOR = Color.blue;

   private BufferedImage image;
   private Rectangle rect = null;
   private boolean drawing = false;

   public MandelDraw() {
      try {
         image = ImageIO.read(new URL(IMAGE_ADDR));
         MyMouseAdapter mouseAdapter = new MyMouseAdapter();
         addMouseListener(mouseAdapter);
         addMouseMotionListener(mouseAdapter);
      } catch (MalformedURLException e) {
         e.printStackTrace();
         System.exit(-1);
      } catch (IOException e) {
         e.printStackTrace();
         System.exit(-1);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      if (image != null) {
         return new Dimension(image.getWidth(), image.getHeight());
      }
      return super.getPreferredSize();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D)g;
      if (image != null) {
         g.drawImage(image, 0, 0, null);
      }
      if (rect == null) {
         return;
      } else if (drawing) {
         g2.setColor(DRAWING_RECT_COLOR);
         g2.draw(rect);
      } else {
         g2.setColor(DRAWN_RECT_COLOR);
         g2.draw(rect);
      }
   }

   private class MyMouseAdapter extends MouseAdapter {
      private Point mousePress = null; 
      @Override
      public void mousePressed(MouseEvent e) {
         mousePress = e.getPoint();
      }

      @Override
      public void mouseDragged(MouseEvent e) {
         drawing = true;
         int x = Math.min(mousePress.x, e.getPoint().x);
         int y = Math.min(mousePress.y, e.getPoint().y);
         int width = Math.abs(mousePress.x - e.getPoint().x);
         int height = Math.abs(mousePress.y - e.getPoint().y);

         rect = new Rectangle(x, y, width, height);
         repaint();
      }

      @Override
      public void mouseReleased(MouseEvent e) {
         drawing = false;
         repaint();
      }

   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("MandelDraw");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new MandelDraw());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

I'm betting that you are getting your Graphics object via a getGraphics() call on a component, and are disatisfied since this obtains a Graphics object which does not persist. It is for this reason that you shouldn't do this but instead just do your drawing inside of the JPanel's paintComponent. If you do this all will be happy.

As an aside -- we'll be able to help you better if you tell us more of the pertinent details of your problem such as how you're getting your Graphics object and how you're trying to draw with it, key issues here. Otherwise we're limited to taking wild guesses about what you're trying to do.

e.g.,

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

public class MandelDraw extends JPanel {
private static final String IMAGE_ADDR = "http://upload.wikimedia.org/" +
        "wikipedia/commons/thumb/b/b3/Mandel_zoom_07_satellite.jpg/" +
        "800px-Mandel_zoom_07_satellite.jpg";
private static final Color DRAWING_RECT_COLOR = new Color(200, 200, 255);
private static final Color DRAWN_RECT_COLOR = Color.blue;

   private BufferedImage image;
   private Rectangle rect = null;
   private boolean drawing = false;

   public MandelDraw() {
      try {
         image = ImageIO.read(new URL(IMAGE_ADDR));
         MyMouseAdapter mouseAdapter = new MyMouseAdapter();
         addMouseListener(mouseAdapter);
         addMouseMotionListener(mouseAdapter);
      } catch (MalformedURLException e) {
         e.printStackTrace();
         System.exit(-1);
      } catch (IOException e) {
         e.printStackTrace();
         System.exit(-1);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      if (image != null) {
         return new Dimension(image.getWidth(), image.getHeight());
      }
      return super.getPreferredSize();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D)g;
      if (image != null) {
         g.drawImage(image, 0, 0, null);
      }
      if (rect == null) {
         return;
      } else if (drawing) {
         g2.setColor(DRAWING_RECT_COLOR);
         g2.draw(rect);
      } else {
         g2.setColor(DRAWN_RECT_COLOR);
         g2.draw(rect);
      }
   }

   private class MyMouseAdapter extends MouseAdapter {
      private Point mousePress = null; 
      @Override
      public void mousePressed(MouseEvent e) {
         mousePress = e.getPoint();
      }

      @Override
      public void mouseDragged(MouseEvent e) {
         drawing = true;
         int x = Math.min(mousePress.x, e.getPoint().x);
         int y = Math.min(mousePress.y, e.getPoint().y);
         int width = Math.abs(mousePress.x - e.getPoint().x);
         int height = Math.abs(mousePress.y - e.getPoint().y);

         rect = new Rectangle(x, y, width, height);
         repaint();
      }

      @Override
      public void mouseReleased(MouseEvent e) {
         drawing = false;
         repaint();
      }

   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("MandelDraw");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new MandelDraw());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
浮世清欢 2024-12-17 21:53:59

您需要在每次鼠标移动时重新绘制:

    public void mouseDragged(MouseEvent e){
        int x = e.getX();
        int y = e.getY();
        //Update the rectangle holder object with that point coordinates
        repaint();
    }

您可能有一个固定矩形对象来保存初始和最终矩形点。声母在鼠标单击时设置,韵母在鼠标拖动和释放时修改。

paint方法中,清除图形并用支架中的坐标绘制一个矩形。这是基本思想。

更新:如何在现有图像之上绘制新形状:
我正在考虑两种选择:

  1. 如果您只绘制形状(例如线条、矩形和其他 Java2D 内容),您可以使用一个 Collection 来保存这些形状坐标,并在每个 paint 上绘制所有形状。优点:当形状很少时,效果很好,可以撤消。缺点:当形状数量增加时,paint 方法在每次传递中将花费越来越多的时间。
  2. 有一个“背景图像”。在每次 paint 调用中,首先绘制图像,然后在顶部绘制当前活动的形状。当活动形状持久化(onMouseReleased)时,它会保存到背景图像中。优点:高效、时间恒定。缺点:每次鼠标移动时绘制一个大的背景图像可能会“昂贵”。

You need to repaint on every mouse movement:

    public void mouseDragged(MouseEvent e){
        int x = e.getX();
        int y = e.getY();
        //Update the rectangle holder object with that point coordinates
        repaint();
    }

You'll probably have a holder rectangle object to hold the initial and final rectangle points. The initials are set on mouse click, the final are modified on mouse dragged and on mouse released.

In paint method, clear the graphics and draw a rectangle with the coordinates in the holder. This is the basic idea.

UPDATE: How to draw a new shape on top of the existing image:
I'm thinking of two options:

  1. If you are only drawing shapes (such as lines, rectangles and other Java2D stuff) you could have a Collection holding these shapes coordinates, and draw all of them on each paint. Pros: good when there are few shapes, allows undoing. Cons: When the number of shapes increase, the paint method will take more and more time in each pass.
  2. Have a "background image". On each paint call, draw first the image and then the currently active shape on top. when an active shape is made persistent (onMouseReleased), it is saved to the background image. Pros: efficient, constant time. Cons: drawing a big background image on every mouse movement could be "expensive".
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文