Java:在 ActionListener 中使用图形组件

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

Java: Using graphics component within an ActionListener

javagraphicsawtpaint

提问by robert825

I have two separate class and driver files, and in the class file I create the paint method:

我有两个单独的类和驱动程序文件,在类文件中我创建了paint方法:

public void paint(Graphics g){
g.drawLine(......
....
//along with all of my other draw commands
}

Further down in the code, I create a JButton and within this button's action listener I don't know how to use a Graphics object to create more graphics in the JFrame. Should I be adding something to my driver to make this happen, or is there a way to use these graphics within my action listener? Thank you, and any help is appreciated.

在代码的更深处,我创建了一个 JButton,在这个按钮的动作侦听器中,我不知道如何使用 Graphics 对象在 JFrame 中创建更多图形。我应该向我的驱动程序添加一些东西来实现这一点,还是有办法在我的动作侦听器中使用这些图形?谢谢,任何帮助表示赞赏。

采纳答案by Paul Samsotha

You need to draw everything within the paintmethod. The actionPerformedshould only change the state of something alreadyin the paintmethod, and then call repaint. For example

您需要在paint方法中绘制所有内容 。本actionPerformed应该只改变事物的状态已经paint方法,然后调用repaint。例如

boolean drawHello = true;
boolean drawWorld = false;

protected void paintComponent(Graphics g) {
    super.paintCompoent(g);
    if (drawHello)
             g.drawString("Hello", 50, 50);

    if (drawWorld)
             g.drawString("World", 10, 10);
}

Then in your actionPerformed, you can change the state of drawWorldto trueand call repaint().

然后在 your 中actionPerformed,您可以更改drawWorldtotrue和 call的状态repaint()

public void actionPerformed(ActionEvent e) {
    drawWorld = true;
    repaint();
}

So as you can see, everything should be drawn in the paintComponentmethod. You can just hide and paint renderings, and make them "visible"from a action command. You should already have predefined what could posibly be drawn. Then just change the state of it rendering

如您所见,所有内容都应在paintComponent方法中绘制。您可以隐藏和绘制渲染,并通过操作命令使它们“可见”。您应该已经预定义了可能绘制的内容。然后只需更改它渲染的状态

And as @MadPrgrammer pointed out, you should not be painting on top-level containers like JFrame. Instead paint on a custom JPanelor JComponentand override the paintComponentmethod, instead of JFrameand paint

正如@MadPrgrammer 指出的那样,您不应该在像JFrame. 而是绘制自定义JPanelJComponent并覆盖paintComponent方法,而不是JFramepaint

Here's an example where I draw a new square every time the button is pressed. If look at the code, you will see that in the paintComponentmethod, I loop through a list of Squares and draw them, and in the actionPerformedall I do is add a new Squareto the Listand call repaint()

这是一个示例,每次按下按钮时我都会绘制一个新方块。如果查看代码,您会看到在paintComponent方法中,我遍历了一个Squares列表并绘制了它们,而actionPerformed我所做的就是向s中添加一个新SquareList并调用repaint()

enter image description here

在此处输入图片说明

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class AddSquares {

    private int R = 0;
    private int G = 0;
    private int B = 0;
    private int xLoc = 0;
    private int yLoc = 0;

    List<Square> squares = new ArrayList<>();
    private JButton addSquare = new JButton("Add Square");
    private RectsPanel panel = new RectsPanel();

    public AddSquares() {

        addSquare.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                Color color = new Color(R, G, B);
                squares.add(new Square(xLoc, yLoc, color));
                panel.repaint();
                R += 10;
                G += 20;
                B += 30;
                xLoc += 20;
                yLoc += 20;

            }
        });

        JFrame frame = new JFrame("Draw Squares");
        frame.add(panel, BorderLayout.CENTER);
        frame.add(addSquare, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    private class RectsPanel extends JPanel {

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (Square square : squares) {
                square.drawSquare(g);
            }
        }

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

    private class Square {
        int x = 0; 
        int y = 0;
        Color color;

        public Square(int x, int y, Color color) {
            this.x = x;
            this.y = y;
            this.color = color;
        }

        public void drawSquare(Graphics g) {
            g.setColor(color);
            g.fillRect(x, y, 75 ,75);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                AddSquares addSquares = new AddSquares();
            }
        });
    }
}

