如何在打开的菜单下绘制图像 [英] How to draw an Image underneath an open Menu

查看:91
本文介绍了如何在打开的菜单下绘制图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为JPanel中的BufferedImage实现自己的双缓冲,这样我就可以在BufferedImage中显示鼠标位置,而无需在mousemovement上重新绘制每个对象.当父JFrame中的JMenu打开时,BufferedImage会在JMenu顶部重新绘制.

此类并不完整,仅具有必要的方法,

    public class Foo extends JPanel implements ComponentListener {
        BufferedImage bufferedImage;
        long mousePosX;
        long mousePoxY;

        protected void paintComponent(Graphics g) {
            paintComponent(g, this.xform);
        }
        protected void paintComponent(Graphics graphics, XFormPixel xformIn) {
            bufferedImage = new BufferedImage(this.getWidth(),this.getHeight(),BufferedImage.TYPE_INT_RGB);
            Graphics g = bufferedImage.getGraphics();
            super.paintComponent(g);
            //Draw lots of stuff to graphics

            if(drawMouseLocation) {
                int width = this.getWidth();
                int height = this.getHeight();
                Color origColor = g.getColor();
                g.setColor(textColor);
                if (cursorLocation != null) {
                    g.drawString("X: "+mousePosX + " Y: " + mousePosY);
                }
            }

            g.setColor(origColor);
            graphics.drawImage(bufferedImage,0,0,null);
        }

        public void drawMouseLocation() {   

            int width = this.getWidth();
            int height = this.getHeight();
            Image image = bufferedImage;
            Graphics graphics = this.getGraphics();
            Graphics g = image.getGraphics();
            Color origColor = g.getColor();
            g.setColor(textColor);
            if (cursorLocation != null) {
                g.drawString("X: "+mousePosX + " Y: " + mousePosY);
            }
            g.setColor(origColor);
            graphics.drawImage(image,0,0,this);
        }
    }

还有另一种方法吗?

另一个可能的破坏因素是,初始化Foo JPanel时,它具有黑色边框,但是当绘制图像以显示鼠标位置时,该边框消失.我假设在父对象上调用repaint()或其他方法可以解决这两个问题,但在子对象上也要调用repaint,我想避免这种情况.

