2

我正在为 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,这是我试图避免的。

编辑 1:这是请求的可运行代码。创建它时,我无法使双缓冲正常工作,因此我也遇到了移动鼠标时鼠标位置闪烁的问题。

    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);
                    }
            }
    }

谢谢!

4

2 回答 2

1

问题是您通过在组件上调用 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);
      }
   }
}
于 2012-03-22T18:30:41.957 回答
0

有一个类叫做 DisplayJAI。即可以显示PlanarImage(可以使用PlanarImage包装BufferedImage)。它扩展了 JPanel 并且已经为您提供了所需的所有鼠标侦听器。在这件事上,你不需要覆盖油漆或做任何事情。

于 2012-03-16T16:58:28.893 回答