回答by MadProgrammer

It's difficult to be 100%, but it would seem as you don't understand how custom painting is performed in Swing.

很难做到 100%,但似乎您不了解如何在 Swing 中执行自定义绘画。

Start by taking a look at Performing Custom Paintingand Painting in AWT and Swing.

首先查看在 AWT 和 Swing执行自定义绘画绘画

Essentially, painting is arranged by the Repaint Manager, which decides what and when something should be painted. It then calls (through a chain of methods) the paintmethod of the components it thinks need to be updated, passing it a reference to a Graphicscontext that should be used to actually paint on.

本质上,绘画是由重绘管理器安排的,它决定什么以及什么时候应该绘画。然后它调用(通过一系列方法)paint它认为需要更新的组件的方法,将它传递给Graphics应该用于实际绘制的上下文的引用。

Basically, when ever your paint method is called, you should create paint the current state of your painting.

基本上,当你的paint方法被调用时,你应该创建paint你的绘画的当前状态。

You should avoid overriding paintand instead use paintComponentfrom classes the extend JComponent

您应该避免覆盖paint,而是paintComponent从类中使用扩展JComponent

回答by Radiodef

Your question is a little on the vague side as to what you are actually wondering about but generally speaking:

您的问题对于您实际想知道的内容有点含糊,但总的来说:

  • We don't override paintin Swing, we override paintComponent.
  • 我们不会paint在 Swing 中覆盖,我们会覆盖paintComponent.

If you are already aware of this, you may be overriding paintbecause you are doing it on a JFrame and you found that JFrame does not have a paintComponentmethod. You shouldn't override painton a JFrame. Instead, create a JPanel or something to put inside the frame and override paintComponenton the panel.

如果您已经意识到这一点,您可能会覆盖,paint因为您是在 JFrame 上执行此操作,并且您发现 JFrame 没有paintComponent方法。您不应该覆盖paintJFrame。相反,创建一个 JPanel 或其他东西放在框架内并覆盖paintComponent在面板上。

  • Question about the ActionListener.
  • 关于 ActionListener 的问题。

It sounds like you are wanting to do painting outside of paintComponentin which case probably the best way is to do painting to a separate Image. Then you paint the Image on to the panel in paintComponent. You can also put an Image in a JLabel as an ImageIcon. Here is a very simple drawing program using MouseListener that demonstrates this (taken from here):

听起来您想在外面进行绘画,paintComponent在这种情况下,最好的方法可能是对单独的图像进行绘画。然后将图像绘制到面板上paintComponent。您还可以将图像作为 ImageIcon 放入 JLabel 中。这是一个使用 MouseListener 的非常简单的绘图程序,它演示了这一点(取自此处):

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

class PaintAnyTime {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new PaintAnyTime();
            }
        });
    }

    final BufferedImage image = (
        new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB)
    );

    final JFrame frame = new JFrame();

    final JLabel label = new JLabel(new ImageIcon(image));

    final MouseAdapter drawer = new MouseAdapter() {
        Graphics2D g2D;

        @Override
        public void mousePressed(MouseEvent me) {
            g2D = image.createGraphics();
            g2D.setColor(Color.BLACK);
        }

        @Override
        public void mouseDragged(MouseEvent me) {
            g2D.fillRect(me.getX(), me.getY(), 3, 3);
            label.repaint();
        }

        @Override
        public void mouseReleased(MouseEvent me) {
            g2D.dispose();
            g2D = null;
        }
    };

    PaintAnyTime() {
        label.setPreferredSize(
            new Dimension(image.getWidth(), image.getHeight())
        );

        label.addMouseListener(drawer);
        label.addMouseMotionListener(drawer);

        frame.add(label);

        frame.pack();
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

@MadProgrammer has already linked to the articles that I was going to link to.

@MadProgrammer 已经链接到我要链接到的文章。