Java JPanel getGraphics()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21322353/
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-13 08:02:41  来源:igfitidea点击:

Java JPanel getGraphics()

javaswinggraphicsjpanelpaintcomponent

提问by Mushy

Since Java only supports single inheritance, I desire to paintdirectly on an instance of a JPanelthat is a member of the class Panel. I grab an instance of Graphicsfrom the member and then paint whatever I desire onto it.

由于 Java 只支持single inheritance,我希望paint直接在作为JPanel类成员的a 的实例上Panel。我Graphics从成员那里获取一个实例,然后在上面绘制我想要的任何东西。

How can I not inherit from JComponentor JPaneland still utilize getGraphics()for painting on thiswithout overriding public void paintComponent(Graphics g)?

我怎么能不继承JComponentJPanel仍然getGraphics()用于绘画this而不覆盖public void paintComponent(Graphics g)

private class Panel
{
      private JPanel panel;
      private Grahics g;

      public Panel()
      {
           panel = new JPanel();
      }

      public void draw()
      {
           g = panel.getGraphics();
           g.setColor(Color.CYAN);
           g.draw(Some Component);
           panel.repaint();
      }
}

The panel is added to a JFramethat is made visible prior to calling panel.draw(). This approach is not working for me and, although I already know how to paint custom components by inheriting from JPaneland overriding public void paintComponent(Graphics g), I did not want to inherit from JPanel.

面板被添加到JFrame在调用之前可见的panel.draw()。这种方法对我不起作用,虽然我已经知道如何通过继承JPanel和覆盖来绘制自定义组件,但我public void paintComponent(Graphics g)不想从JPanel.

采纳答案by Radiodef

Here are some very simple examples which show how to paint outside paintComponent.

这里有一些非常简单的例子,展示了如何在外面画画paintComponent

The drawing actually happens on a java.awt.image.BufferedImage, and we can do that anywhere, as long as we're on the Event Dispatch Thread. (For discussion of multithreading with Swing, see hereand here.)

绘图实际上发生在 a 上java.awt.image.BufferedImage,我们可以在任何地方进行,只要我们在事件调度线程上。(有关使用 Swing 进行多线程的讨论,请参见此处此处。)

Then, I'm overriding paintComponent, but only to paint the image on to the panel. (I also paint a little swatch in the corner.)

然后,我覆盖paintComponent, 但只是将图像绘制到面板上。(我还在角落里画了一个小色板。)

This way the drawing is actually permanent, and Swing is able to repaint the panel if it needs to without causing a problem for us. We could also do something like save the image to a file easily, if we wanted to.

这样绘图实际上是永久性的,并且 Swing 能够在需要时重新绘制面板而不会给我们带来问题。如果我们愿意,我们还可以轻松地将图像保存到文件中。

PaintAnyTime screenshot

PaintAnyTime 屏幕截图

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

/**
 * Holding left-click draws, and
 * right-clicking cycles the color.
 */
class PaintAnyTime {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new PaintAnyTime();
            }
        });
    }

    Color[]    colors = {Color.red, Color.blue, Color.black};
    int  currentColor = 0;
    BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
    Graphics2D  imgG2 = img.createGraphics();

    JFrame frame = new JFrame("Paint Any Time");
    JPanel panel = new JPanel() {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            // Creating a copy of the Graphics
            // so any reconfiguration we do on
            // it doesn't interfere with what
            // Swing is doing.
            Graphics2D g2 = (Graphics2D) g.create();
            // Drawing the image.
            int w = img.getWidth();
            int h = img.getHeight();
            g2.drawImage(img, 0, 0, w, h, null);
            // Drawing a swatch.
            Color color = colors[currentColor];
            g2.setColor(color);
            g2.fillRect(0, 0, 16, 16);
            g2.setColor(Color.black);
            g2.drawRect(-1, -1, 17, 17);
            // At the end, we dispose the
            // Graphics copy we've created
            g2.dispose();
        }
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(img.getWidth(), img.getHeight());
        }
    };

    MouseAdapter drawer = new MouseAdapter() {
        boolean rButtonDown;
        Point prev;

        @Override
        public void mousePressed(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e)) {
                prev = e.getPoint();
            }
            if (SwingUtilities.isRightMouseButton(e) && !rButtonDown) {
                // (This just behaves a little better
                // than using the mouseClicked event.)
                rButtonDown  = true;
                currentColor = (currentColor + 1) % colors.length;
                panel.repaint();
            }
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (prev != null) {
                Point  next = e.getPoint();
                Color color = colors[currentColor];
                // We can safely paint to the
                // image any time we want to.
                imgG2.setColor(color);
                imgG2.drawLine(prev.x, prev.y, next.x, next.y);
                // We just need to repaint the
                // panel to make sure the
                // changes are visible
                // immediately.
                panel.repaint();
                prev = next;
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e)) {
                prev = null;
            }
            if (SwingUtilities.isRightMouseButton(e)) {
                rButtonDown = false;
            }
        }
    };

    PaintAnyTime() {
        // RenderingHints let you specify
        // options such as antialiasing.
        imgG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
        imgG2.setStroke(new BasicStroke(3));
        //
        panel.setBackground(Color.white);
        panel.addMouseListener(drawer);
        panel.addMouseMotionListener(drawer);
        Cursor cursor =
            Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
        panel.setCursor(cursor);
        frame.setContentPane(panel);
        frame.pack();
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

It's also possible to set up a JLabelwith an ImageIcon, although personally I don't like this method. I don't think JLabeland ImageIconare required by their specifications to see changes we make to the image after we've passed it to the constructors.

它也有可能建立一个JLabelImageIcon,虽然我个人不喜欢这种方法。我不认为JLabel并且ImageIcon他们的规范要求在我们将图像传递给构造函数后查看我们对图像所做的更改。

This way also doesn't let us do stuff like painting the swatch. (For a slightly more complicated paint program, on the level of e.g. MSPaint, we'd want to have a way to select an area and draw a bounding box around it. That's another place we'd want to be able to paint directly on the panel, in addition to drawing to the image.)