这是请求的可运行代码.创建它时,我无法使双缓冲正常工作,因此在移动鼠标时,鼠标位置的闪烁也很麻烦.

    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import javax.swing.AbstractAction;
    import javax.swing.Action;
    import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;

    public class DrawingTestFrame extends JFrame {
        private static final long serialVersionUID = 1L;        

        public static void main(String[] args) {
                new DrawingTestFrame();
        }   
        public DrawingTestFrame() {
                init();
        }

        public void init() {
                JMenuBar menuBar = new JMenuBar();                  
                    setJMenuBar(menuBar);
                JMenu dropMenu = new JMenu("Drop This");
                dropMenu.add(needs);
                dropMenu.add(to);
                dropMenu.add(overlap);
                menuBar.add(dropMenu);          
                    DrawingTest test = new DrawingTest();
                setTitle("Drawing Test");
                add(test);
                setMinimumSize(new Dimension(550,270));
                pack();
                setVisible(true);
        }

            public static Action needs = new AbstractAction("Needs") {
                private static final long serialVersionUID = 1L;
                public void actionPerformed(ActionEvent ae) {}};    
            public static Action to = new AbstractAction("To") {
                private static final long serialVersionUID = 1L;
                public void actionPerformed(ActionEvent ae) {}};    
            public static Action overlap = new AbstractAction("Overlap") {
                private static final long serialVersionUID = 1L;
                public void actionPerformed(ActionEvent ae) {}};    
    }


    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.MouseInfo;
    import java.awt.Point;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.MouseMotionListener;
    import java.awt.image.BufferedImage;
    import javax.swing.BorderFactory;
    import javax.swing.JPanel;

    public class DrawingTest extends JPanel implements MouseListener  {
        private static final long serialVersionUID = 1L;
            public Component parent;
            private Point mouseLocation;
            private BufferedImage bufferedImage;
            public DrawingTest() {
                    init();
            }        
            public void init() {
                    this.setPreferredSize(new Dimension(100, 100));
                    this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
                    this.addMouseListener(this);
                    this.addMouseMotionListener(new MouseMotionListener() {
                public void mouseDragged(MouseEvent e) {
                    mouseLocation = MouseInfo.getPointerInfo().getLocation();
                    DrawingTest.this.repaint();
                }

                public void mouseMoved(MouseEvent e) {
                    mouseLocation = MouseInfo.getPointerInfo().getLocation();
                    DrawingTest.this.drawLocation();
                }
                    });
                    this.setVisible(true);
            }
        public void mouseClicked(MouseEvent e) {
            mouseLocation = MouseInfo.getPointerInfo().getLocation();
            this.repaint();
        }
        public void mousePressed(MouseEvent e) {}
        public void mouseReleased(MouseEvent e) {}
        public void mouseEntered(MouseEvent e) {}
        public void mouseExited(MouseEvent e) {}

            protected void paintComponent(Graphics graphics) {
                    bufferedImage = new   
                            BufferedImage(this.getWidth(),this.getHeight(),BufferedImage.TYPE_INT_RGB);
                    Graphics2D g = bufferedImage.createGraphics();
                    super.paintComponent(g);
                    g.setColor(Color.red);
                    g.drawRect(10,10,110,110);
                    graphics.drawImage(bufferedImage,0,0,null);
                    if (mouseLocation != null) {
                        graphics.drawString("X: " + mouseLocation.getX() + 
                "  Y: " + mouseLocation.getY(), this.getWidth()/2 - 50, this.getHeight()-10);
                    }
            }
            protected void drawLocation() {
                    this.getGraphics().drawImage(bufferedImage, 0,0,null);
                    this.getGraphics().setColor(Color.green);
                    if (mouseLocation != null) {
                        this.getGraphics().drawString("X: " + mouseLocation.getX() + 
                "  Y: " + mouseLocation.getY(), this.getWidth()/2 - 50, this.getHeight()-10);
                    }
            }
    }

谢谢!

解决方案

问题是您通过在组件上调用getGraphics()来获取Graphics对象,而您不应该这样做.为什么要进行这种自制的双缓冲,在哪里读到这是实现它的方法?我想看那个教程.如果这是我的应用程序,那么我要么:

  • 对我的背景图像使用BufferedImage,然后在paintComponent上简单地绘制它,也许将我的绘画限制在感兴趣的矩形内...
  • 或使用JLabel显示我的鼠标位置.

例如,此代码显示了两种技术:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import javax.swing.*;

@SuppressWarnings("serial")
public class DrawingTestFrame2 {
   private static void createAndShowGui() {
      JFrame frame = new JFrame("DrawingTestFrame2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      DrawingTest2 drawingTest = new DrawingTest2();

      frame.getContentPane().add(drawingTest);
      frame.setJMenuBar(drawingTest.createMenuBar());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

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

class DrawingTest2 extends JPanel {

   private static final int PREF_W = 500;
   private static final int PREF_H = 300;
   private static final int RECT_W = 100;
   private static final int RECT_H = 20;
   public static final Rectangle BOTTOM_RECT = new Rectangle(PREF_W/2 - RECT_W/2, PREF_H - RECT_H, 
         RECT_W, RECT_H);
   private String[] menuItemStrings = {"One", "Two", "Three"};
   public Point mouseLocation;
   private BufferedImage bufferedImage = new BufferedImage(PREF_W, PREF_H, 
         BufferedImage.TYPE_INT_ARGB);
   private JLabel mousePositionLabel = new JLabel("", SwingConstants.RIGHT);

   public DrawingTest2() {
      MouseAdapter mouseAdapter = new MyMouseAdapter();
      addMouseListener(mouseAdapter);
      addMouseMotionListener(mouseAdapter);

      mousePositionLabel.setForeground(Color.gray);
      setLayout(new GridBagLayout());
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.gridx = 1;
      gbc.gridy = 1;
      gbc.gridwidth = 1;
      gbc.gridheight = 1;
      gbc.weightx = 1.0;
      gbc.weighty = 1.0;
      gbc.anchor = GridBagConstraints.SOUTHEAST;
      add(mousePositionLabel, gbc);

      Graphics2D g2 = bufferedImage.createGraphics();
      g2.setPaint(new GradientPaint(0, 0, Color.yellow, 40, 40, Color.green, true));
      g2.fillRect(0, 0, PREF_W, PREF_H);
      g2.dispose();
      g2 = bufferedImage.createGraphics();
      g2.setColor(Color.red);
      g2.setStroke(new BasicStroke(3f));
      g2.drawRect(10, 10, 110, 110);
      g2.dispose();
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (bufferedImage != null) {
         g.drawImage(bufferedImage, 0, 0, this);
      }
      if (mouseLocation != null) {
         g.drawString("X: " + mouseLocation.getX() + "  Y: "
               + mouseLocation.getY(), this.getWidth() / 2 - 50,
               this.getHeight() - 10);
      }
   }

   public JMenuBar createMenuBar() {
      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("Menu");
      for (int i = 0; i < menuItemStrings .length; i++) {
         menu.add(new JMenuItem(menuItemStrings[i]));
      }
      menuBar.add(menu );
      return menuBar;
   }

   class MyMouseAdapter extends MouseAdapter {
      @Override
      public void mouseMoved(MouseEvent mEvt) {
         mouseLocation = mEvt.getLocationOnScreen();
         repaint(BOTTOM_RECT);

         String mousePosStr = String.format("x:%d y:%d", mouseLocation.x, mouseLocation.y);
         mousePositionLabel.setText(mousePosStr);
      }
   }
}

I'm implementing my own double-buffering for a BufferedImage in a JPanel so that I can display the mouse location in the BufferedImage without repainting every object back onto it on mousemovement. When a JMenu in the parent JFrame is open, the BufferedImage gets repainted on top of the JMenu.

This class is not complete, and has only the necessary methods,

    public class Foo extends JPanel implements ComponentListener {
        BufferedImage bufferedImage;
        long mousePosX;
        long mousePoxY;

        protected void paintComponent(Graphics g) {
            paintComponent(g, this.xform);
        }
        protected void paintComponent(Graphics graphics, XFormPixel xformIn) {
            bufferedImage = new BufferedImage(this.getWidth(),this.getHeight(),BufferedImage.TYPE_INT_RGB);
            Graphics g = bufferedImage.getGraphics();
            super.paintComponent(g);
            //Draw lots of stuff to graphics

            if(drawMouseLocation) {
                int width = this.getWidth();
                int height = this.getHeight();
                Color origColor = g.getColor();
                g.setColor(textColor);
                if (cursorLocation != null) {
                    g.drawString("X: "+mousePosX + " Y: " + mousePosY);
                }
            }

            g.setColor(origColor);
            graphics.drawImage(bufferedImage,0,0,null);
        }

        public void drawMouseLocation() {   

            int width = this.getWidth();
            int height = this.getHeight();
            Image image = bufferedImage;
            Graphics graphics = this.getGraphics();
            Graphics g = image.getGraphics();
            Color origColor = g.getColor();
            g.setColor(textColor);
            if (cursorLocation != null) {
                g.drawString("X: "+mousePosX + " Y: " + mousePosY);
            }
            g.setColor(origColor);
            graphics.drawImage(image,0,0,this);
        }
    }

Is there another way to do this?

Another possible dealbreaker is that when the Foo JPanel is initialized, it has a black border, but when the image is drawn to display the mouselocation, the border disappears. I'm assuming calling a repaint() or something on the parent will fix both issues, but it would also call a repaint on the child, which I am trying to avoid.

EDIT 1: Here is the requested runnable code. When creating it, I could not get the double-buffering working correctly, so I'm also having trouble with the flickering of the mouse location when the mouse is moved.

    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import javax.swing.AbstractAction;
    import javax.swing.Action;
    import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;

    public class DrawingTestFrame extends JFrame {
        private static final long serialVersionUID = 1L;        

        public static void main(String[] args) {
                new DrawingTestFrame();
        }   
        public DrawingTestFrame() {
                init();
        }

        public void init() {
                JMenuBar menuBar = new JMenuBar();                  
                    setJMenuBar(menuBar);
                JMenu dropMenu = new JMenu("Drop This");
                dropMenu.add(needs);
                dropMenu.add(to);
                dropMenu.add(overlap);
                menuBar.add(dropMenu);          
                    DrawingTest test = new DrawingTest();
                setTitle("Drawing Test");
                add(test);
                setMinimumSize(new Dimension(550,270));
                pack();
                setVisible(true);
        }

            public static Action needs = new AbstractAction("Needs") {
                private static final long serialVersionUID = 1L;
                public void actionPerformed(ActionEvent ae) {}};    
            public static Action to = new AbstractAction("To") {
                private static final long serialVersionUID = 1L;
                public void actionPerformed(ActionEvent ae) {}};    
            public static Action overlap = new AbstractAction("Overlap") {
                private static final long serialVersionUID = 1L;
                public void actionPerformed(ActionEvent ae) {}};    
    }


    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.MouseInfo;
    import java.awt.Point;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.MouseMotionListener;
    import java.awt.image.BufferedImage;
    import javax.swing.BorderFactory;
    import javax.swing.JPanel;

    public class DrawingTest extends JPanel implements MouseListener  {
        private static final long serialVersionUID = 1L;
            public Component parent;
            private Point mouseLocation;
            private BufferedImage bufferedImage;
            public DrawingTest() {
                    init();
            }        
            public void init() {
                    this.setPreferredSize(new Dimension(100, 100));
                    this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
                    this.addMouseListener(this);
                    this.addMouseMotionListener(new MouseMotionListener() {
                public void mouseDragged(MouseEvent e) {
                    mouseLocation = MouseInfo.getPointerInfo().getLocation();
                    DrawingTest.this.repaint();
                }

                public void mouseMoved(MouseEvent e) {
                    mouseLocation = MouseInfo.getPointerInfo().getLocation();
                    DrawingTest.this.drawLocation();
                }
                    });
                    this.setVisible(true);
            }
        public void mouseClicked(MouseEvent e) {
            mouseLocation = MouseInfo.getPointerInfo().getLocation();
            this.repaint();
        }
        public void mousePressed(MouseEvent e) {}
        public void mouseReleased(MouseEvent e) {}
        public void mouseEntered(MouseEvent e) {}
        public void mouseExited(MouseEvent e) {}

            protected void paintComponent(Graphics graphics) {
                    bufferedImage = new   
                            BufferedImage(this.getWidth(),this.getHeight(),BufferedImage.TYPE_INT_RGB);
                    Graphics2D g = bufferedImage.createGraphics();
                    super.paintComponent(g);
                    g.setColor(Color.red);
                    g.drawRect(10,10,110,110);
                    graphics.drawImage(bufferedImage,0,0,null);
                    if (mouseLocation != null) {
                        graphics.drawString("X: " + mouseLocation.getX() + 
                "  Y: " + mouseLocation.getY(), this.getWidth()/2 - 50, this.getHeight()-10);
                    }
            }
            protected void drawLocation() {
                    this.getGraphics().drawImage(bufferedImage, 0,0,null);
                    this.getGraphics().setColor(Color.green);
                    if (mouseLocation != null) {
                        this.getGraphics().drawString("X: " + mouseLocation.getX() + 
                "  Y: " + mouseLocation.getY(), this.getWidth()/2 - 50, this.getHeight()-10);
                    }
            }
    }

Thanks!

解决方案

The problem is you're getting your Graphics object by calling getGraphics() on a component and this you should not do. Why are you doing this home-cooked double buffering, and where have you read that this is the way to implement it? I'd like to see that tutorial. If this were my application, I'd either:

  • Use a BufferedImage for my background images, and simply draw over it in paintComponent, perhaps limiting my painting to the rectangle of interest...
  • or show my mouse position using a JLabel.

For example, this code shows both techniques:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import javax.swing.*;

@SuppressWarnings("serial")
public class DrawingTestFrame2 {
   private static void createAndShowGui() {
      JFrame frame = new JFrame("DrawingTestFrame2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      DrawingTest2 drawingTest = new DrawingTest2();

      frame.getContentPane().add(drawingTest);
      frame.setJMenuBar(drawingTest.createMenuBar());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

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

class DrawingTest2 extends JPanel {

   private static final int PREF_W = 500;
   private static final int PREF_H = 300;
   private static final int RECT_W = 100;
   private static final int RECT_H = 20;
   public static final Rectangle BOTTOM_RECT = new Rectangle(PREF_W/2 - RECT_W/2, PREF_H - RECT_H, 
         RECT_W, RECT_H);
   private String[] menuItemStrings = {"One", "Two", "Three"};
   public Point mouseLocation;
   private BufferedImage bufferedImage = new BufferedImage(PREF_W, PREF_H, 
         BufferedImage.TYPE_INT_ARGB);
   private JLabel mousePositionLabel = new JLabel("", SwingConstants.RIGHT);

   public DrawingTest2() {
      MouseAdapter mouseAdapter = new MyMouseAdapter();
      addMouseListener(mouseAdapter);
      addMouseMotionListener(mouseAdapter);

      mousePositionLabel.setForeground(Color.gray);
      setLayout(new GridBagLayout());
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.gridx = 1;
      gbc.gridy = 1;
      gbc.gridwidth = 1;
      gbc.gridheight = 1;
      gbc.weightx = 1.0;
      gbc.weighty = 1.0;
      gbc.anchor = GridBagConstraints.SOUTHEAST;
      add(mousePositionLabel, gbc);

      Graphics2D g2 = bufferedImage.createGraphics();
      g2.setPaint(new GradientPaint(0, 0, Color.yellow, 40, 40, Color.green, true));
      g2.fillRect(0, 0, PREF_W, PREF_H);
      g2.dispose();
      g2 = bufferedImage.createGraphics();
      g2.setColor(Color.red);
      g2.setStroke(new BasicStroke(3f));
      g2.drawRect(10, 10, 110, 110);
      g2.dispose();
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (bufferedImage != null) {
         g.drawImage(bufferedImage, 0, 0, this);
      }
      if (mouseLocation != null) {
         g.drawString("X: " + mouseLocation.getX() + "  Y: "
               + mouseLocation.getY(), this.getWidth() / 2 - 50,
               this.getHeight() - 10);
      }
   }

   public JMenuBar createMenuBar() {
      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("Menu");
      for (int i = 0; i < menuItemStrings .length; i++) {
         menu.add(new JMenuItem(menuItemStrings[i]));
      }
      menuBar.add(menu );
      return menuBar;
   }

   class MyMouseAdapter extends MouseAdapter {
      @Override
      public void mouseMoved(MouseEvent mEvt) {
         mouseLocation = mEvt.getLocationOnScreen();
         repaint(BOTTOM_RECT);

         String mousePosStr = String.format("x:%d y:%d", mouseLocation.x, mouseLocation.y);
         mousePositionLabel.setText(mousePosStr);
      }
   }
}

这篇关于如何在打开的菜单下绘制图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