这种方式也不会让我们做诸如绘制色板之类的事情。(对于稍微复杂一点的绘画程序,例如在 MSPaint 级别,我们希望有一种方法来选择一个区域并在它周围绘制一个边界框。这是我们希望能够直接在其上绘画的另一个地方面板,除了绘制到图像。)

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

/**
 * Holding left-click draws, and
 * right-clicking cycles the color.
 */
class PaintAnyTime {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new PaintAnyTime();
            }
        });
    }

    Color[]    colors = {Color.red, Color.blue, Color.black};
    int  currentColor = 0;
    BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
    Graphics2D  imgG2 = img.createGraphics();

    JFrame frame = new JFrame("Paint Any Time");
    JLabel label = new JLabel(new ImageIcon(img));

    MouseAdapter drawer = new MouseAdapter() {
        boolean rButtonDown;
        Point prev;

        @Override
        public void mousePressed(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e)) {
                prev = e.getPoint();
            }
            if (SwingUtilities.isRightMouseButton(e) && !rButtonDown) {
                // (This just behaves a little better
                // than using the mouseClicked event.)
                rButtonDown  = true;
                currentColor = (currentColor + 1) % colors.length;
                label.repaint();
            }
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (prev != null) {
                Point  next = e.getPoint();
                Color color = colors[currentColor];
                // We can safely paint to the
                // image any time we want to.
                imgG2.setColor(color);
                imgG2.drawLine(prev.x, prev.y, next.x, next.y);
                // We just need to repaint the
                // label to make sure the
                // changes are visible
                // immediately.
                label.repaint();
                prev = next;
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e)) {
                prev = null;
            }
            if (SwingUtilities.isRightMouseButton(e)) {
                rButtonDown = false;
            }
        }
    };

    PaintAnyTime() {
        // RenderingHints let you specify
        // options such as antialiasing.
        imgG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
        imgG2.setStroke(new BasicStroke(3));
        //
        label.setPreferredSize(new Dimension(img.getWidth(), img.getHeight()));
        label.setBackground(Color.white);
        label.setOpaque(true);
        label.addMouseListener(drawer);
        label.addMouseMotionListener(drawer);
        Cursor cursor =
            Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
        label.setCursor(cursor);
        frame.add(label, BorderLayout.CENTER);
        frame.pack();
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

回答by Exorcismus

class SomeComponent extends JComponent {

    private Graphics2D g2d;

    public void paintComponent(Graphics g) {
        g2d = (Graphics2D) g.create();
        g2d.setColor(Color.BLACK);
        g2d.scale(scale, scale);
        g2d.drawOval(0, 0, importance, importance);

    }

    public Graphics2D getG2d() {
        return g2d;
    }
    public void setG2d(Graphics2D g2d) {
        this.g2d = g2d;
    }
}

then you can do the following get the SomeComponent instance in the panel and modify it

那么你可以做以下操作获取面板中的 SomeComponent 实例并修改它

Graphics2D x= v.getPanel().get(i).getG2d;
x.setColor(Color.BLUE);
v.getPanel().get(i).setG2d(x);
v.getPanel().repaint();
v.getPanel().revalidate();

V is a class that extends JFrame and contains the panel in it AND i is instance of SomeComponent

V 是一个扩展 JFrame 并在其中包含面板的类,并且 i 是 SomeComponent 的实例